aboutsummaryrefslogtreecommitdiffstats
path: root/src/vpp-api/java/jvpp/gen/jvppgen
diff options
context:
space:
mode:
Diffstat (limited to 'src/vpp-api/java/jvpp/gen/jvppgen')
-rw-r--r--src/vpp-api/java/jvpp/gen/jvppgen/__init__.py0
-rw-r--r--src/vpp-api/java/jvpp/gen/jvppgen/callback_gen.py105
-rw-r--r--src/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py310
-rw-r--r--src/vpp-api/java/jvpp/gen/jvppgen/jni_gen.py303
-rw-r--r--src/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py392
-rw-r--r--src/vpp-api/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py326
-rw-r--r--src/vpp-api/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py331
-rw-r--r--src/vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py219
-rw-r--r--src/vpp-api/java/jvpp/gen/jvppgen/notification_gen.py199
-rw-r--r--src/vpp-api/java/jvpp/gen/jvppgen/types_gen.py232
-rw-r--r--src/vpp-api/java/jvpp/gen/jvppgen/util.py212
11 files changed, 2629 insertions, 0 deletions
diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/__init__.py b/src/vpp-api/java/jvpp/gen/jvppgen/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/vpp-api/java/jvpp/gen/jvppgen/__init__.py
diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/callback_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/callback_gen.py
new file mode 100644
index 00000000..b3024b9c
--- /dev/null
+++ b/src/vpp-api/java/jvpp/gen/jvppgen/callback_gen.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2016 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import util
+from string import Template
+
+from util import remove_suffix
+
+callback_suffix = "Callback"
+
+callback_template = Template("""
+package $plugin_package.$callback_package;
+
+/**
+ * <p>Represents callback for plugin's api file message.
+ * <br>It was generated by callback_gen.py based on $inputfile preparsed data:
+ * <pre>
+$docs
+ * </pre>
+ */
+public interface $cls_name extends $base_package.$callback_package.$callback_type {
+
+ $callback_method
+
+}
+""")
+
+global_callback_template = Template("""
+package $plugin_package.$callback_package;
+
+/**
+ * <p>Global aggregated callback interface.
+ * <br>It was generated by callback_gen.py based on $inputfile
+ * <br>(python representation of api file generated by vppapigen).
+ */
+public interface JVpp${plugin_name}GlobalCallback extends $base_package.$callback_package.ControlPingCallback, $callbacks {
+}
+""")
+
+
+def generate_callbacks(func_list, base_package, plugin_package, plugin_name, callback_package, dto_package, inputfile):
+ """ Generates callback interfaces """
+ print "Generating Callback interfaces"
+
+ if not os.path.exists(callback_package):
+ os.mkdir(callback_package)
+
+ callbacks = []
+ for func in func_list:
+
+ camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name'])
+
+ if util.is_ignored(func['name']) or util.is_control_ping(camel_case_name_with_suffix):
+ continue
+ if not util.is_reply(camel_case_name_with_suffix) and not util.is_notification(func['name']):
+ continue
+
+ if util.is_reply(camel_case_name_with_suffix):
+ camel_case_name = util.remove_reply_suffix(camel_case_name_with_suffix)
+ callback_type = "JVppCallback"
+ else:
+ camel_case_name_with_suffix = util.add_notification_suffix(camel_case_name_with_suffix)
+ camel_case_name = camel_case_name_with_suffix
+ callback_type = "JVppNotificationCallback"
+
+ callbacks.append("{0}.{1}.{2}".format(plugin_package, callback_package, camel_case_name + callback_suffix))
+ callback_path = os.path.join(callback_package, camel_case_name + callback_suffix + ".java")
+ callback_file = open(callback_path, 'w')
+
+ reply_type = "%s.%s.%s" % (plugin_package, dto_package, camel_case_name_with_suffix)
+ method = "void on{0}({1} reply);".format(camel_case_name_with_suffix, reply_type)
+ callback_file.write(
+ callback_template.substitute(inputfile=inputfile,
+ docs=util.api_message_to_javadoc(func),
+ cls_name=camel_case_name + callback_suffix,
+ callback_method=method,
+ base_package=base_package,
+ plugin_package=plugin_package,
+ callback_package=callback_package,
+ callback_type=callback_type))
+ callback_file.flush()
+ callback_file.close()
+
+ callback_file = open(os.path.join(callback_package, "JVpp%sGlobalCallback.java" % plugin_name), 'w')
+ callback_file.write(global_callback_template.substitute(inputfile=inputfile,
+ callbacks=", ".join(callbacks),
+ base_package=base_package,
+ plugin_package=plugin_package,
+ plugin_name=plugin_name,
+ callback_package=callback_package))
+ callback_file.flush()
+ callback_file.close()
diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py
new file mode 100644
index 00000000..e831557c
--- /dev/null
+++ b/src/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py
@@ -0,0 +1,310 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2016 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+from string import Template
+
+import util
+
+dto_template = Template("""
+package $plugin_package.$dto_package;
+
+/**
+ * <p>This class represents $description.
+ * <br>It was generated by dto_gen.py based on $inputfile preparsed data:
+ * <pre>
+$docs
+ * </pre>
+ */
+public final class $cls_name implements $base_package.$dto_package.$base_type {
+
+$fields
+$methods
+}
+""")
+
+field_template = Template(""" public $type $name;\n""")
+
+send_template = Template(""" @Override
+ public int send(final $base_package.JVpp jvpp) throws io.fd.vpp.jvpp.VppInvocationException {
+ return (($plugin_package.JVpp${plugin_name})jvpp).$method_name($args);
+ }""")
+
+
+def generate_dtos(func_list, base_package, plugin_package, plugin_name, dto_package, inputfile):
+ """ Generates dto objects in a dedicated package """
+ print "Generating DTOs"
+
+ if not os.path.exists(dto_package):
+ os.mkdir(dto_package)
+
+ for func in func_list:
+ camel_case_dto_name = util.underscore_to_camelcase_upper(func['name'])
+ camel_case_method_name = util.underscore_to_camelcase(func['name'])
+ dto_path = os.path.join(dto_package, camel_case_dto_name + ".java")
+
+ if util.is_ignored(func['name']) or util.is_control_ping(camel_case_dto_name):
+ continue
+
+ fields = generate_dto_fields(camel_case_dto_name, func)
+ methods = generate_dto_base_methods(camel_case_dto_name, func)
+ base_type = ""
+
+ # Generate request/reply or dump/dumpReply even if structure can be used as notification
+ if not util.is_just_notification(func["name"]):
+ if util.is_reply(camel_case_dto_name):
+ description = "reply DTO"
+ request_dto_name = get_request_name(camel_case_dto_name, func['name'])
+ if util.is_details(camel_case_dto_name):
+ # FIXME assumption that dump calls end with "Dump" suffix. Not enforced in vpe.api
+ base_type += "JVppReply<%s.%s.%s>" % (plugin_package, dto_package, request_dto_name + "Dump")
+ generate_dump_reply_dto(request_dto_name, base_package, plugin_package, dto_package,
+ camel_case_dto_name, camel_case_method_name, func)
+ else:
+ base_type += "JVppReply<%s.%s.%s>" % (plugin_package, dto_package, request_dto_name)
+ else:
+ args = "" if fields is "" else "this"
+ methods += send_template.substitute(method_name=camel_case_method_name,
+ base_package=base_package,
+ plugin_package=plugin_package,
+ plugin_name=plugin_name,
+ args=args)
+ if util.is_dump(camel_case_dto_name):
+ base_type += "JVppDump"
+ description = "dump request DTO"
+ else:
+ base_type += "JVppRequest"
+ description = "request DTO"
+
+ write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, description, dto_package,
+ dto_path, fields, func, inputfile, methods)
+
+ # for structures that are also used as notifications, generate dedicated notification DTO
+ if util.is_notification(func["name"]):
+ base_type = "JVppNotification"
+ description = "notification DTO"
+ camel_case_dto_name = util.add_notification_suffix(camel_case_dto_name)
+ dto_path = os.path.join(dto_package, camel_case_dto_name + ".java")
+ methods = generate_dto_base_methods(camel_case_dto_name, func)
+ write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, description, dto_package,
+ dto_path, fields, func, inputfile, methods)
+
+ flush_dump_reply_dtos(inputfile)
+
+
+def generate_dto_base_methods(camel_case_dto_name, func):
+ methods = generate_dto_hash(func)
+ methods += generate_dto_equals(camel_case_dto_name, func)
+ methods += generate_dto_tostring(camel_case_dto_name, func)
+ return methods
+
+
+def generate_dto_fields(camel_case_dto_name, func):
+ fields = ""
+ for t in zip(func['types'], func['args']):
+ # for retval don't generate dto field in Reply
+ field_name = util.underscore_to_camelcase(t[1])
+ if util.is_reply(camel_case_dto_name) and util.is_retval_field(field_name):
+ continue
+ fields += field_template.substitute(type=util.jni_2_java_type_mapping[t[0]],
+ name=field_name)
+ return fields
+
+
+tostring_field_template = Template(""" \"$field_name=\" + $field_name + ", " +\n""")
+tostring_array_field_template = Template(""" \"$field_name=\" + java.util.Arrays.toString($field_name) + ", " +\n""")
+tostring_template = Template(""" @Override
+ public String toString() {
+ return "$cls_name{" +
+$fields_tostring "}";
+ }\n\n""")
+
+
+def generate_dto_tostring(camel_case_dto_name, func):
+ tostring_fields = ""
+ for t in zip(func['types'], func['args']):
+
+ field_name = util.underscore_to_camelcase(t[1])
+ # for retval don't generate dto field in Reply
+ if util.is_retval_field(field_name):
+ continue
+
+ # handle array types
+ if util.is_array(util.jni_2_java_type_mapping[t[0]]):
+ tostring_fields += tostring_array_field_template.substitute(field_name=field_name)
+ else:
+ tostring_fields += tostring_field_template.substitute(field_name=field_name)
+
+ return tostring_template.substitute(cls_name=camel_case_dto_name,
+ fields_tostring=tostring_fields[:-8])
+
+equals_other_template = Template("""
+ final $cls_name other = ($cls_name) o;
+\n""")
+equals_field_template = Template(""" if (!java.util.Objects.equals(this.$field_name, other.$field_name)) {
+ return false;
+ }\n""")
+equals_array_field_template = Template(""" if (!java.util.Arrays.equals(this.$field_name, other.$field_name)) {
+ return false;
+ }\n""")
+equals_template = Template(""" @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+$comparisons
+ return true;
+ }\n\n""")
+
+
+def generate_dto_equals(camel_case_dto_name, func):
+ equals_fields = ""
+ for t in zip(func['types'], func['args']):
+ field_name = util.underscore_to_camelcase(t[1])
+ # for retval don't generate dto field in Reply
+ if util.is_retval_field(field_name):
+ continue
+
+ # handle array types
+ if util.is_array(util.jni_2_java_type_mapping[t[0]]):
+ equals_fields += equals_array_field_template.substitute(field_name=field_name)
+ else:
+ equals_fields += equals_field_template.substitute(field_name=field_name)
+
+ if equals_fields != "":
+ equals_fields = equals_other_template.substitute(cls_name=camel_case_dto_name) + equals_fields
+
+ return equals_template.substitute(comparisons=equals_fields)
+
+
+hash_template = Template(""" @Override
+ @io.fd.vpp.jvpp.coverity.SuppressFBWarnings("UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD")
+ public int hashCode() {
+ return java.util.Objects.hash($fields);
+ }\n\n""")
+hash_single_array_type_template = Template(""" @Override
+ @io.fd.vpp.jvpp.coverity.SuppressFBWarnings("UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD")
+ public int hashCode() {
+ return java.util.Arrays.hashCode($fields);
+ }\n\n""")
+
+
+def generate_dto_hash(func):
+ hash_fields = ""
+
+ # Special handling for hashCode in case just a single array field is present. Cannot use Objects.equals since the
+ # array is mistaken for a varargs parameter. Instead use Arrays.hashCode in such case.
+ if len(func['args']) == 1:
+ single_type = func['types'][0]
+ single_type_name = func['args'][0]
+ if util.is_array(util.jni_2_java_type_mapping[single_type]):
+ return hash_single_array_type_template.substitute(fields=util.underscore_to_camelcase(single_type_name))
+
+ for t in zip(func['types'], func['args']):
+ field_name = util.underscore_to_camelcase(t[1])
+ # for retval don't generate dto field in Reply
+ if util.is_retval_field(field_name):
+ continue
+
+ hash_fields += field_name + ", "
+
+ return hash_template.substitute(fields=hash_fields[:-2])
+
+
+def write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, description, dto_package, dto_path,
+ fields, func, inputfile, methods):
+ dto_file = open(dto_path, 'w')
+ dto_file.write(dto_template.substitute(inputfile=inputfile,
+ description=description,
+ docs=util.api_message_to_javadoc(func),
+ cls_name=camel_case_dto_name,
+ fields=fields,
+ methods=methods,
+ base_package=base_package,
+ plugin_package=plugin_package,
+ base_type=base_type,
+ dto_package=dto_package))
+ dto_file.flush()
+ dto_file.close()
+
+
+dump_dto_suffix = "ReplyDump"
+dump_reply_artificial_dtos = {}
+
+
+# Returns request name or special one from unconventional_naming_rep_req map
+def get_request_name(camel_case_dto_name, func_name):
+ return util.underscore_to_camelcase_upper(
+ util.unconventional_naming_rep_req[func_name]) if func_name in util.unconventional_naming_rep_req \
+ else util.remove_reply_suffix(camel_case_dto_name)
+
+
+def flush_dump_reply_dtos(inputfile):
+ for dump_reply_artificial_dto in dump_reply_artificial_dtos.values():
+ dto_path = os.path.join(dump_reply_artificial_dto['dto_package'],
+ dump_reply_artificial_dto['cls_name'] + ".java")
+ dto_file = open(dto_path, 'w')
+ dto_file.write(dto_template.substitute(inputfile=inputfile,
+ description="dump reply wrapper",
+ docs=dump_reply_artificial_dto['docs'],
+ cls_name=dump_reply_artificial_dto['cls_name'],
+ fields=dump_reply_artificial_dto['fields'],
+ methods=dump_reply_artificial_dto['methods'],
+ plugin_package=dump_reply_artificial_dto['plugin_package'],
+ base_package=dump_reply_artificial_dto['base_package'],
+ base_type=dump_reply_artificial_dto['base_type'],
+ dto_package=dump_reply_artificial_dto['dto_package']))
+ dto_file.flush()
+ dto_file.close()
+
+
+def generate_dump_reply_dto(request_dto_name, base_package, plugin_package, dto_package, camel_case_dto_name,
+ camel_case_method_name, func):
+ base_type = "JVppReplyDump<%s.%s.%s, %s.%s.%s>" % (
+ plugin_package, dto_package, util.remove_reply_suffix(camel_case_dto_name) + "Dump",
+ plugin_package, dto_package, camel_case_dto_name)
+ fields = " public java.util.List<%s> %s = new java.util.ArrayList<>();" % (camel_case_dto_name, camel_case_method_name)
+ cls_name = camel_case_dto_name + dump_dto_suffix
+ # using artificial type for fields, just to bypass the is_array check in base methods generators
+ # the type is not really used
+ artificial_type = 'u8'
+
+ # In case of already existing artificial reply dump DTO, just update it
+ # Used for sub-dump dtos
+ if request_dto_name in dump_reply_artificial_dtos.keys():
+ dump_reply_artificial_dtos[request_dto_name]['fields'] += '\n' + fields
+ dump_reply_artificial_dtos[request_dto_name]['field_names'].append(func['name'])
+ dump_reply_artificial_dtos[request_dto_name]['field_types'].append(artificial_type)
+ methods = '\n' + generate_dto_base_methods(dump_reply_artificial_dtos[request_dto_name]['cls_name'],
+ {'args': dump_reply_artificial_dtos[request_dto_name]['field_names'],
+ 'types': dump_reply_artificial_dtos[request_dto_name]['field_types']})
+ dump_reply_artificial_dtos[request_dto_name]['methods'] = methods
+ else:
+ methods = '\n' + generate_dto_base_methods(cls_name, {'args': [func['name']],
+ 'types': [artificial_type]})
+ dump_reply_artificial_dtos[request_dto_name] = ({'docs': util.api_message_to_javadoc(func),
+ 'cls_name': cls_name,
+ 'fields': fields,
+ 'field_names': [func['name']],
+ 'field_types': [artificial_type],
+ # strip too many newlines at the end of base method block
+ 'methods': methods,
+ 'plugin_package': plugin_package,
+ 'base_package': base_package,
+ 'base_type': base_type,
+ 'dto_package': dto_package})
diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/jni_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/jni_gen.py
new file mode 100644
index 00000000..cb0d66e8
--- /dev/null
+++ b/src/vpp-api/java/jvpp/gen/jvppgen/jni_gen.py
@@ -0,0 +1,303 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2016 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from string import Template
+
+import util
+
+variable_length_array_value_template = Template("""mp->${length_var_name}""")
+variable_length_array_template = Template("""clib_net_to_host_${length_field_type}(${value})""")
+
+dto_field_id_template = Template("""
+ jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${field_name}", "${jni_signature}");""")
+
+default_dto_field_setter_template = Template("""
+ (*env)->Set${jni_setter}(env, ${object_name}, ${field_reference_name}FieldId, mp->${c_name});
+""")
+
+variable_length_array_value_template = Template("""mp->${length_var_name}""")
+variable_length_array_template = Template("""clib_net_to_host_${length_field_type}(${value})""")
+
+u16_dto_field_setter_template = Template("""
+ (*env)->Set${jni_setter}(env, ${object_name}, ${field_reference_name}FieldId, clib_net_to_host_u16(mp->${c_name}));
+""")
+
+u32_dto_field_setter_template = Template("""
+ (*env)->Set${jni_setter}(env, ${object_name}, ${field_reference_name}FieldId, clib_net_to_host_u32(mp->${c_name}));
+""")
+
+u64_dto_field_setter_template = Template("""
+ (*env)->Set${jni_setter}(env, ${object_name}, ${field_reference_name}FieldId, clib_net_to_host_u64(mp->${c_name}));
+""")
+
+u8_array_dto_field_setter_template = Template("""
+ jbyteArray ${field_reference_name} = (*env)->NewByteArray(env, ${field_length});
+ (*env)->SetByteArrayRegion(env, ${field_reference_name}, 0, ${field_length}, (const jbyte*)mp->${c_name});
+ (*env)->SetObjectField(env, ${object_name}, ${field_reference_name}FieldId, ${field_reference_name});
+ (*env)->DeleteLocalRef(env, ${field_reference_name});
+""")
+
+u16_array_dto_field_setter_template = Template("""
+ {
+ jshortArray ${field_reference_name} = (*env)->NewShortArray(env, ${field_length});
+ jshort * ${field_reference_name}ArrayElements = (*env)->GetShortArrayElements(env, ${field_reference_name}, NULL);
+ unsigned int _i;
+ for (_i = 0; _i < ${field_length}; _i++) {
+ ${field_reference_name}ArrayElements[_i] = clib_net_to_host_u16(mp->${c_name}[_i]);
+ }
+
+ (*env)->ReleaseShortArrayElements(env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0);
+ (*env)->SetObjectField(env, ${object_name}, ${field_reference_name}FieldId, ${field_reference_name});
+ (*env)->DeleteLocalRef(env, ${field_reference_name});
+ }
+""")
+
+u32_array_dto_field_setter_template = Template("""
+ {
+ jintArray ${field_reference_name} = (*env)->NewIntArray(env, ${field_length});
+ jint * ${field_reference_name}ArrayElements = (*env)->GetIntArrayElements(env, ${field_reference_name}, NULL);
+ unsigned int _i;
+ for (_i = 0; _i < ${field_length}; _i++) {
+ ${field_reference_name}ArrayElements[_i] = clib_net_to_host_u32(mp->${c_name}[_i]);
+ }
+
+ (*env)->ReleaseIntArrayElements(env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0);
+ (*env)->SetObjectField(env, ${object_name}, ${field_reference_name}FieldId, ${field_reference_name});
+ (*env)->DeleteLocalRef(env, ${field_reference_name});
+ }
+""")
+
+# For each u64 array we get its elements. Then we convert values to host byte order.
+# All changes to jlong* buffer are written to jlongArray (isCopy is set to NULL)
+u64_array_dto_field_setter_template = Template("""
+ {
+ jlongArray ${field_reference_name} = (*env)->NewLongArray(env, ${field_length});
+ jlong * ${field_reference_name}ArrayElements = (*env)->GetLongArrayElements(env, ${field_reference_name}, NULL);
+ unsigned int _i;
+ for (_i = 0; _i < ${field_length}; _i++) {
+ ${field_reference_name}ArrayElements[_i] = clib_net_to_host_u64(mp->${c_name}[_i]);
+ }
+
+ (*env)->ReleaseLongArrayElements(env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0);
+ (*env)->SetObjectField(env, ${object_name}, ${field_reference_name}FieldId, ${field_reference_name});
+ (*env)->DeleteLocalRef(env, ${field_reference_name});
+ }
+""")
+
+dto_field_setter_templates = {'u8': default_dto_field_setter_template,
+ 'u16': u16_dto_field_setter_template,
+ 'u32': u32_dto_field_setter_template,
+ 'i32': u32_dto_field_setter_template,
+ 'u64': u64_dto_field_setter_template,
+ 'f64': default_dto_field_setter_template, # fixme
+ 'u8[]': u8_array_dto_field_setter_template,
+ 'u16[]': u16_array_dto_field_setter_template,
+ 'u32[]': u32_array_dto_field_setter_template,
+ 'u64[]': u64_array_dto_field_setter_template
+ }
+
+
+def jni_reply_handler_for_type(handler_name, ref_name, field_type, c_name, field_reference_name,
+ field_name, field_length, is_variable_len_array, length_field_type,
+ object_name="dto"):
+ """
+ Generates jni code that initializes a field of java object (dto or custom type).
+ To be used in reply message handlers.
+ :param field_type: type of the field to be initialized (as defined in vpe.api)
+ :param c_name: name of the message struct member that stores initialization value
+ :param field_reference_name: name of the field reference in generated code
+ :param field_name: name of the field (camelcase)
+ :param field_length: integer or name of variable that stores field length
+ :param object_name: name of the object to be initialized
+ """
+
+ # todo move validation to vppapigen
+ if field_type.endswith('[]') and field_length == '0':
+ raise Exception('Variable array \'%s\' defined in \'%s\' '
+ 'should have defined length (e.g. \'%s[%s_length]\''
+ % (c_name, handler_name, c_name, c_name))
+
+ if is_variable_len_array:
+ length_var_name = field_length
+ field_length = variable_length_array_value_template.substitute(length_var_name=length_var_name)
+ if length_field_type != 'u8': # we need net to host conversion:
+ field_length = variable_length_array_template.substitute(
+ length_field_type=length_field_type, value=field_length)
+
+ # for retval don't generate setters
+ if util.is_retval_field(c_name):
+ return ""
+
+ jni_signature = util.jni_2_signature_mapping[field_type]
+ jni_setter = util.jni_field_accessors[field_type]
+
+ result = dto_field_id_template.substitute(
+ field_reference_name=field_reference_name,
+ field_name=field_name,
+ class_ref_name=ref_name,
+ jni_signature=jni_signature)
+
+ dto_setter_template = dto_field_setter_templates[field_type]
+
+ result += dto_setter_template.substitute(
+ jni_signature=jni_signature,
+ object_name=object_name,
+ field_reference_name=field_reference_name,
+ c_name=c_name,
+ jni_setter=jni_setter,
+ field_length=field_length)
+ return result
+
+
+request_field_identifier_template = Template("""
+ jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${object_name}Class, "${field_name}", "${jni_signature}");
+ ${jni_type} ${field_reference_name} = (*env)->Get${jni_getter}(env, ${object_name}, ${field_reference_name}FieldId);
+ """)
+
+array_length_enforcement_template = Template("""
+ size_t max_size = ${field_length};
+ if (cnt > max_size) cnt = max_size;""")
+
+u8_struct_setter_template = Template("""
+ mp->${c_name} = ${field_reference_name};""")
+
+u16_struct_setter_template = Template("""
+ mp->${c_name} = clib_host_to_net_u16(${field_reference_name});""")
+
+u32_struct_setter_template = Template("""
+ mp->${c_name} = clib_host_to_net_u32(${field_reference_name});""")
+
+i32_struct_setter_template = Template("""
+ mp->${c_name} = clib_host_to_net_i32(${field_reference_name});!""")
+
+u64_struct_setter_template = Template("""
+ mp->${c_name} = clib_host_to_net_u64(${field_reference_name});""")
+
+array_length_enforcement_template = Template("""
+ size_t max_size = ${field_length};
+ if (cnt > max_size) cnt = max_size;""")
+
+u8_array_struct_setter_template = Template("""
+ if (${field_reference_name}) {
+ jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name});
+ ${field_length_check}
+ (*env)->GetByteArrayRegion(env, ${field_reference_name}, 0, cnt, (jbyte *)mp->${c_name});
+ }
+""")
+
+u16_array_struct_setter_template = Template("""
+ if (${field_reference_name}) {
+ jshort * ${field_reference_name}ArrayElements = (*env)->GetShortArrayElements(env, ${field_reference_name}, NULL);
+ size_t _i;
+ jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name});
+ ${field_length_check}
+ for (_i = 0; _i < cnt; _i++) {
+ mp->${c_name}[_i] = clib_host_to_net_u16(${field_reference_name}ArrayElements[_i]);
+ }
+ (*env)->ReleaseShortArrayElements (env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0);
+ }
+ """)
+
+u32_array_struct_setter_template = Template("""
+ if (${field_reference_name}) {
+ jint * ${field_reference_name}ArrayElements = (*env)->GetIntArrayElements(env, ${field_reference_name}, NULL);
+ size_t _i;
+ jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name});
+ ${field_length_check}
+ for (_i = 0; _i < cnt; _i++) {
+ mp->${c_name}[_i] = clib_host_to_net_u32(${field_reference_name}ArrayElements[_i]);
+ }
+ (*env)->ReleaseIntArrayElements (env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0);
+ }
+ """)
+
+u64_array_struct_setter_template = Template("""
+ if (${field_reference_name}) {
+ jlong * ${field_reference_name}ArrayElements = (*env)->GetLongArrayElements(env, ${field_reference_name}, NULL);
+ size_t _i;
+ jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name});
+ ${field_length_check}
+ for (_i = 0; _i < cnt; _i++) {
+ mp->${c_name}[_i] = clib_host_to_net_u64(${field_reference_name}ArrayElements[_i]);
+ }
+ (*env)->ReleaseLongArrayElements (env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0);
+ }
+ """)
+
+struct_setter_templates = {'u8': u8_struct_setter_template,
+ 'u16': u16_struct_setter_template,
+ 'u32': u32_struct_setter_template,
+ 'i32': u32_struct_setter_template,
+ 'u64': u64_struct_setter_template,
+ 'u8[]': u8_array_struct_setter_template,
+ 'u16[]': u16_array_struct_setter_template,
+ 'u32[]': u32_array_struct_setter_template,
+ 'u64[]': u64_array_struct_setter_template
+ }
+
+
+def jni_request_identifiers_for_type(field_type, field_reference_name, field_name, object_name="request"):
+ """
+ Generates jni code that defines C variable corresponding to field of java object
+ (dto or custom type). To be used in request message handlers.
+ :param field_type: type of the field to be initialized (as defined in vpe.api)
+ :param field_reference_name: name of the field reference in generated code
+ :param field_name: name of the field (camelcase)
+ :param object_name: name of the object to be initialized
+ """
+ # field identifiers
+ jni_type = util.vpp_2_jni_type_mapping[field_type]
+ jni_signature = util.jni_2_signature_mapping[field_type]
+ jni_getter = util.jni_field_accessors[field_type]
+
+ # field identifier
+ return request_field_identifier_template.substitute(
+ jni_type=jni_type,
+ field_reference_name=field_reference_name,
+ field_name=field_name,
+ jni_signature=jni_signature,
+ jni_getter=jni_getter,
+ object_name=object_name)
+
+
+def jni_request_binding_for_type(field_type, c_name, field_reference_name, field_length, is_variable_len_array):
+ """
+ Generates jni code that initializes C structure that corresponds to a field of java object
+ (dto or custom type). To be used in request message handlers.
+ :param field_type: type of the field to be initialized (as defined in vpe.api)
+ :param c_name: name of the message struct member to be initialized
+ :param field_reference_name: name of the field reference in generated code
+ :param field_length: integer or name of variable that stores field length
+ """
+
+ # field setter
+ field_length_check = ""
+
+ # check if we are processing variable length array:
+ if is_variable_len_array:
+ field_length = util.underscore_to_camelcase(field_length)
+
+ # enforce max length if array has fixed length or uses variable length syntax
+ if str(field_length) != "0":
+ field_length_check = array_length_enforcement_template.substitute(field_length=field_length)
+
+ struct_setter_template = struct_setter_templates[field_type]
+
+ msg_initialization = struct_setter_template.substitute(
+ c_name=c_name,
+ field_reference_name=field_reference_name,
+ field_length_check=field_length_check)
+
+ return msg_initialization
diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py
new file mode 100644
index 00000000..8761eb13
--- /dev/null
+++ b/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py
@@ -0,0 +1,392 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2016 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+# l
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import os, util
+from string import Template
+
+import jni_gen
+
+
+def is_manually_generated(f_name, plugin_name):
+ return f_name in {'control_ping_reply'}
+
+
+class_reference_template = Template("""jclass ${ref_name}Class;
+""")
+
+find_class_invocation_template = Template("""
+ ${ref_name}Class = (jclass)(*env)->NewGlobalRef(env, (*env)->FindClass(env, "io/fd/vpp/jvpp/${plugin_name}/dto/${class_name}"));
+ if ((*env)->ExceptionCheck(env)) {
+ (*env)->ExceptionDescribe(env);
+ return JNI_ERR;
+ }""")
+
+find_class_template = Template("""
+ ${ref_name}Class = (jclass)(*env)->NewGlobalRef(env, (*env)->FindClass(env, "${class_name}"));
+ if ((*env)->ExceptionCheck(env)) {
+ (*env)->ExceptionDescribe(env);
+ return JNI_ERR;
+ }""")
+
+delete_class_invocation_template = Template("""
+ if (${ref_name}Class) {
+ (*env)->DeleteGlobalRef(env, ${ref_name}Class);
+ }""")
+
+class_cache_template = Template("""
+$class_references
+static int cache_class_references(JNIEnv* env) {
+ $find_class_invocations
+ return 0;
+}
+
+static void delete_class_references(JNIEnv* env) {
+ $delete_class_invocations
+}""")
+
+
+def generate_class_cache(func_list, plugin_name):
+ class_references = []
+ find_class_invocations = []
+ delete_class_invocations = []
+ for f in func_list:
+ c_name = f['name']
+ class_name = util.underscore_to_camelcase_upper(c_name)
+ ref_name = util.underscore_to_camelcase(c_name)
+
+ if util.is_ignored(c_name) or util.is_control_ping(class_name):
+ continue
+
+ if util.is_reply(class_name):
+ class_references.append(class_reference_template.substitute(
+ ref_name=ref_name))
+ find_class_invocations.append(find_class_invocation_template.substitute(
+ plugin_name=plugin_name,
+ ref_name=ref_name,
+ class_name=class_name))
+ delete_class_invocations.append(delete_class_invocation_template.substitute(ref_name=ref_name))
+ elif util.is_notification(c_name):
+ class_references.append(class_reference_template.substitute(
+ ref_name=util.add_notification_suffix(ref_name)))
+ find_class_invocations.append(find_class_invocation_template.substitute(
+ plugin_name=plugin_name,
+ ref_name=util.add_notification_suffix(ref_name),
+ class_name=util.add_notification_suffix(class_name)))
+ delete_class_invocations.append(delete_class_invocation_template.substitute(
+ ref_name=util.add_notification_suffix(ref_name)))
+
+ # add exception class to class cache
+ ref_name = 'callbackException'
+ class_name = 'io/fd/vpp/jvpp/VppCallbackException'
+ class_references.append(class_reference_template.substitute(
+ ref_name=ref_name))
+ find_class_invocations.append(find_class_template.substitute(
+ ref_name=ref_name,
+ class_name=class_name))
+ delete_class_invocations.append(delete_class_invocation_template.substitute(ref_name=ref_name))
+
+ return class_cache_template.substitute(
+ class_references="".join(class_references), find_class_invocations="".join(find_class_invocations),
+ delete_class_invocations="".join(delete_class_invocations))
+
+
+# TODO: cache method and field identifiers to achieve better performance
+# https://jira.fd.io/browse/HONEYCOMB-42
+request_class_template = Template("""
+ jclass requestClass = (*env)->FindClass(env, "io/fd/vpp/jvpp/${plugin_name}/dto/${java_name_upper}");""")
+
+request_field_identifier_template = Template("""
+ jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${object_name}Class, "${field_name}", "${jni_signature}");
+ ${jni_type} ${field_reference_name} = (*env)->Get${jni_getter}(env, ${object_name}, ${field_reference_name}FieldId);
+ """)
+
+jni_msg_size_template = Template(""" + ${array_length}*sizeof(${element_type})""")
+
+jni_impl_template = Template("""
+/**
+ * JNI binding for sending ${c_name} message.
+ * Generated based on $inputfile preparsed data:
+$api_data
+ */
+JNIEXPORT jint JNICALL Java_io_fd_vpp_jvpp_${plugin_name}_JVpp${java_plugin_name}Impl_${field_name}0
+(JNIEnv * env, jclass clazz$args) {
+ ${plugin_name}_main_t *plugin_main = &${plugin_name}_main;
+ vl_api_${c_name}_t * mp;
+ u32 my_context_id = vppjni_get_context_id (&jvpp_main);
+ $request_class
+
+ $jni_identifiers
+
+ // create message:
+ mp = vl_msg_api_alloc(${msg_size});
+ memset (mp, 0, ${msg_size});
+ mp->_vl_msg_id = ntohs (get_message_id(env, "${c_name}_${crc}"));
+ mp->client_index = plugin_main->my_client_index;
+ mp->context = clib_host_to_net_u32 (my_context_id);
+
+ $msg_initialization
+
+ // send message:
+ vl_msg_api_send_shmem (plugin_main->vl_input_queue, (u8 *)&mp);
+ if ((*env)->ExceptionCheck(env)) {
+ return JNI_ERR;
+ }
+ return my_context_id;
+}""")
+
+def generate_jni_impl(func_list, plugin_name, inputfile):
+ jni_impl = []
+ for f in func_list:
+ f_name = f['name']
+ camel_case_function_name = util.underscore_to_camelcase(f_name)
+ if is_manually_generated(f_name, plugin_name) or util.is_reply(camel_case_function_name) \
+ or util.is_ignored(f_name) or util.is_just_notification(f_name):
+ continue
+
+ arguments = ''
+ request_class = ''
+ jni_identifiers = ''
+ msg_initialization = ''
+ f_name_uppercase = f_name.upper()
+ msg_size = 'sizeof(*mp)'
+
+ if f['args']:
+ arguments = ', jobject request'
+ camel_case_function_name_upper = util.underscore_to_camelcase_upper(f_name)
+
+ request_class = request_class_template.substitute(
+ java_name_upper=camel_case_function_name_upper,
+ plugin_name=plugin_name)
+
+ for t in zip(f['types'], f['args'], f['lengths'], f['arg_types']):
+ field_name = util.underscore_to_camelcase(t[1])
+ is_variable_len_array = t[2][1]
+ if is_variable_len_array:
+ msg_size += jni_msg_size_template.substitute(array_length=util.underscore_to_camelcase(t[2][0]),
+ element_type=t[3])
+ jni_identifiers += jni_gen.jni_request_identifiers_for_type(field_type=t[0],
+ field_reference_name=field_name,
+ field_name=field_name)
+ msg_initialization += jni_gen.jni_request_binding_for_type(field_type=t[0], c_name=t[1],
+ field_reference_name=field_name,
+ field_length=t[2][0],
+ is_variable_len_array=is_variable_len_array)
+
+ jni_impl.append(jni_impl_template.substitute(
+ inputfile=inputfile,
+ api_data=util.api_message_to_javadoc(f),
+ field_reference_name=camel_case_function_name,
+ field_name=camel_case_function_name,
+ c_name_uppercase=f_name_uppercase,
+ c_name=f_name,
+ crc=f['crc'],
+ plugin_name=plugin_name,
+ java_plugin_name=plugin_name.title(),
+ request_class=request_class,
+ jni_identifiers=jni_identifiers,
+ msg_size=msg_size,
+ msg_initialization=msg_initialization,
+ args=arguments))
+
+ return "\n".join(jni_impl)
+
+# code fragment for checking result of the operation before sending request reply
+callback_err_handler_template = Template("""
+ // for negative result don't send callback message but send error callback
+ if (mp->retval<0) {
+ call_on_error("${handler_name}", mp->context, mp->retval, plugin_main->callbackClass, plugin_main->callbackObject, callbackExceptionClass);
+ return;
+ }
+ if (mp->retval == VNET_API_ERROR_IN_PROGRESS) {
+ clib_warning("Result in progress");
+ return;
+ }
+""")
+
+msg_handler_template = Template("""
+/**
+ * Handler for ${handler_name} message.
+ * Generated based on $inputfile preparsed data:
+$api_data
+ */
+static void vl_api_${handler_name}_t_handler (vl_api_${handler_name}_t * mp)
+{
+ ${plugin_name}_main_t *plugin_main = &${plugin_name}_main;
+ JNIEnv *env = jvpp_main.jenv;
+ jthrowable exc;
+ $err_handler
+
+ jmethodID constructor = (*env)->GetMethodID(env, ${class_ref_name}Class, "<init>", "()V");
+
+ // User does not have to provide callbacks for all VPP messages.
+ // We are ignoring messages that are not supported by user.
+ (*env)->ExceptionClear(env); // just in case exception occurred in different place and was not properly cleared
+ jmethodID callbackMethod = (*env)->GetMethodID(env, plugin_main->callbackClass, "on${dto_name}", "(Lio/fd/vpp/jvpp/${plugin_name}/dto/${dto_name};)V");
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ clib_warning("Unable to extract on${dto_name} method reference from ${plugin_name} plugin's callbackClass. Ignoring message.\\n");
+ (*env)->ExceptionDescribe(env);
+ (*env)->ExceptionClear(env);
+ return;
+ }
+
+ jobject dto = (*env)->NewObject(env, ${class_ref_name}Class, constructor);
+ $dto_setters
+
+ (*env)->CallVoidMethod(env, plugin_main->callbackObject, callbackMethod, dto);
+ // free DTO as per http://stackoverflow.com/questions/1340938/memory-leak-when-calling-java-code-from-c-using-jni
+ (*env)->DeleteLocalRef(env, dto);
+}""")
+
+
+def generate_msg_handlers(func_list, plugin_name, inputfile):
+ handlers = []
+ for f in func_list:
+ handler_name = f['name']
+ dto_name = util.underscore_to_camelcase_upper(handler_name)
+ ref_name = util.underscore_to_camelcase(handler_name)
+
+ if is_manually_generated(handler_name, plugin_name) or util.is_ignored(handler_name):
+ continue
+
+ if not util.is_reply(dto_name) and not util.is_notification(handler_name):
+ continue
+
+ if util.is_notification(handler_name):
+ dto_name = util.add_notification_suffix(dto_name)
+ ref_name = util.add_notification_suffix(ref_name)
+
+ dto_setters = ''
+ err_handler = ''
+ # dto setters
+ for t in zip(f['types'], f['args'], f['lengths']):
+ c_name = t[1]
+ java_name = util.underscore_to_camelcase(c_name)
+ field_length = t[2][0]
+ is_variable_len_array = t[2][1]
+ length_field_type = None
+ if is_variable_len_array:
+ length_field_type = f['types'][f['args'].index(field_length)]
+ dto_setters += jni_gen.jni_reply_handler_for_type(handler_name=handler_name, ref_name=ref_name,
+ field_type=t[0], c_name=t[1],
+ field_reference_name=java_name,
+ field_name=java_name, field_length=field_length,
+ is_variable_len_array=is_variable_len_array,
+ length_field_type=length_field_type)
+
+ # for retval don't generate setters and generate retval check
+ if util.is_retval_field(c_name):
+ err_handler = callback_err_handler_template.substitute(
+ handler_name=handler_name
+ )
+ continue
+
+ handlers.append(msg_handler_template.substitute(
+ inputfile=inputfile,
+ api_data=util.api_message_to_javadoc(f),
+ handler_name=handler_name,
+ plugin_name=plugin_name,
+ dto_name=dto_name,
+ class_ref_name=ref_name,
+ dto_setters=dto_setters,
+ err_handler=err_handler))
+
+ return "\n".join(handlers)
+
+
+handler_registration_template = Template("""_(${name}_${crc}, ${name}) \\
+""")
+
+
+def generate_handler_registration(func_list):
+ handler_registration = ["#define foreach_api_reply_handler \\\n"]
+ for f in func_list:
+ name = f['name']
+ camelcase_name = util.underscore_to_camelcase(f['name'])
+
+ if (not util.is_reply(camelcase_name) and not util.is_notification(name)) or util.is_ignored(name) \
+ or util.is_control_ping(camelcase_name):
+ continue
+
+ handler_registration.append(handler_registration_template.substitute(
+ name=name,
+ crc=f['crc']))
+
+ return "".join(handler_registration)
+
+
+api_verification_template = Template("""_(${name}_${crc}) \\
+""")
+
+
+def generate_api_verification(func_list):
+ api_verification = ["#define foreach_supported_api_message \\\n"]
+ for f in func_list:
+ name = f['name']
+
+ if util.is_ignored(name):
+ continue
+
+ api_verification.append(api_verification_template.substitute(
+ name=name,
+ crc=f['crc']))
+
+ return "".join(api_verification)
+
+
+jvpp_c_template = Template("""/**
+ * This file contains JNI bindings for jvpp Java API.
+ * It was generated by jvpp_c_gen.py based on $inputfile
+ * (python representation of api file generated by vppapigen).
+ */
+
+// JAVA class reference cache
+$class_cache
+
+// List of supported API messages used for verification
+$api_verification
+
+// JNI bindings
+$jni_implementations
+
+// Message handlers
+$msg_handlers
+
+// Registration of message handlers in vlib
+$handler_registration
+""")
+
+def generate_jvpp(func_list, plugin_name, inputfile, path):
+ """ Generates jvpp C file """
+ print "Generating jvpp C"
+
+ class_cache = generate_class_cache(func_list, plugin_name)
+ jni_impl = generate_jni_impl(func_list, plugin_name, inputfile)
+ msg_handlers = generate_msg_handlers(func_list, plugin_name, inputfile)
+ handler_registration = generate_handler_registration(func_list)
+ api_verification = generate_api_verification(func_list)
+
+ jvpp_c_file = open("%s/jvpp_%s_gen.h" % (path, plugin_name), 'w')
+ jvpp_c_file.write(jvpp_c_template.substitute(
+ inputfile=inputfile,
+ class_cache=class_cache,
+ api_verification=api_verification,
+ jni_implementations=jni_impl,
+ msg_handlers=msg_handlers,
+ handler_registration=handler_registration))
+ jvpp_c_file.flush()
+ jvpp_c_file.close()
+
diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py
new file mode 100644
index 00000000..9aaa4c64
--- /dev/null
+++ b/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py
@@ -0,0 +1,326 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2016 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os, util
+from string import Template
+
+import callback_gen
+import dto_gen
+
+jvpp_ifc_template = Template("""
+package $plugin_package.$callback_facade_package;
+
+/**
+ * <p>Callback Java API representation of $plugin_package plugin.
+ * <br>It was generated by jvpp_callback_facade_gen.py based on $inputfile
+ * <br>(python representation of api file generated by vppapigen).
+ */
+public interface CallbackJVpp${plugin_name} extends $base_package.$notification_package.NotificationRegistryProvider, java.lang.AutoCloseable {
+
+ // TODO add send
+
+$methods
+}
+""")
+
+jvpp_impl_template = Template("""
+package $plugin_package.$callback_facade_package;
+
+/**
+ * <p>Default implementation of Callback${plugin_name}JVpp interface.
+ * <br>It was generated by jvpp_callback_facade_gen.py based on $inputfile
+ * <br>(python representation of api file generated by vppapigen).
+ */
+public final class CallbackJVpp${plugin_name}Facade implements CallbackJVpp${plugin_name} {
+
+ private final $plugin_package.JVpp${plugin_name} jvpp;
+ private final java.util.Map<Integer, $base_package.$callback_package.JVppCallback> callbacks;
+ private final $plugin_package.$notification_package.${plugin_name}NotificationRegistryImpl notificationRegistry = new $plugin_package.$notification_package.${plugin_name}NotificationRegistryImpl();
+ /**
+ * <p>Create CallbackJVpp${plugin_name}Facade object for provided JVpp instance.
+ * Constructor internally creates CallbackJVppFacadeCallback class for processing callbacks
+ * and then connects to provided JVpp instance
+ *
+ * @param jvpp provided $base_package.JVpp instance
+ *
+ * @throws java.io.IOException in case instance cannot connect to JVPP
+ */
+ public CallbackJVpp${plugin_name}Facade(final $base_package.JVppRegistry registry, final $plugin_package.JVpp${plugin_name} jvpp) throws java.io.IOException {
+ this.jvpp = java.util.Objects.requireNonNull(jvpp,"jvpp is null");
+ this.callbacks = new java.util.HashMap<>();
+ java.util.Objects.requireNonNull(registry, "JVppRegistry should not be null");
+ registry.register(jvpp, new CallbackJVpp${plugin_name}FacadeCallback(this.callbacks, notificationRegistry));
+ }
+
+ @Override
+ public $plugin_package.$notification_package.${plugin_name}NotificationRegistry getNotificationRegistry() {
+ return notificationRegistry;
+ }
+
+ @Override
+ public void close() throws Exception {
+ jvpp.close();
+ }
+
+ // TODO add send()
+
+$methods
+}
+""")
+
+method_template = Template(
+ """ void $name($plugin_package.$dto_package.$request request, $plugin_package.$callback_package.$callback callback) throws $base_package.VppInvocationException;""")
+
+method_impl_template = Template(""" public final void $name($plugin_package.$dto_package.$request request, $plugin_package.$callback_package.$callback callback) throws $base_package.VppInvocationException {
+ synchronized (callbacks) {
+ callbacks.put(jvpp.$name(request), callback);
+ }
+ }
+""")
+
+no_arg_method_template = Template(""" void $name($plugin_package.$callback_package.$callback callback) throws $base_package.VppInvocationException;""")
+no_arg_method_impl_template = Template(""" public final void $name($plugin_package.$callback_package.$callback callback) throws $base_package.VppInvocationException {
+ synchronized (callbacks) {
+ callbacks.put(jvpp.$name(), callback);
+ }
+ }
+""")
+
+
+def generate_jvpp(func_list, base_package, plugin_package, plugin_name, dto_package, callback_package, notification_package, callback_facade_package, inputfile):
+ """ Generates callback facade """
+ print "Generating JVpp callback facade"
+
+ if os.path.exists(callback_facade_package):
+ util.remove_folder(callback_facade_package)
+
+ os.mkdir(callback_facade_package)
+
+ methods = []
+ methods_impl = []
+ for func in func_list:
+
+ if util.is_notification(func['name']) or util.is_ignored(func['name']):
+ continue
+
+ camel_case_name = util.underscore_to_camelcase(func['name'])
+ camel_case_name_upper = util.underscore_to_camelcase_upper(func['name'])
+ if util.is_reply(camel_case_name) or util.is_control_ping(camel_case_name):
+ continue
+
+ # Strip suffix for dump calls
+ callback_type = get_request_name(camel_case_name_upper, func['name']) + callback_gen.callback_suffix
+
+ if len(func['args']) == 0:
+ methods.append(no_arg_method_template.substitute(name=camel_case_name,
+ base_package=base_package,
+ plugin_package=plugin_package,
+ dto_package=dto_package,
+ callback_package=callback_package,
+ callback=callback_type))
+ methods_impl.append(no_arg_method_impl_template.substitute(name=camel_case_name,
+ base_package=base_package,
+ plugin_package=plugin_package,
+ dto_package=dto_package,
+ callback_package=callback_package,
+ callback=callback_type))
+ else:
+ methods.append(method_template.substitute(name=camel_case_name,
+ request=camel_case_name_upper,
+ base_package=base_package,
+ plugin_package=plugin_package,
+ dto_package=dto_package,
+ callback_package=callback_package,
+ callback=callback_type))
+ methods_impl.append(method_impl_template.substitute(name=camel_case_name,
+ request=camel_case_name_upper,
+ base_package=base_package,
+ plugin_package=plugin_package,
+ dto_package=dto_package,
+ callback_package=callback_package,
+ callback=callback_type))
+
+ join = os.path.join(callback_facade_package, "CallbackJVpp%s.java" % plugin_name)
+ jvpp_file = open(join, 'w')
+ jvpp_file.write(
+ jvpp_ifc_template.substitute(inputfile=inputfile,
+ methods="\n".join(methods),
+ base_package=base_package,
+ plugin_package=plugin_package,
+ plugin_name=plugin_name,
+ dto_package=dto_package,
+ notification_package=notification_package,
+ callback_facade_package=callback_facade_package))
+ jvpp_file.flush()
+ jvpp_file.close()
+
+ jvpp_file = open(os.path.join(callback_facade_package, "CallbackJVpp%sFacade.java" % plugin_name), 'w')
+ jvpp_file.write(jvpp_impl_template.substitute(inputfile=inputfile,
+ methods="\n".join(methods_impl),
+ base_package=base_package,
+ plugin_package=plugin_package,
+ plugin_name=plugin_name,
+ dto_package=dto_package,
+ notification_package=notification_package,
+ callback_package=callback_package,
+ callback_facade_package=callback_facade_package))
+ jvpp_file.flush()
+ jvpp_file.close()
+
+ generate_callback(func_list, base_package, plugin_package, plugin_name, dto_package, callback_package, notification_package, callback_facade_package, inputfile)
+
+
+jvpp_facade_callback_template = Template("""
+package $plugin_package.$callback_facade_package;
+
+/**
+ * <p>Implementation of JVppGlobalCallback interface for Java Callback API.
+ * <br>It was generated by jvpp_callback_facade_gen.py based on $inputfile
+ * <br>(python representation of api file generated by vppapigen).
+ */
+public final class CallbackJVpp${plugin_name}FacadeCallback implements $plugin_package.$callback_package.JVpp${plugin_name}GlobalCallback {
+
+ private final java.util.Map<Integer, $base_package.$callback_package.JVppCallback> requests;
+ private final $plugin_package.$notification_package.Global${plugin_name}NotificationCallback notificationCallback;
+ private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(CallbackJVpp${plugin_name}FacadeCallback.class.getName());
+
+ public CallbackJVpp${plugin_name}FacadeCallback(final java.util.Map<Integer, $base_package.$callback_package.JVppCallback> requestMap,
+ final $plugin_package.$notification_package.Global${plugin_name}NotificationCallback notificationCallback) {
+ this.requests = requestMap;
+ this.notificationCallback = notificationCallback;
+ }
+
+ @Override
+ public void onError($base_package.VppCallbackException reply) {
+
+ $base_package.$callback_package.JVppCallback failedCall;
+ synchronized(requests) {
+ failedCall = requests.remove(reply.getCtxId());
+ }
+
+ if(failedCall != null) {
+ try {
+ failedCall.onError(reply);
+ } catch(RuntimeException ex) {
+ ex.addSuppressed(reply);
+ LOG.log(java.util.logging.Level.WARNING, String.format("Callback: %s failed while handling exception: %s", failedCall, reply), ex);
+ }
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void onControlPingReply(final $base_package.$dto_package.ControlPingReply reply) {
+
+ $base_package.$callback_package.ControlPingCallback callback;
+ final int replyId = reply.context;
+ synchronized(requests) {
+ callback = ($base_package.$callback_package.ControlPingCallback) requests.remove(replyId);
+ }
+
+ if(callback != null) {
+ callback.onControlPingReply(reply);
+ }
+ }
+
+$methods
+}
+""")
+
+jvpp_facade_callback_method_template = Template("""
+ @Override
+ @SuppressWarnings("unchecked")
+ public void on$callback_dto(final $plugin_package.$dto_package.$callback_dto reply) {
+
+ $plugin_package.$callback_package.$callback callback;
+ final int replyId = reply.context;
+ synchronized(requests) {
+ callback = ($plugin_package.$callback_package.$callback) requests.remove(replyId);
+ }
+
+ if(callback != null) {
+ callback.on$callback_dto(reply);
+ }
+ }
+""")
+
+jvpp_facade_callback_notification_method_template = Template("""
+ @Override
+ @SuppressWarnings("unchecked")
+ public void on$callback_dto($plugin_package.$dto_package.$callback_dto notification) {
+ notificationCallback.on$callback_dto(notification);
+ }
+""")
+
+
+def generate_callback(func_list, base_package, plugin_package, plugin_name, dto_package, callback_package, notification_package, callback_facade_package, inputfile):
+ callbacks = []
+ for func in func_list:
+
+ camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name'])
+
+ if util.is_ignored(func['name']) or util.is_control_ping(camel_case_name_with_suffix):
+ continue
+
+ if util.is_reply(camel_case_name_with_suffix):
+ callbacks.append(jvpp_facade_callback_method_template.substitute(plugin_package=plugin_package,
+ dto_package=dto_package,
+ callback_package=callback_package,
+ callback=util.remove_reply_suffix(camel_case_name_with_suffix) + callback_gen.callback_suffix,
+ callback_dto=camel_case_name_with_suffix))
+
+ if util.is_notification(func["name"]):
+ with_notification_suffix = util.add_notification_suffix(camel_case_name_with_suffix)
+ callbacks.append(jvpp_facade_callback_notification_method_template.substitute(plugin_package=plugin_package,
+ dto_package=dto_package,
+ callback_package=callback_package,
+ callback=with_notification_suffix + callback_gen.callback_suffix,
+ callback_dto=with_notification_suffix))
+
+ jvpp_file = open(os.path.join(callback_facade_package, "CallbackJVpp%sFacadeCallback.java" % plugin_name), 'w')
+ jvpp_file.write(jvpp_facade_callback_template.substitute(inputfile=inputfile,
+ base_package=base_package,
+ plugin_package=plugin_package,
+ plugin_name=plugin_name,
+ dto_package=dto_package,
+ notification_package=notification_package,
+ callback_package=callback_package,
+ methods="".join(callbacks),
+ callback_facade_package=callback_facade_package))
+ jvpp_file.flush()
+ jvpp_file.close()
+
+
+# Returns request name or special one from unconventional_naming_rep_req map
+def get_request_name(camel_case_dto_name, func_name):
+ if func_name in reverse_dict(util.unconventional_naming_rep_req):
+ request_name = util.underscore_to_camelcase_upper(reverse_dict(util.unconventional_naming_rep_req)[func_name])
+ else:
+ request_name = camel_case_dto_name
+ return remove_suffix(request_name)
+
+
+def reverse_dict(map):
+ return dict((v, k) for k, v in map.iteritems())
+
+
+def remove_suffix(name):
+ if util.is_reply(name):
+ return util.remove_reply_suffix(name)
+ else:
+ if util.is_dump(name):
+ return util.remove_suffix(name, util.dump_suffix)
+ else:
+ return name
diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py
new file mode 100644
index 00000000..07947e30
--- /dev/null
+++ b/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py
@@ -0,0 +1,331 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2016 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+from string import Template
+
+import dto_gen
+import util
+
+jvpp_facade_callback_template = Template("""
+package $plugin_package.$future_package;
+
+/**
+ * <p>Async facade callback setting values to future objects
+ * <br>It was generated by jvpp_future_facade_gen.py based on $inputfile
+ * <br>(python representation of api file generated by vppapigen).
+ */
+public final class FutureJVpp${plugin_name}FacadeCallback implements $plugin_package.$callback_package.JVpp${plugin_name}GlobalCallback {
+
+ private final java.util.Map<java.lang.Integer, java.util.concurrent.CompletableFuture<? extends $base_package.$dto_package.JVppReply<?>>> requests;
+ private final $plugin_package.$notification_package.Global${plugin_name}NotificationCallback notificationCallback;
+
+ public FutureJVpp${plugin_name}FacadeCallback(
+ final java.util.Map<java.lang.Integer, java.util.concurrent.CompletableFuture<? extends $base_package.$dto_package.JVppReply<?>>> requestMap,
+ final $plugin_package.$notification_package.Global${plugin_name}NotificationCallback notificationCallback) {
+ this.requests = requestMap;
+ this.notificationCallback = notificationCallback;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void onError($base_package.VppCallbackException reply) {
+ final java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply<?>> completableFuture;
+
+ synchronized(requests) {
+ completableFuture = (java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply<?>>) requests.get(reply.getCtxId());
+ }
+
+ if(completableFuture != null) {
+ completableFuture.completeExceptionally(reply);
+
+ synchronized(requests) {
+ requests.remove(reply.getCtxId());
+ }
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void onControlPingReply(final $base_package.$dto_package.ControlPingReply reply) {
+ final java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply<?>> completableFuture;
+
+ final int replyId = reply.context;
+ synchronized(requests) {
+ completableFuture = (java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply<?>>) requests.get(replyId);
+ }
+
+ if(completableFuture != null) {
+ // Finish dump call
+ if (completableFuture instanceof $base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture) {
+ completableFuture.complete((($base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture) completableFuture).getReplyDump());
+ // Remove future mapped to dump call context id
+ synchronized(requests) {
+ requests.remove((($base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture) completableFuture).getContextId());
+ }
+ } else {
+ completableFuture.complete(reply);
+ }
+ synchronized(requests) {
+ requests.remove(replyId);
+ }
+ }
+ }
+
+$methods
+}
+""")
+
+jvpp_facade_callback_method_template = Template("""
+ @Override
+ @SuppressWarnings("unchecked")
+ public void on$callback_dto(final $plugin_package.$dto_package.$callback_dto reply) {
+ final java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply<?>> completableFuture;
+ final int replyId = reply.context;
+ synchronized(requests) {
+ completableFuture = (java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply<?>>) requests.get(replyId);
+ }
+
+ if(completableFuture != null) {
+ completableFuture.complete(reply);
+
+ synchronized(requests) {
+ requests.remove(replyId);
+ }
+ }
+ }
+""")
+
+jvpp_facade_callback_notification_method_template = Template("""
+ @Override
+ public void on$callback_dto($plugin_package.$dto_package.$callback_dto notification) {
+ notificationCallback.on$callback_dto(notification);
+ }
+""")
+
+jvpp_facade_details_callback_method_template = Template("""
+ @Override
+ @SuppressWarnings("unchecked")
+ public void on$callback_dto(final $plugin_package.$dto_package.$callback_dto reply) {
+ final $base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture<$plugin_package.$dto_package.$callback_dto_reply_dump> completableFuture;
+ final int replyId = reply.context;
+ synchronized(requests) {
+ completableFuture = ($base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture<$plugin_package.$dto_package.$callback_dto_reply_dump>) requests.get(replyId);
+ }
+
+ if(completableFuture != null) {
+ completableFuture.getReplyDump().$callback_dto_field.add(reply);
+ }
+ }
+""")
+
+
+def generate_jvpp(func_list, base_package, plugin_package, plugin_name, dto_package, callback_package, notification_package, future_facade_package, inputfile):
+ """ Generates JVpp interface and JNI implementation """
+ print "Generating JVpp future facade"
+
+ if not os.path.exists(future_facade_package):
+ os.mkdir(future_facade_package)
+
+ methods = []
+ methods_impl = []
+ callbacks = []
+ for func in func_list:
+ camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name'])
+
+ if util.is_ignored(func['name']) or util.is_control_ping(camel_case_name_with_suffix):
+ continue
+
+ if not util.is_reply(camel_case_name_with_suffix) and not util.is_notification(func['name']):
+ continue
+
+ camel_case_method_name = util.underscore_to_camelcase(func['name'])
+
+ if not util.is_notification(func["name"]):
+ camel_case_request_method_name = util.remove_reply_suffix(util.underscore_to_camelcase(func['name']))
+ if util.is_details(camel_case_name_with_suffix):
+ camel_case_reply_name = get_standard_dump_reply_name(util.underscore_to_camelcase_upper(func['name']),
+ func['name'])
+ callbacks.append(jvpp_facade_details_callback_method_template.substitute(base_package=base_package,
+ plugin_package=plugin_package,
+ dto_package=dto_package,
+ callback_dto=camel_case_name_with_suffix,
+ callback_dto_field=camel_case_method_name,
+ callback_dto_reply_dump=camel_case_reply_name + dto_gen.dump_dto_suffix,
+ future_package=future_facade_package))
+
+ methods.append(future_jvpp_method_template.substitute(plugin_package=plugin_package,
+ dto_package=dto_package,
+ method_name=camel_case_request_method_name +
+ util.underscore_to_camelcase_upper(util.dump_suffix),
+ reply_name=camel_case_reply_name + dto_gen.dump_dto_suffix,
+ request_name=util.remove_reply_suffix(camel_case_reply_name) +
+ util.underscore_to_camelcase_upper(util.dump_suffix)))
+ methods_impl.append(future_jvpp_dump_method_impl_template.substitute(plugin_package=plugin_package,
+ dto_package=dto_package,
+ method_name=camel_case_request_method_name +
+ util.underscore_to_camelcase_upper(util.dump_suffix),
+ reply_name=camel_case_reply_name + dto_gen.dump_dto_suffix,
+ request_name=util.remove_reply_suffix(camel_case_reply_name) +
+ util.underscore_to_camelcase_upper(util.dump_suffix)))
+ else:
+ request_name = util.underscore_to_camelcase_upper(util.unconventional_naming_rep_req[func['name']]) \
+ if func['name'] in util.unconventional_naming_rep_req else util.remove_reply_suffix(camel_case_name_with_suffix)
+
+ methods.append(future_jvpp_method_template.substitute(plugin_package=plugin_package,
+ dto_package=dto_package,
+ method_name=camel_case_request_method_name,
+ reply_name=camel_case_name_with_suffix,
+ request_name=request_name))
+ methods_impl.append(future_jvpp_method_impl_template.substitute(plugin_package=plugin_package,
+ dto_package=dto_package,
+ method_name=camel_case_request_method_name,
+ reply_name=camel_case_name_with_suffix,
+ request_name=request_name))
+
+ callbacks.append(jvpp_facade_callback_method_template.substitute(base_package=base_package,
+ plugin_package=plugin_package,
+ dto_package=dto_package,
+ callback_dto=camel_case_name_with_suffix))
+
+ if util.is_notification(func["name"]):
+ callbacks.append(jvpp_facade_callback_notification_method_template.substitute(plugin_package=plugin_package,
+ dto_package=dto_package,
+ callback_dto=util.add_notification_suffix(camel_case_name_with_suffix)))
+
+ jvpp_file = open(os.path.join(future_facade_package, "FutureJVpp%sFacadeCallback.java" % plugin_name), 'w')
+ jvpp_file.write(jvpp_facade_callback_template.substitute(inputfile=inputfile,
+ base_package=base_package,
+ plugin_package=plugin_package,
+ plugin_name=plugin_name,
+ dto_package=dto_package,
+ notification_package=notification_package,
+ callback_package=callback_package,
+ methods="".join(callbacks),
+ future_package=future_facade_package))
+ jvpp_file.flush()
+ jvpp_file.close()
+
+ jvpp_file = open(os.path.join(future_facade_package, "FutureJVpp%s.java" % plugin_name), 'w')
+ jvpp_file.write(future_jvpp_template.substitute(inputfile=inputfile,
+ base_package=base_package,
+ plugin_package=plugin_package,
+ plugin_name=plugin_name,
+ notification_package=notification_package,
+ methods="".join(methods),
+ future_package=future_facade_package))
+ jvpp_file.flush()
+ jvpp_file.close()
+
+ jvpp_file = open(os.path.join(future_facade_package, "FutureJVpp%sFacade.java" % plugin_name), 'w')
+ jvpp_file.write(future_jvpp_facade_template.substitute(inputfile=inputfile,
+ base_package=base_package,
+ plugin_package=plugin_package,
+ plugin_name=plugin_name,
+ dto_package=dto_package,
+ notification_package=notification_package,
+ methods="".join(methods_impl),
+ future_package=future_facade_package))
+ jvpp_file.flush()
+ jvpp_file.close()
+
+
+future_jvpp_template = Template('''
+package $plugin_package.$future_package;
+
+/**
+ * <p>Async facade extension adding specific methods for each request invocation
+ * <br>It was generated by jvpp_future_facade_gen.py based on $inputfile
+ * <br>(python representation of api file generated by vppapigen).
+ */
+public interface FutureJVpp${plugin_name} extends $base_package.$future_package.FutureJVppInvoker {
+$methods
+
+ @Override
+ public $plugin_package.$notification_package.${plugin_name}NotificationRegistry getNotificationRegistry();
+
+}
+''')
+
+future_jvpp_method_template = Template('''
+ java.util.concurrent.CompletionStage<$plugin_package.$dto_package.$reply_name> $method_name($plugin_package.$dto_package.$request_name request);
+''')
+
+
+future_jvpp_facade_template = Template('''
+package $plugin_package.$future_package;
+
+/**
+ * <p>Implementation of FutureJVpp based on AbstractFutureJVppInvoker
+ * <br>It was generated by jvpp_future_facade_gen.py based on $inputfile
+ * <br>(python representation of api file generated by vppapigen).
+ */
+public class FutureJVpp${plugin_name}Facade extends $base_package.$future_package.AbstractFutureJVppInvoker implements FutureJVpp${plugin_name} {
+
+ private final $plugin_package.$notification_package.${plugin_name}NotificationRegistryImpl notificationRegistry = new $plugin_package.$notification_package.${plugin_name}NotificationRegistryImpl();
+
+ /**
+ * <p>Create FutureJVpp${plugin_name}Facade object for provided JVpp instance.
+ * Constructor internally creates FutureJVppFacadeCallback class for processing callbacks
+ * and then connects to provided JVpp instance
+ *
+ * @param jvpp provided $base_package.JVpp instance
+ *
+ * @throws java.io.IOException in case instance cannot connect to JVPP
+ */
+ public FutureJVpp${plugin_name}Facade(final $base_package.JVppRegistry registry, final $base_package.JVpp jvpp) throws java.io.IOException {
+ super(jvpp, registry, new java.util.HashMap<>());
+ java.util.Objects.requireNonNull(registry, "JVppRegistry should not be null");
+ registry.register(jvpp, new FutureJVpp${plugin_name}FacadeCallback(getRequests(), notificationRegistry));
+ }
+
+ @Override
+ public $plugin_package.$notification_package.${plugin_name}NotificationRegistry getNotificationRegistry() {
+ return notificationRegistry;
+ }
+
+$methods
+}
+''')
+
+future_jvpp_method_impl_template = Template('''
+ @Override
+ public java.util.concurrent.CompletionStage<$plugin_package.$dto_package.$reply_name> $method_name($plugin_package.$dto_package.$request_name request) {
+ return send(request);
+ }
+''')
+
+future_jvpp_dump_method_impl_template = Template('''
+ @Override
+ public java.util.concurrent.CompletionStage<$plugin_package.$dto_package.$reply_name> $method_name($plugin_package.$dto_package.$request_name request) {
+ return send(request, new $plugin_package.$dto_package.$reply_name());
+ }
+''')
+
+
+# Returns request name or special one from unconventional_naming_rep_req map
+def get_standard_dump_reply_name(camel_case_dto_name, func_name):
+ # FIXME this is a hotfix for sub-details callbacks
+ # FIXME also for L2FibTableEntry
+ # It's all because unclear mapping between
+ # request -> reply,
+ # dump -> reply, details,
+ # notification_start -> reply, notifications
+
+ # vpe.api needs to be "standardized" so we can parse the information and create maps before generating java code
+ suffix = func_name.split("_")[-1]
+ return util.underscore_to_camelcase_upper(
+ util.unconventional_naming_rep_req[func_name]) + util.underscore_to_camelcase_upper(suffix) if func_name in util.unconventional_naming_rep_req \
+ else camel_case_dto_name
diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py
new file mode 100644
index 00000000..7bf91138
--- /dev/null
+++ b/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py
@@ -0,0 +1,219 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2016 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os, util
+from string import Template
+
+jvpp_ifc_template = Template("""
+package $plugin_package;
+
+/**
+ * <p>Java representation of plugin's api file.
+ * <br>It was generated by jvpp_impl_gen.py based on $inputfile
+ * <br>(python representation of api file generated by vppapigen).
+ */
+public interface JVpp${plugin_name} extends $base_package.JVpp {
+
+ /**
+ * Generic dispatch method for sending requests to VPP
+ *
+ * @throws io.fd.vpp.jvpp.VppInvocationException if send request had failed
+ */
+ int send($base_package.$dto_package.JVppRequest request) throws io.fd.vpp.jvpp.VppInvocationException;
+
+$methods
+}
+""")
+
+jvpp_impl_template = Template("""
+package $plugin_package;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.util.Set;
+import java.util.logging.Logger;
+import $base_package.callback.JVppCallback;
+import $base_package.VppConnection;
+import $base_package.JVppRegistry;
+
+/**
+ * <p>Default implementation of JVpp interface.
+ * <br>It was generated by jvpp_impl_gen.py based on $inputfile
+ * <br>(python representation of api file generated by vppapigen).
+ */
+public final class JVpp${plugin_name}Impl implements $plugin_package.JVpp${plugin_name} {
+
+ private final static Logger LOG = Logger.getLogger(JVpp${plugin_name}Impl.class.getName());
+ private static final String LIBNAME = "libjvpp_${plugin_name_underscore}.so";
+
+ // FIXME using NativeLibraryLoader makes load fail could not find (WantInterfaceEventsReply).
+ static {
+ try {
+ loadLibrary();
+ } catch (Exception e) {
+ LOG.severe("Can't find jvpp jni library: " + LIBNAME);
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ private static void loadStream(final InputStream is) throws IOException {
+ final Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rwxr-x---");
+ final Path p = Files.createTempFile(LIBNAME, null, PosixFilePermissions.asFileAttribute(perms));
+ try {
+ Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING);
+
+ try {
+ Runtime.getRuntime().load(p.toString());
+ } catch (UnsatisfiedLinkError e) {
+ throw new IOException("Failed to load library " + p, e);
+ }
+ } finally {
+ try {
+ Files.deleteIfExists(p);
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ private static void loadLibrary() throws IOException {
+ try (final InputStream is = JVpp${plugin_name}Impl.class.getResourceAsStream('/' + LIBNAME)) {
+ if (is == null) {
+ throw new IOException("Failed to open library resource " + LIBNAME);
+ }
+ loadStream(is);
+ }
+ }
+
+ private VppConnection connection;
+ private JVppRegistry registry;
+
+ private static native void init0(final JVppCallback callback, final long queueAddress, final int clientIndex);
+ @Override
+ public void init(final JVppRegistry registry, final JVppCallback callback, final long queueAddress, final int clientIndex) {
+ this.registry = java.util.Objects.requireNonNull(registry, "registry should not be null");
+ this.connection = java.util.Objects.requireNonNull(registry.getConnection(), "connection should not be null");
+ connection.checkActive();
+ init0(callback, queueAddress, clientIndex);
+ }
+
+ private static native void close0();
+ @Override
+ public void close() {
+ close0();
+ }
+
+ @Override
+ public int send($base_package.$dto_package.JVppRequest request) throws io.fd.vpp.jvpp.VppInvocationException {
+ return request.send(this);
+ }
+
+ @Override
+ public final int controlPing(final io.fd.vpp.jvpp.dto.ControlPing controlPing) throws io.fd.vpp.jvpp.VppInvocationException {
+ return registry.controlPing(JVpp${plugin_name}Impl.class);
+ }
+
+$methods
+}
+""")
+
+method_template = Template(""" int $name($plugin_package.$dto_package.$request request) throws io.fd.vpp.jvpp.VppInvocationException;""")
+method_native_template = Template(
+ """ private static native int ${name}0($plugin_package.$dto_package.$request request);""")
+method_impl_template = Template(""" public final int $name($plugin_package.$dto_package.$request request) throws io.fd.vpp.jvpp.VppInvocationException {
+ java.util.Objects.requireNonNull(request,"Null request object");
+ connection.checkActive();
+ int result=${name}0(request);
+ if(result<0){
+ throw new io.fd.vpp.jvpp.VppInvocationException("${name}",result);
+ }
+ return result;
+ }
+""")
+
+no_arg_method_template = Template(""" int $name() throws io.fd.vpp.jvpp.VppInvocationException;""")
+no_arg_method_native_template = Template(""" private static native int ${name}0() throws io.fd.vpp.jvpp.VppInvocationException;""")
+no_arg_method_impl_template = Template(""" public final int $name() throws io.fd.vpp.jvpp.VppInvocationException {
+ connection.checkActive();
+ int result=${name}0();
+ if(result<0){
+ throw new io.fd.vpp.jvpp.VppInvocationException("${name}",result);
+ }
+ return result;
+ }
+""")
+
+
+def generate_jvpp(func_list, base_package, plugin_package, plugin_name_underscore, dto_package, inputfile):
+ """ Generates JVpp interface and JNI implementation """
+ print "Generating JVpp"
+ plugin_name = util.underscore_to_camelcase_upper(plugin_name_underscore)
+
+ methods = []
+ methods_impl = []
+ for func in func_list:
+
+ # Skip structures that are used only as notifications
+ if util.is_just_notification(func['name']) or util.is_ignored(func['name']):
+ continue
+
+ camel_case_name = util.underscore_to_camelcase(func['name'])
+ camel_case_name_upper = util.underscore_to_camelcase_upper(func['name'])
+ if util.is_reply(camel_case_name):
+ continue
+
+ if len(func['args']) == 0:
+ methods.append(no_arg_method_template.substitute(name=camel_case_name))
+ methods_impl.append(no_arg_method_native_template.substitute(name=camel_case_name))
+ methods_impl.append(no_arg_method_impl_template.substitute(name=camel_case_name))
+ else:
+ methods.append(method_template.substitute(name=camel_case_name,
+ request=camel_case_name_upper,
+ plugin_package=plugin_package,
+ dto_package=dto_package))
+ methods_impl.append(method_native_template.substitute(name=camel_case_name,
+ request=camel_case_name_upper,
+ plugin_package=plugin_package,
+ dto_package=dto_package))
+ methods_impl.append(method_impl_template.substitute(name=camel_case_name,
+ request=camel_case_name_upper,
+ plugin_package=plugin_package,
+ dto_package=dto_package))
+
+ jvpp_file = open("JVpp%s.java" % plugin_name, 'w')
+ jvpp_file.write(
+ jvpp_ifc_template.substitute(inputfile=inputfile,
+ methods="\n".join(methods),
+ base_package=base_package,
+ plugin_package=plugin_package,
+ plugin_name=plugin_name,
+ dto_package=dto_package))
+ jvpp_file.flush()
+ jvpp_file.close()
+
+ jvpp_file = open("JVpp%sImpl.java" % plugin_name, 'w')
+ jvpp_file.write(jvpp_impl_template.substitute(inputfile=inputfile,
+ methods="\n".join(methods_impl),
+ base_package=base_package,
+ plugin_package=plugin_package,
+ plugin_name=plugin_name,
+ plugin_name_underscore=plugin_name_underscore,
+ dto_package=dto_package))
+ jvpp_file.flush()
+ jvpp_file.close()
diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/notification_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/notification_gen.py
new file mode 100644
index 00000000..94302d56
--- /dev/null
+++ b/src/vpp-api/java/jvpp/gen/jvppgen/notification_gen.py
@@ -0,0 +1,199 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2016 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+
+import callback_gen
+import util
+from string import Template
+
+notification_registry_template = Template("""
+package $plugin_package.$notification_package;
+
+/**
+ * <p>Registry for notification callbacks defined in ${plugin_name}.
+ * <br>It was generated by notification_gen.py based on $inputfile
+ * <br>(python representation of api file generated by vppapigen).
+ */
+public interface ${plugin_name}NotificationRegistry extends $base_package.$notification_package.NotificationRegistry {
+
+ $register_callback_methods
+
+ @Override
+ void close();
+}
+""")
+
+global_notification_callback_template = Template("""
+package $plugin_package.$notification_package;
+
+/**
+ * <p>Aggregated callback interface for notifications only.
+ * <br>It was generated by notification_gen.py based on $inputfile
+ * <br>(python representation of api file generated by vppapigen).
+ */
+public interface Global${plugin_name}NotificationCallback$callbacks {
+
+}
+""")
+
+notification_registry_impl_template = Template("""
+package $plugin_package.$notification_package;
+
+/**
+ * <p>Notification registry delegating notification processing to registered callbacks.
+ * <br>It was generated by notification_gen.py based on $inputfile
+ * <br>(python representation of api file generated by vppapigen).
+ */
+public final class ${plugin_name}NotificationRegistryImpl implements ${plugin_name}NotificationRegistry, Global${plugin_name}NotificationCallback {
+
+ // TODO add a special NotificationCallback interface and only allow those to be registered
+ private final java.util.concurrent.ConcurrentMap<Class<? extends $base_package.$dto_package.JVppNotification>, $base_package.$callback_package.JVppNotificationCallback> registeredCallbacks =
+ new java.util.concurrent.ConcurrentHashMap<>();
+
+ $register_callback_methods
+ $handler_methods
+
+ @Override
+ public void close() {
+ registeredCallbacks.clear();
+ }
+}
+""")
+
+register_callback_impl_template = Template("""
+ public java.lang.AutoCloseable register$callback(final $plugin_package.$callback_package.$callback callback){
+ if(null != registeredCallbacks.putIfAbsent($plugin_package.$dto_package.$notification.class, callback)){
+ throw new IllegalArgumentException("Callback for " + $plugin_package.$dto_package.$notification.class +
+ "notification already registered");
+ }
+ return () -> registeredCallbacks.remove($plugin_package.$dto_package.$notification.class);
+ }
+""")
+
+handler_impl_template = Template("""
+ @Override
+ public void on$notification(
+ final $plugin_package.$dto_package.$notification notification) {
+ final $base_package.$callback_package.JVppNotificationCallback jVppNotificationCallback = registeredCallbacks.get($plugin_package.$dto_package.$notification.class);
+ if (null != jVppNotificationCallback) {
+ (($plugin_package.$callback_package.$callback) registeredCallbacks
+ .get($plugin_package.$dto_package.$notification.class))
+ .on$notification(notification);
+ }
+ }
+""")
+
+notification_provider_template = Template("""
+package $plugin_package.$notification_package;
+
+ /**
+ * Provides ${plugin_name}NotificationRegistry.
+ * <br>The file was generated by notification_gen.py based on $inputfile
+ * <br>(python representation of api file generated by vppapigen).
+ */
+public interface ${plugin_name}NotificationRegistryProvider extends $base_package.$notification_package.NotificationRegistryProvider {
+
+ @Override
+ public ${plugin_name}NotificationRegistry getNotificationRegistry();
+}
+""")
+
+
+def generate_notification_registry(func_list, base_package, plugin_package, plugin_name, notification_package, callback_package, dto_package, inputfile):
+ """ Generates notification registry interface and implementation """
+ print "Generating Notification interfaces and implementation"
+
+ if not os.path.exists(notification_package):
+ os.mkdir(notification_package)
+
+ callbacks = []
+ register_callback_methods = []
+ register_callback_methods_impl = []
+ handler_methods = []
+ for func in func_list:
+
+ if not util.is_notification(func['name']):
+ continue
+
+ camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name'])
+ notification_dto = util.add_notification_suffix(camel_case_name_with_suffix)
+ callback_ifc = notification_dto + callback_gen.callback_suffix
+ fully_qualified_callback_ifc = "{0}.{1}.{2}".format(plugin_package, callback_package, callback_ifc)
+ callbacks.append(fully_qualified_callback_ifc)
+
+ # TODO create NotificationListenerRegistration and return that instead of AutoCloseable to better indicate
+ # that the registration should be closed
+ register_callback_methods.append("java.lang.AutoCloseable register{0}({1} callback);"
+ .format(callback_ifc, fully_qualified_callback_ifc))
+ register_callback_methods_impl.append(register_callback_impl_template.substitute(plugin_package=plugin_package,
+ callback_package=callback_package,
+ dto_package=dto_package,
+ notification=notification_dto,
+ callback=callback_ifc))
+ handler_methods.append(handler_impl_template.substitute(base_package=base_package,
+ plugin_package=plugin_package,
+ callback_package=callback_package,
+ dto_package=dto_package,
+ notification=notification_dto,
+ callback=callback_ifc))
+
+
+ callback_file = open(os.path.join(notification_package, "%sNotificationRegistry.java" % plugin_name), 'w')
+ callback_file.write(notification_registry_template.substitute(inputfile=inputfile,
+ register_callback_methods="\n ".join(register_callback_methods),
+ base_package=base_package,
+ plugin_package=plugin_package,
+ plugin_name=plugin_name,
+ notification_package=notification_package))
+ callback_file.flush()
+ callback_file.close()
+
+ callback_file = open(os.path.join(notification_package, "Global%sNotificationCallback.java" % plugin_name), 'w')
+
+ global_notification_callback_callbacks = ""
+ if (callbacks):
+ global_notification_callback_callbacks = " extends " + ", ".join(callbacks)
+
+ callback_file.write(global_notification_callback_template.substitute(inputfile=inputfile,
+ callbacks=global_notification_callback_callbacks,
+ plugin_package=plugin_package,
+ plugin_name=plugin_name,
+ notification_package=notification_package))
+ callback_file.flush()
+ callback_file.close()
+
+ callback_file = open(os.path.join(notification_package, "%sNotificationRegistryImpl.java" % plugin_name), 'w')
+ callback_file.write(notification_registry_impl_template.substitute(inputfile=inputfile,
+ callback_package=callback_package,
+ dto_package=dto_package,
+ register_callback_methods="".join(register_callback_methods_impl),
+ handler_methods="".join(handler_methods),
+ base_package=base_package,
+ plugin_package=plugin_package,
+ plugin_name=plugin_name,
+ notification_package=notification_package))
+ callback_file.flush()
+ callback_file.close()
+
+ callback_file = open(os.path.join(notification_package, "%sNotificationRegistryProvider.java" % plugin_name), 'w')
+ callback_file.write(notification_provider_template.substitute(inputfile=inputfile,
+ base_package=base_package,
+ plugin_package=plugin_package,
+ plugin_name=plugin_name,
+ notification_package=notification_package))
+ callback_file.flush()
+ callback_file.close()
+
diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/types_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/types_gen.py
new file mode 100644
index 00000000..858ea8ba
--- /dev/null
+++ b/src/vpp-api/java/jvpp/gen/jvppgen/types_gen.py
@@ -0,0 +1,232 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2016 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+from string import Template
+
+import util
+import jni_gen
+import dto_gen
+
+type_template = Template("""
+package $plugin_package.$type_package;
+
+/**
+ * <p>This class represents $c_type_name type definition.
+ * <br>It was generated by types_gen.py based on $inputfile preparsed data:
+ * <pre>
+$docs
+ * </pre>
+ */
+public final class $java_type_name {
+$fields
+$methods
+}
+""")
+
+field_template = Template(""" public $type $name;\n""")
+
+
+def generate_type_fields(type_definition):
+ """
+ Generates fields for class representing typeonly definition
+ :param type_definition: python representation of typeonly definition
+ :return: string representing class fields
+ """
+ fields = ""
+ for t in zip(type_definition['types'], type_definition['args']):
+ field_name = util.underscore_to_camelcase(t[1])
+ fields += field_template.substitute(type=util.jni_2_java_type_mapping[t[0]],
+ name=field_name)
+ return fields
+
+object_struct_setter_template = Template("""
+ {
+ jclass ${field_reference_name}Class = (*env)->FindClass(env, "${class_FQN}");
+ memset (&(mp->${c_name}), 0, sizeof (mp->${c_name}));
+ ${struct_initialization}
+ }
+""")
+
+object_array_struct_setter_template = Template("""
+ {
+ jclass ${field_reference_name}ArrayElementClass = (*env)->FindClass(env, "${class_FQN}");
+ if (${field_reference_name}) {
+ size_t _i;
+ jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name});
+ ${field_length_check}
+ for (_i = 0; _i < cnt; _i++) {
+ jobject ${field_reference_name}ArrayElement = (*env)->GetObjectArrayElement(env, ${field_reference_name}, _i);
+ memset (&(mp->${c_name}[_i]), 0, sizeof (mp->${c_name}[_i]));
+ ${struct_initialization}
+ }
+ }
+ }
+""")
+
+object_dto_field_setter_template = Template("""
+ {
+ jclass ${field_reference_name}Class = (*env)->FindClass(env, "${class_FQN}");
+ jmethodID ${field_reference_name}Constructor = (*env)->GetMethodID(env, ${field_reference_name}Class, "<init>", "()V");
+ jobject ${field_reference_name} = (*env)->NewObject(env, ${field_reference_name}Class, ${field_reference_name}Constructor);
+ ${type_initialization}
+ (*env)->SetObjectField(env, dto, ${field_reference_name}FieldId, ${field_reference_name});
+ (*env)->DeleteLocalRef(env, ${field_reference_name});
+ }
+""")
+
+object_array_dto_field_setter_template = Template("""
+ {
+ jclass ${field_reference_name}Class = (*env)->FindClass(env, "${class_FQN}");
+ jobjectArray ${field_reference_name} = (*env)->NewObjectArray(env, ${field_length}, ${field_reference_name}Class, 0);
+ jmethodID ${field_reference_name}Constructor = (*env)->GetMethodID(env, ${field_reference_name}Class, "<init>", "()V");
+ unsigned int _i;
+ for (_i = 0; _i < ${field_length}; _i++) {
+ jobject ${field_reference_name}ArrayElement = (*env)->NewObject(env, ${field_reference_name}Class, ${field_reference_name}Constructor);
+ ${type_initialization}
+ (*env)->SetObjectArrayElement(env, ${field_reference_name}, _i, ${field_reference_name}ArrayElement);
+ (*env)->DeleteLocalRef(env, ${field_reference_name}ArrayElement);
+ }
+ (*env)->SetObjectField(env, dto, ${field_reference_name}FieldId, ${field_reference_name});
+ (*env)->DeleteLocalRef(env, ${field_reference_name});
+ }
+""")
+
+
+def generate_struct_initialization(type_def, c_name_prefix, object_name, indent):
+ struct_initialization = ""
+ # field identifiers
+ for t in zip(type_def['types'], type_def['args'], type_def['lengths']):
+ field_reference_name = "${c_name}" + util.underscore_to_camelcase_upper(t[1])
+ field_name = util.underscore_to_camelcase(t[1])
+ struct_initialization += jni_gen.jni_request_identifiers_for_type(field_type=t[0],
+ field_reference_name=field_reference_name,
+ field_name=field_name,
+ object_name=object_name)
+ struct_initialization += jni_gen.jni_request_binding_for_type(field_type=t[0], c_name=c_name_prefix + t[1],
+ field_reference_name=field_reference_name,
+ field_length=t[2][0],
+ is_variable_len_array=t[2][1])
+ return indent + struct_initialization.replace('\n', '\n' + indent)
+
+
+def generate_type_setter(handler_name, type_def, c_name_prefix, object_name, indent):
+ type_initialization = ""
+ for t in zip(type_def['types'], type_def['args'], type_def['lengths']):
+ field_length = t[2][0]
+ is_variable_len_array = t[2][1]
+ length_field_type = None
+ if is_variable_len_array:
+ length_field_type = type_def['types'][type_def['args'].index(field_length)]
+ type_initialization += jni_gen.jni_reply_handler_for_type(handler_name=handler_name,
+ ref_name="${field_reference_name}",
+ field_type=t[0], c_name=c_name_prefix + t[1],
+ field_reference_name="${c_name}" + util.underscore_to_camelcase_upper(t[1]),
+ field_name=util.underscore_to_camelcase(t[1]),
+ field_length=field_length,
+ is_variable_len_array=is_variable_len_array,
+ length_field_type=length_field_type,
+ object_name=object_name)
+ return indent + type_initialization.replace('\n', '\n' + indent)
+
+
+def generate_types(types_list, plugin_package, types_package, inputfile):
+ """
+ Generates Java representation of custom types defined in api file.
+ """
+
+ #
+ if not types_list:
+ print "Skipping custom types generation (%s does not define custom types)." % inputfile
+ return
+
+ print "Generating custom types"
+
+ if not os.path.exists(types_package):
+ os.mkdir(types_package)
+
+ for type in types_list:
+ c_type_name = type['name']
+ java_type_name = util.underscore_to_camelcase_upper(type['name'])
+ dto_path = os.path.join(types_package, java_type_name + ".java")
+
+ fields = generate_type_fields(type)
+
+ dto_file = open(dto_path, 'w')
+ dto_file.write(type_template.substitute(plugin_package=plugin_package,
+ type_package=types_package,
+ c_type_name=c_type_name,
+ inputfile=inputfile,
+ docs=util.api_message_to_javadoc(type),
+ java_type_name=java_type_name,
+ fields=fields,
+ methods=dto_gen.generate_dto_base_methods(java_type_name, type)
+ ))
+
+ # update type mappings:
+ # todo fix vpe.api to use type_name instead of vl_api_type_name_t
+ type_name = "vl_api_" + c_type_name + "_t"
+ java_fqn = "%s.%s.%s" % (plugin_package, types_package, java_type_name)
+ util.vpp_2_jni_type_mapping[type_name] = "jobject"
+ util.vpp_2_jni_type_mapping[type_name + "[]"] = "jobjectArray"
+ util.jni_2_java_type_mapping[type_name] = java_fqn
+ util.jni_2_java_type_mapping[type_name + "[]"] = java_fqn + "[]"
+ jni_name = java_fqn.replace('.', "/")
+ jni_signature = "L" + jni_name + ";"
+ util.jni_2_signature_mapping[type_name] = "L" + jni_name + ";"
+ util.jni_2_signature_mapping[type_name + "[]"] = "[" + jni_signature
+ util.jni_field_accessors[type_name] = "ObjectField"
+ util.jni_field_accessors[type_name + "[]"] = "ObjectField"
+
+ jni_gen.struct_setter_templates[type_name] = Template(
+ object_struct_setter_template.substitute(
+ c_name="${c_name}",
+ field_reference_name="${field_reference_name}",
+ class_FQN=jni_name,
+ struct_initialization=generate_struct_initialization(type, "${c_name}.",
+ "${field_reference_name}", ' ' * 4))
+ )
+
+ jni_gen.struct_setter_templates[type_name+ "[]"] = Template(
+ object_array_struct_setter_template.substitute(
+ c_name="${c_name}",
+ field_reference_name="${field_reference_name}",
+ field_length_check="${field_length_check}",
+ class_FQN=jni_name,
+ struct_initialization=generate_struct_initialization(type, "${c_name}[_i].",
+ "${field_reference_name}ArrayElement", ' ' * 8))
+ )
+
+ jni_gen.dto_field_setter_templates[type_name] = Template(
+ object_dto_field_setter_template.substitute(
+ field_reference_name="${field_reference_name}",
+ field_length="${field_length}",
+ class_FQN=jni_name,
+ type_initialization=generate_type_setter(c_type_name, type, "${c_name}.",
+ "${field_reference_name}", ' ' * 4))
+ )
+
+ jni_gen.dto_field_setter_templates[type_name + "[]"] = Template(
+ object_array_dto_field_setter_template.substitute(
+ field_reference_name="${field_reference_name}",
+ field_length="${field_length}",
+ class_FQN=jni_name,
+ type_initialization=generate_type_setter(c_type_name, type, "${c_name}[_i].",
+ "${field_reference_name}ArrayElement", ' ' * 8))
+ )
+
+ dto_file.flush()
+ dto_file.close()
+
diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/util.py b/src/vpp-api/java/jvpp/gen/jvppgen/util.py
new file mode 100644
index 00000000..42394419
--- /dev/null
+++ b/src/vpp-api/java/jvpp/gen/jvppgen/util.py
@@ -0,0 +1,212 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2016 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os, pprint
+from os import removedirs
+
+
+def underscore_to_camelcase(name):
+ name = name.title().replace("_", "")
+ return name[0].lower() + name[1:]
+
+
+def underscore_to_camelcase_upper(name):
+ name = name.title().replace("_", "")
+ return name[0].upper() + name[1:]
+
+
+def remove_folder(folder):
+ """ Remove folder with all its files """
+ for root, dirs, files in os.walk(folder, topdown=False):
+ for name in files:
+ os.remove(os.path.join(root, name))
+ removedirs(folder)
+
+
+reply_suffixes = ("reply", "details", "l2fibtableentry")
+
+
+def is_reply(name):
+ return name.lower().endswith(reply_suffixes)
+
+
+def is_details(name):
+ return name.lower().endswith(reply_suffixes[1]) or name.lower().endswith(reply_suffixes[2])
+
+
+def is_retval_field(name):
+ return name == 'retval'
+
+dump_suffix = "dump"
+
+
+def is_dump(name):
+ return name.lower().endswith(dump_suffix)
+
+
+def get_reply_suffix(name):
+ for reply_suffix in reply_suffixes:
+ if name.lower().endswith(reply_suffix):
+ if reply_suffix == reply_suffixes[2]:
+ # FIXME workaround for l2_fib_table_entry
+ return 'entry'
+ else:
+ return reply_suffix
+
+# Mapping according to:
+# http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html
+#
+# Unsigned types are converted to signed java types that have the same size.
+# It is the API user responsibility to interpret them correctly.
+jni_2_java_type_mapping = {'u8': 'byte',
+ 'u8[]': 'byte[]',
+ 'i8': 'byte',
+ 'i8[]': 'byte[]',
+ 'u16': 'short',
+ 'u16[]': 'short[]',
+ 'i16': 'short',
+ 'i16[]': 'short[]',
+ 'u32': 'int',
+ 'u32[]': 'int[]',
+ 'i32': 'int',
+ 'i32[]': 'int[]',
+ 'u64': 'long',
+ 'u64[]': 'long[]',
+ 'i64': 'long',
+ 'i64[]': 'long[]',
+ 'f64': 'double',
+ 'f64[]': 'double[]'
+ }
+
+vpp_2_jni_type_mapping = {'u8': 'jbyte',
+ 'u8[]': 'jbyteArray',
+ 'i8': 'jbyte',
+ 'u8[]': 'jbyteArray',
+ 'u16': 'jshort',
+ 'u16[]': 'jshortArray',
+ 'i16': 'jshort',
+ 'i16[]': 'jshortArray',
+ 'u32': 'jint',
+ 'u32[]': 'jintArray',
+ 'i32': 'jint',
+ 'i32[]': 'jintArray',
+ 'u64': 'jlong',
+ 'u64[]': 'jlongArray',
+ 'i64': 'jlong',
+ 'i64[]': 'jlongArray',
+ 'f64': 'jdouble',
+ 'f64[]': 'jdoubleArray'
+ }
+
+# https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/types.html#type_signatures
+jni_2_signature_mapping = {'u8': 'B',
+ 'u8[]': '[B',
+ 'i8': 'B',
+ 'i8[]': '[B',
+ 'u16': 'S',
+ 'u16[]': '[S',
+ 'i16': 'S',
+ 'i16[]': '[S',
+ 'u32': 'I',
+ 'u32[]': '[I',
+ 'i32': 'I',
+ 'i32[]': '[I',
+ 'u64': 'J',
+ 'u64[]': '[J',
+ 'i64': 'J',
+ 'i64[]': '[J',
+ 'f64': 'D',
+ 'f64[]': '[D'
+ }
+
+# https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#Get_type_Field_routines
+jni_field_accessors = {'u8': 'ByteField',
+ 'u8[]': 'ObjectField',
+ 'i8': 'ByteField',
+ 'i8[]': 'ObjectField',
+ 'u16': 'ShortField',
+ 'u16[]': 'ObjectField',
+ 'i16': 'ShortField',
+ 'i16[]': 'ObjectField',
+ 'u32': 'IntField',
+ 'u32[]': 'ObjectField',
+ 'i32': 'IntField',
+ 'i32[]': 'ObjectField',
+ 'u64': 'LongField',
+ 'u64[]': 'ObjectField',
+ 'i64': 'LongField',
+ 'i64[]': 'ObjectField',
+ 'f64': 'DoubleField',
+ 'f64[]': 'ObjectField'
+ }
+
+
+# vpe.api calls that do not follow naming conventions and have to be handled exceptionally when finding reply -> request mapping
+# FIXME in vpe.api
+unconventional_naming_rep_req = {
+ }
+
+#
+# FIXME no convention in the naming of events (notifications) in vpe.api
+notifications_message_suffixes = ("event", "counters")
+
+# messages that must be ignored. These messages are INSUFFICIENTLY marked as disabled in vpe.api
+# FIXME
+ignored_messages = []
+
+
+def is_notification(name):
+ """ Returns true if the structure is a notification regardless of its no other use """
+ return is_just_notification(name)
+
+
+def is_just_notification(name):
+ """ Returns true if the structure is just a notification and has no other use """
+ return name.lower().endswith(notifications_message_suffixes)
+
+
+def is_ignored(param):
+ return param.lower() in ignored_messages
+
+
+def remove_reply_suffix(camel_case_name_with_suffix):
+ return remove_suffix(camel_case_name_with_suffix, get_reply_suffix(camel_case_name_with_suffix))
+
+
+def remove_suffix(camel_case_name_with_suffix, suffix):
+ suffix_length = len(suffix)
+ return camel_case_name_with_suffix[:-suffix_length] if suffix_length != 0 else camel_case_name_with_suffix
+
+
+def is_control_ping(camel_case_name_with_suffix):
+ return camel_case_name_with_suffix.lower().startswith("controlping");
+
+
+def api_message_to_javadoc(api_message):
+ """ Converts vpe.api message description to javadoc """
+ str = pprint.pformat(api_message, indent=4, width=120, depth=None)
+ return " * " + str.replace("\n", "\n * ")
+
+
+notification_dto_suffix = "Notification"
+
+
+def add_notification_suffix(camel_case_dto_name):
+ camel_case_dto_name += notification_dto_suffix
+ return camel_case_dto_name
+
+
+def is_array(java_type_as_string):
+ return java_type_as_string.endswith("[]")