diff options
author | Marek Gradzki <mgradzki@cisco.com> | 2016-09-29 13:22:35 +0200 |
---|---|---|
committer | Damjan Marion <dmarion.lists@gmail.com> | 2016-10-31 21:42:40 +0000 |
commit | 81c7dfc1bb48f1121fca4bf6f1e6e24efb0024de (patch) | |
tree | b0f831227ab2a7fd412d733c09f83649d8472692 /vpp-api/java | |
parent | c967a8239d98830e0b889bf9a621581a38a71dd8 (diff) |
VPP-120: add custom types support to jvpp
Generates java classes based on typeonly definitions
(hashcode, equals and toString methods are also included).
Adds JNI handling for request and reply messages
(also arrays of custom types).
Change-Id: I16f1cea17899704426aa083fad1cb800a8d115df
Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
Diffstat (limited to 'vpp-api/java')
-rw-r--r-- | vpp-api/java/Makefile.am | 8 | ||||
-rw-r--r-- | vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/LispAdjacencyTest.java | 124 | ||||
-rw-r--r-- | vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/Readme.txt | 1 | ||||
-rw-r--r-- | vpp-api/java/jvpp-core/jvpp_core.c | 4 | ||||
-rwxr-xr-x | vpp-api/java/jvpp/gen/jvpp_gen.py | 48 | ||||
-rw-r--r-- | vpp-api/java/jvpp/gen/jvppgen/dto_gen.py | 2 | ||||
-rw-r--r-- | vpp-api/java/jvpp/gen/jvppgen/jni_gen.py | 291 | ||||
-rw-r--r-- | vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py | 286 | ||||
-rw-r--r-- | vpp-api/java/jvpp/gen/jvppgen/types_gen.py | 227 | ||||
-rw-r--r-- | vpp-api/java/jvpp/gen/jvppgen/util.py | 130 |
10 files changed, 779 insertions, 342 deletions
diff --git a/vpp-api/java/Makefile.am b/vpp-api/java/Makefile.am index cdb83791d6d..390562b4d2a 100644 --- a/vpp-api/java/Makefile.am +++ b/vpp-api/java/Makefile.am @@ -92,11 +92,13 @@ jvpp-core/io_fd_vpp_jvpp_core_JVppCoreImpl.h: jvpp-registry/io_fd_vpp_jvpp_VppJN cp -rf @srcdir@/jvpp-core/* -t jvpp-core/ mkdir -p jvpp-core/target cd jvpp-core \ - && mkdir -p dto future callfacade callback notification \ + && mkdir -p types dto future callfacade callback notification \ && @srcdir@/jvpp/gen/jvpp_gen.py -i defs_vpp_papi.py --plugin_name core \ - && cp -rf dto future callfacade callback notification *.java -t $(packagedir_jvpp_core) \ - && rm -rf dto future callfacade callback notification *.java + && cp -rf types dto future callfacade callback notification *.java -t $(packagedir_jvpp_core) \ + && rm -rf types dto future callfacade callback notification *.java + $(JAVAC) -classpath jvpp-registry/target -d jvpp-core/target jvpp-core/$(packagedir_jvpp_core)/*.java \ + jvpp-core/$(packagedir_jvpp_core)/types/*.java \ jvpp-core/$(packagedir_jvpp_core)/dto/*.java \ jvpp-core/$(packagedir_jvpp_core)/callback/*.java \ jvpp-core/$(packagedir_jvpp_core)/notification/*.java \ diff --git a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/LispAdjacencyTest.java b/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/LispAdjacencyTest.java new file mode 100644 index 00000000000..d7f5039b152 --- /dev/null +++ b/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/LispAdjacencyTest.java @@ -0,0 +1,124 @@ +/* + * 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. + */ + +package io.fd.vpp.jvpp.core.test; + +import io.fd.vpp.jvpp.JVppRegistry; +import io.fd.vpp.jvpp.JVppRegistryImpl; +import io.fd.vpp.jvpp.core.JVppCoreImpl; +import io.fd.vpp.jvpp.core.dto.LispAddDelAdjacency; +import io.fd.vpp.jvpp.core.dto.LispAddDelLocalEid; +import io.fd.vpp.jvpp.core.dto.LispAddDelLocatorSet; +import io.fd.vpp.jvpp.core.dto.LispAddDelRemoteMapping; +import io.fd.vpp.jvpp.core.dto.LispAdjacenciesGet; +import io.fd.vpp.jvpp.core.dto.LispAdjacenciesGetReply; +import io.fd.vpp.jvpp.core.dto.LispEnableDisable; +import io.fd.vpp.jvpp.core.future.FutureJVppCoreFacade; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.ExecutionException; +import java.util.logging.Logger; + +/** + * Tests lisp adjacency creation and read (custom vpe.api type support showcase). + */ +public class LispAdjacencyTest { + + private static final Logger LOG = Logger.getLogger(LispAdjacencyTest.class.getName()); + + private static void enableLisp(final FutureJVppCoreFacade jvpp) throws ExecutionException, InterruptedException { + final LispEnableDisable request = new LispEnableDisable(); + request.isEn = 1; + jvpp.lispEnableDisable(request).toCompletableFuture().get(); + LOG.info("Lisp enabled successfully"); + } + + private static void addLocatorSet(final FutureJVppCoreFacade jvpp) throws ExecutionException, InterruptedException { + final LispAddDelLocatorSet request = new LispAddDelLocatorSet(); + request.isAdd = 1; + request.locatorSetName = "ls1".getBytes(StandardCharsets.UTF_8); + jvpp.lispAddDelLocatorSet(request).toCompletableFuture().get(); + LOG.info("Locator set created successfully:" + request.toString()); + } + + private static void addLocalEid(final FutureJVppCoreFacade jvpp) throws ExecutionException, InterruptedException { + final LispAddDelLocalEid request = new LispAddDelLocalEid(); + request.isAdd = 1; + request.locatorSetName = "ls1".getBytes(StandardCharsets.UTF_8); + request.eid = new byte[] {1, 2, 1, 10}; + request.eidType = 0; // ip4 + request.vni = 0; + request.prefixLen = 32; + jvpp.lispAddDelLocalEid(request).toCompletableFuture().get(); + LOG.info("Local EID created successfully:" + request.toString()); + } + + private static void addRemoteMapping(final FutureJVppCoreFacade jvpp) + throws ExecutionException, InterruptedException { + final LispAddDelRemoteMapping request = new LispAddDelRemoteMapping(); + request.isAdd = 1; + request.vni = 0; + request.eid = new byte[] {1, 2, 1, 20}; + request.eidLen = 32; + request.rlocNum = 1; + request.rlocs = new byte[] {1, 1, 1, 1, 2, 1, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + jvpp.lispAddDelRemoteMapping(request).toCompletableFuture().get(); + LOG.info("Remote mapping created successfully:" + request.toString()); + } + + private static void addAdjacency(final FutureJVppCoreFacade jvpp) throws ExecutionException, InterruptedException { + final LispAddDelAdjacency request = new LispAddDelAdjacency(); + request.isAdd = 1; + request.leid = new byte[] {1, 2, 1, 10}; + request.leidLen = 32; + request.reid = new byte[] {1, 2, 1, 20}; + request.reidLen = 32; + request.eidType = 0; // ip4 + request.vni = 0; + jvpp.lispAddDelAdjacency(request).toCompletableFuture().get(); + LOG.info("Lisp adjacency created successfully:" + request.toString()); + } + + private static void showAdjacencies(final FutureJVppCoreFacade jvpp) + throws ExecutionException, InterruptedException { + final LispAdjacenciesGetReply reply = + jvpp.lispAdjacenciesGet(new LispAdjacenciesGet()).toCompletableFuture().get(); + LOG.info("Lisp adjacency received successfully:" + reply.toString()); + } + + private static void testAdjacency(final FutureJVppCoreFacade jvpp) throws Exception { + enableLisp(jvpp); + addLocatorSet(jvpp); + addLocalEid(jvpp); + addRemoteMapping(jvpp); + addAdjacency(jvpp); + showAdjacencies(jvpp); + } + + private static void testFutureApi() throws Exception { + LOG.info("Create lisp adjacency test"); + try (final JVppRegistry registry = new JVppRegistryImpl("LispAdjacencyTest"); + final FutureJVppCoreFacade jvppFacade = new FutureJVppCoreFacade(registry, new JVppCoreImpl())) { + LOG.info("Successfully connected to VPP"); + + testAdjacency(jvppFacade); + LOG.info("Disconnecting..."); + } + } + + public static void main(String[] args) throws Exception { + testFutureApi(); + } +} diff --git a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/Readme.txt b/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/Readme.txt index 2c9c42439bc..c1b0c5aa2de 100644 --- a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/Readme.txt +++ b/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/Readme.txt @@ -14,3 +14,4 @@ CreateSubInterfaceTest - Tests sub-interface creation FutureApiNotificationTest - Tests interface notifications using Future based JVpp facade FutureApiTest - Execution of more complex calls using Future based JVpp facade L2AclTest - Tests L2 ACL creation +LispAdjacencyTest - Tests lisp adjacency creation and read (custom vpe.api type support showcase) diff --git a/vpp-api/java/jvpp-core/jvpp_core.c b/vpp-api/java/jvpp-core/jvpp_core.c index 8872ef5ffea..83c0bb2a8bf 100644 --- a/vpp-api/java/jvpp-core/jvpp_core.c +++ b/vpp-api/java/jvpp-core/jvpp_core.c @@ -71,8 +71,8 @@ JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_core_JVppCoreImpl_init0 vl_msg_api_set_handlers(VL_API_##N, #n, \ vl_api_##n##_t_handler, \ vl_noop_handler, \ - vl_api_##n##_t_endian, \ - vl_api_##n##_t_print, \ + vl_noop_handler, \ + vl_noop_handler, \ sizeof(vl_api_##n##_t), 1); foreach_api_reply_handler; #undef _ diff --git a/vpp-api/java/jvpp/gen/jvpp_gen.py b/vpp-api/java/jvpp/gen/jvpp_gen.py index 80bb4b9e93a..3be83824e9c 100755 --- a/vpp-api/java/jvpp/gen/jvpp_gen.py +++ b/vpp-api/java/jvpp/gen/jvpp_gen.py @@ -19,6 +19,7 @@ import importlib import sys import os +from jvppgen import types_gen from jvppgen import callback_gen from jvppgen import notification_gen from jvppgen import dto_gen @@ -37,7 +38,6 @@ from jvppgen import util # # where # defs_api_vpp_papi.py - vpe.api in python format (generated by vppapigen) -from jvppgen.util import vpp_2_jni_type_mapping parser = argparse.ArgumentParser(description='VPP Java API generator') parser.add_argument('-i', action="store", dest="inputfile") @@ -47,7 +47,7 @@ args = parser.parse_args() sys.path.append(".") -print "args.inputfile %s" % args.inputfile +print "Generating Java API for %s" % args.inputfile importdir = os.path.dirname(args.inputfile) print "importdir %s" % importdir inputfile = os.path.basename(args.inputfile) @@ -60,13 +60,6 @@ print "control_ping_class %s" % control_ping_class sys.path.append(importdir) cfg = importlib.import_module(inputfile, package=None) - -# FIXME: functions unsupported due to problems with vpe.api -def is_supported(f_name): - return f_name not in {'vnet_ip4_fib_counters', 'vnet_ip6_fib_counters', - 'lisp_adjacencies_get_reply', 'lisp_adjacencies_get'} - - def is_request_field(field_name): return field_name not in {'_vl_msg_id', 'client_index', 'context'} @@ -86,60 +79,52 @@ def get_args(t, filter): def get_types(t, filter): types_list = [] - c_types_list = [] lengths_list = [] for i in t: if not filter(i[1]): continue if len(i) is 3: # array type - types_list.append(vpp_2_jni_type_mapping[i[0]] + 'Array') - c_types_list.append(i[0] + '[]') + types_list.append(i[0] + '[]') lengths_list.append((i[2], False)) elif len(i) is 4: # variable length array type - types_list.append(vpp_2_jni_type_mapping[i[0]] + 'Array') - c_types_list.append(i[0] + '[]') + types_list.append(i[0] + '[]') lengths_list.append((i[3], True)) else: # primitive type - types_list.append(vpp_2_jni_type_mapping[i[0]]) - c_types_list.append(i[0]) + types_list.append(i[0]) lengths_list.append((0, False)) - return types_list, c_types_list, lengths_list + return types_list, lengths_list -def get_definitions(): +def get_definitions(defs): # Pass 1 func_list = [] func_name = {} - for a in cfg.messages: - if not is_supported(a[0]): - continue - + for a in defs: java_name = util.underscore_to_camelcase(a[0]) # For replies include all the arguments except message_id if util.is_reply(java_name): - types, c_types, lengths = get_types(a[1:], is_response_field) + types, lengths = get_types(a[1:], is_response_field) func_name[a[0]] = dict( [('name', a[0]), ('java_name', java_name), ('args', get_args(a[1:], is_response_field)), ('full_args', get_args(a[1:], lambda x: True)), - ('types', types), ('c_types', c_types), ('lengths', lengths)]) + ('types', types), ('lengths', lengths)]) # For requests skip message_id, client_id and context else: - types, c_types, lengths = get_types(a[1:], is_request_field) + types, lengths = get_types(a[1:], is_request_field) func_name[a[0]] = dict( [('name', a[0]), ('java_name', java_name), ('args', get_args(a[1:], is_request_field)), ('full_args', get_args(a[1:], lambda x: True)), - ('types', types), ('c_types', c_types), ('lengths', lengths)]) + ('types', types), ('lengths', lengths)]) # Indexed by name func_list.append(func_name[a[0]]) return func_list, func_name -func_list, func_name = get_definitions() - base_package = 'io.fd.vpp.jvpp' plugin_package = base_package + '.' + plugin_name +types_package = 'types' dto_package = 'dto' callback_package = 'callback' notification_package = 'notification' @@ -148,6 +133,11 @@ future_package = 'future' callback_facade_package = 'callfacade' control_ping_class_fqn = "%s.%s.%s" % (plugin_package, dto_package, control_ping_class) +types_list, types_name = get_definitions(cfg.types) + +types_gen.generate_types(types_list, plugin_package, types_package, inputfile) + +func_list, func_name = get_definitions(cfg.messages) dto_gen.generate_dtos(func_list, base_package, plugin_package, plugin_name.title(), dto_package, args.inputfile) jvpp_impl_gen.generate_jvpp(func_list, base_package, plugin_package, plugin_name, control_ping_class_fqn, dto_package, args.inputfile) callback_gen.generate_callbacks(func_list, base_package, plugin_package, plugin_name.title(), callback_package, dto_package, args.inputfile) @@ -155,3 +145,5 @@ notification_gen.generate_notification_registry(func_list, base_package, plugin_ jvpp_c_gen.generate_jvpp(func_list, plugin_name, args.inputfile) jvpp_future_facade_gen.generate_jvpp(func_list, base_package, plugin_package, plugin_name.title(), dto_package, callback_package, notification_package, future_package, args.inputfile) jvpp_callback_facade_gen.generate_jvpp(func_list, base_package, plugin_package, plugin_name.title(), dto_package, callback_package, notification_package, callback_facade_package, args.inputfile) + +print "Java API for %s generated successfully" % args.inputfile diff --git a/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py b/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py index 12354793bf7..a043c9459b0 100644 --- a/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py +++ b/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py @@ -280,7 +280,7 @@ def generate_dump_reply_dto(request_dto_name, base_package, plugin_package, dto_ 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 = 'jstring' + artificial_type = 'u8' # In case of already existing artificial reply dump DTO, just update it # Used for sub-dump dtos diff --git a/vpp-api/java/jvpp/gen/jvppgen/jni_gen.py b/vpp-api/java/jvpp/gen/jvppgen/jni_gen.py new file mode 100644 index 00000000000..4b03b31d163 --- /dev/null +++ b/vpp-api/java/jvpp/gen/jvppgen/jni_gen.py @@ -0,0 +1,291 @@ +#!/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}); +""") + +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}); + } +""") + +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}); + } +""") + +# 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}); + } +""") + +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(""" + jshort * ${field_reference_name}ArrayElements = (*env)->GetShortArrayElements(env, ${field_reference_name}, NULL); + if (${field_reference_name}) { + 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(""" + jint * ${field_reference_name}ArrayElements = (*env)->GetIntArrayElements(env, ${field_reference_name}, NULL); + if (${field_reference_name}) { + 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(""" + jlong * ${field_reference_name}ArrayElements = (*env)->GetLongArrayElements(env, ${field_reference_name}, NULL); + if (${field_reference_name}) { + 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_binding_for_type(field_type, c_name, field_reference_name, field_name, field_length, + is_variable_len_array, object_name="request"): + """ + 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_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 + """ + # 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 + msg_initialization = 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) + + # 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/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py b/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py index d63acd6965f..1a35a6c09c0 100644 --- a/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py +++ b/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py @@ -17,6 +17,9 @@ 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'} @@ -54,6 +57,7 @@ static void delete_class_references(JNIEnv* env) { $delete_class_invocations }""") + def generate_class_cache(func_list, plugin_name): class_references = [] find_class_invocations = [] @@ -105,94 +109,10 @@ 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 ${java_name}FieldId = (*env)->GetFieldID(env, requestClass, "${java_name}", "${jni_signature}"); - ${jni_type} ${java_name} = (*env)->Get${jni_getter}(env, request, ${java_name}FieldId); + 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); """) -u8_struct_setter_template = Template(""" - mp->${c_name} = ${java_name};""") - -u16_struct_setter_template = Template(""" - mp->${c_name} = clib_host_to_net_u16(${java_name});""") - -u32_struct_setter_template = Template(""" - mp->${c_name} = clib_host_to_net_u32(${java_name});""") - -i32_struct_setter_template = Template(""" - mp->${c_name} = clib_host_to_net_i32(${java_name});!""") - -u64_struct_setter_template = Template(""" - mp->${c_name} = clib_host_to_net_u64(${java_name});""") - -fixed_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 (${java_name}) { - jsize cnt = (*env)->GetArrayLength (env, ${java_name}); - ${field_length_check} - (*env)->GetByteArrayRegion(env, ${java_name}, 0, cnt, (jbyte *)mp->${c_name}); - } -""") - -u16_array_struct_setter_template = Template(""" - jshort * ${java_name}ArrayElements = (*env)->GetShortArrayElements(env, ${java_name}, NULL); - if (${java_name}) { - size_t _i; - jsize cnt = (*env)->GetArrayLength (env, ${java_name}); - ${field_length_check} - for (_i = 0; _i < cnt; _i++) { - mp->${c_name}[_i] = clib_host_to_net_u16(${java_name}ArrayElements[_i]); - } - } - (*env)->ReleaseShortArrayElements (env, ${java_name}, ${java_name}ArrayElements, 0); - """) - -u32_array_struct_setter_template = Template(""" - jint * ${java_name}ArrayElements = (*env)->GetIntArrayElements(env, ${java_name}, NULL); - if (${java_name}) { - size_t _i; - jsize cnt = (*env)->GetArrayLength (env, ${java_name}); - ${field_length_check} - for (_i = 0; _i < cnt; _i++) { - mp->${c_name}[_i] = clib_host_to_net_u32(${java_name}ArrayElements[_i]); - } - } - (*env)->ReleaseIntArrayElements (env, ${java_name}, ${java_name}ArrayElements, 0); - """) - -u64_array_struct_setter_template = Template(""" - jlong * ${java_name}ArrayElements = (*env)->GetLongArrayElements(env, ${java_name}, NULL); - if (${java_name}) { - size_t _i; - jsize cnt = (*env)->GetArrayLength (env, ${java_name}); - ${field_length_check} - for (_i = 0; _i < cnt; _i++) { - mp->${c_name}[_i] = clib_host_to_net_u64(${java_name}ArrayElements[_i]); - } - } - (*env)->ReleaseLongArrayElements (env, ${java_name}, ${java_name}ArrayElements, 0); - """) - -vl_api_ip4_fib_counter_t_array_struct_setter_template = Template(""" - // vl_api_ip4_fib_counter_t_array_field_setter_template FIXME""") - -vl_api_ip6_fib_counter_t_array_struct_setter_template = Template(""" - // vl_api_ip6_fib_counter_t_array_field_setter_template FIXME""") - -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, - 'vl_api_ip4_fib_counter_t[]': vl_api_ip4_fib_counter_t_array_struct_setter_template, - 'vl_api_ip6_fib_counter_t[]': vl_api_ip6_fib_counter_t_array_struct_setter_template - } jni_impl_template = Template(""" /** @@ -200,13 +120,12 @@ jni_impl_template = Template(""" * Generated based on $inputfile preparsed data: $api_data */ -JNIEXPORT jint JNICALL Java_io_fd_vpp_jvpp_${plugin_name}_JVpp${java_plugin_name}Impl_${java_name}0 +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 - $field_identifiers // create message: mp = vl_msg_api_alloc(sizeof(*mp)); @@ -215,7 +134,8 @@ JNIEXPORT jint JNICALL Java_io_fd_vpp_jvpp_${plugin_name}_JVpp${java_plugin_name mp->client_index = plugin_main->my_client_index; mp->context = clib_host_to_net_u32 (my_context_id); - $struct_setters + $msg_initialization + // send message: vl_msg_api_send_shmem (plugin_main->vl_input_queue, (u8 *)&mp); if ((*env)->ExceptionCheck(env)) { @@ -235,8 +155,7 @@ def generate_jni_impl(func_list, plugin_name, inputfile): arguments = '' request_class = '' - field_identifiers = '' - struct_setters = '' + msg_initialization = '' f_name_uppercase = f_name.upper() if f['args']: @@ -247,142 +166,29 @@ def generate_jni_impl(func_list, plugin_name, inputfile): java_name_upper=camel_case_function_name_upper, plugin_name=plugin_name) - # field identifiers - for t in zip(f['types'], f['args']): - jni_type = t[0] - java_field_name = util.underscore_to_camelcase(t[1]) - jni_signature = util.jni_2_signature_mapping[jni_type] - jni_getter = util.jni_field_accessors[jni_type] - field_identifiers += request_field_identifier_template.substitute( - jni_type=jni_type, - java_name=java_field_name, - jni_signature=jni_signature, - jni_getter=jni_getter) - - # field setters - for t in zip(f['c_types'], f['args'], f['lengths']): - c_type = t[0] - c_name = t[1] - field_length = t[2][0] - field_length_check = "" - - # check if we are processing variable length array: - if t[2][1]: - field_length = util.underscore_to_camelcase(t[2][0]) - - # enforce max length if array has fixed length or uses variable length syntax - if str(t[2][0]) != "0": - field_length_check = fixed_array_length_enforcement_template.substitute(field_length=field_length) - - java_field_name = util.underscore_to_camelcase(c_name) - - struct_setter_template = struct_setter_templates[c_type] - - struct_setters += struct_setter_template.substitute( - c_name=c_name, - java_name=java_field_name, - field_length_check=field_length_check) + for t in zip(f['types'], f['args'], f['lengths']): + field_name = util.underscore_to_camelcase(t[1]) + msg_initialization += jni_gen.jni_request_binding_for_type(field_type=t[0], c_name=t[1], + field_reference_name=field_name, + field_name=field_name, + field_length=t[2][0], + is_variable_len_array=t[2][1]) jni_impl.append(jni_impl_template.substitute( inputfile=inputfile, api_data=util.api_message_to_javadoc(f), - java_name=camel_case_function_name, + field_reference_name=camel_case_function_name, + field_name=camel_case_function_name, c_name_uppercase=f_name_uppercase, c_name=f_name, plugin_name=plugin_name, java_plugin_name=plugin_name.title(), request_class=request_class, - field_identifiers=field_identifiers, - struct_setters=struct_setters, + msg_initialization=msg_initialization, args=arguments)) return "\n".join(jni_impl) - -dto_field_id_template = Template(""" - jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");""") - -default_dto_field_setter_template = Template(""" - (*env)->Set${jni_setter}(env, dto, ${java_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, dto, ${java_name}FieldId, clib_net_to_host_u16(mp->${c_name})); -""") - -u32_dto_field_setter_template = Template(""" - (*env)->Set${jni_setter}(env, dto, ${java_name}FieldId, clib_net_to_host_u32(mp->${c_name})); -""") - -u64_dto_field_setter_template = Template(""" - (*env)->Set${jni_setter}(env, dto, ${java_name}FieldId, clib_net_to_host_u64(mp->${c_name})); -""") - -u8_array_dto_field_setter_template = Template(""" - jbyteArray ${java_name} = (*env)->NewByteArray(env, ${field_length}); - (*env)->SetByteArrayRegion(env, ${java_name}, 0, ${field_length}, (const jbyte*)mp->${c_name}); - (*env)->SetObjectField(env, dto, ${java_name}FieldId, ${java_name}); -""") - -u16_array_dto_field_setter_template = Template(""" - { - jshortArray ${java_name} = (*env)->NewShortArray(env, ${field_length}); - jshort * ${java_name}ArrayElements = (*env)->GetShortArrayElements(env, ${java_name}, NULL); - unsigned int _i; - for (_i = 0; _i < ${field_length}; _i++) { - ${java_name}ArrayElements[_i] = clib_net_to_host_u16(mp->${c_name}[_i]); - } - - (*env)->ReleaseShortArrayElements(env, ${java_name}, ${java_name}ArrayElements, 0); - (*env)->SetObjectField(env, dto, ${java_name}FieldId, ${java_name}); - } -""") - -u32_array_dto_field_setter_template = Template(""" - { - jintArray ${java_name} = (*env)->NewIntArray(env, ${field_length}); - jint * ${java_name}ArrayElements = (*env)->GetIntArrayElements(env, ${java_name}, NULL); - unsigned int _i; - for (_i = 0; _i < ${field_length}; _i++) { - ${java_name}ArrayElements[_i] = clib_net_to_host_u32(mp->${c_name}[_i]); - } - - (*env)->ReleaseIntArrayElements(env, ${java_name}, ${java_name}ArrayElements, 0); - (*env)->SetObjectField(env, dto, ${java_name}FieldId, ${java_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 ${java_name} = (*env)->NewLongArray(env, ${field_length}); - jlong * ${java_name}ArrayElements = (*env)->GetLongArrayElements(env, ${java_name}, NULL); - unsigned int _i; - for (_i = 0; _i < ${field_length}; _i++) { - ${java_name}ArrayElements[_i] = clib_net_to_host_u64(mp->${c_name}[_i]); - } - - (*env)->ReleaseLongArrayElements(env, ${java_name}, ${java_name}ArrayElements, 0); - (*env)->SetObjectField(env, dto, ${java_name}FieldId, ${java_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 - } - # 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 @@ -418,6 +224,7 @@ static void vl_api_${handler_name}_t_handler (vl_api_${handler_name}_t * mp) (*env)->CallVoidMethod(env, plugin_main->callbackObject, callbackMethod, dto); }""") + def generate_msg_handlers(func_list, plugin_name, inputfile): handlers = [] for f in func_list: @@ -438,25 +245,20 @@ def generate_msg_handlers(func_list, plugin_name, inputfile): dto_setters = '' err_handler = '' # dto setters - for t in zip(f['c_types'], f['types'], f['args'], f['lengths']): - c_type = t[0] - jni_type = t[1] - c_name = t[2] - field_length = t[3][0] - - if jni_type.endswith('Array') and field_length == '0': - raise Exception('Variable array \'%s\' defined in message \'%s\' ' - 'should have defined length (e.g. \'%s[%s_length]\'' - % (c_name, handler_name, c_name, c_name)) - - # check if we are processing variable length array - if t[3][1]: - length_var_name = t[3][0] - length_field_type = f['c_types'][f['args'].index(length_var_name)] - 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 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): @@ -465,24 +267,6 @@ def generate_msg_handlers(func_list, plugin_name, inputfile): ) continue - java_field_name = util.underscore_to_camelcase(c_name) - jni_signature = util.jni_2_signature_mapping[jni_type] - jni_setter = util.jni_field_accessors[jni_type] - - dto_setters += dto_field_id_template.substitute( - java_name=java_field_name, - class_ref_name=ref_name, - jni_signature=jni_signature) - - dto_setter_template = dto_field_setter_templates[c_type] - - dto_setters += dto_setter_template.substitute( - java_name=java_field_name, - jni_signature=jni_signature, - c_name=c_name, - jni_setter=jni_setter, - field_length=field_length) - handlers.append(msg_handler_template.substitute( inputfile=inputfile, api_data=util.api_message_to_javadoc(f), diff --git a/vpp-api/java/jvpp/gen/jvppgen/types_gen.py b/vpp-api/java/jvpp/gen/jvppgen/types_gen.py new file mode 100644 index 00000000000..d12fb3d7850 --- /dev/null +++ b/vpp-api/java/jvpp/gen/jvppgen/types_gen.py @@ -0,0 +1,227 @@ +#!/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}); + } +""") + +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); + unsigned int _i; + for (_i = 0; _i < ${field_length}; _i++) { + jmethodID ${field_reference_name}Constructor = (*env)->GetMethodID(env, ${field_reference_name}Class, "<init>", "()V"); + 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)->SetObjectField(env, dto, ${field_reference_name}FieldId, ${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_binding_for_type(field_type=t[0], c_name=c_name_prefix + t[1], + field_reference_name=field_reference_name, + field_name=field_name, + field_length=t[2][0], + is_variable_len_array=t[2][1], + object_name=object_name) + 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): + raise Exception("%s folder is missing" % 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/vpp-api/java/jvpp/gen/jvppgen/util.py b/vpp-api/java/jvpp/gen/jvppgen/util.py index 712f17866c3..4d3fca342dd 100644 --- a/vpp-api/java/jvpp/gen/jvppgen/util.py +++ b/vpp-api/java/jvpp/gen/jvppgen/util.py @@ -65,78 +65,94 @@ def get_reply_suffix(name): else: return reply_suffix -# http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html -jni_2_java_type_mapping = {'jbyte': 'byte', - 'jbyteArray': 'byte[]', - 'jchar': 'char', - 'jcharArray': 'char[]', - 'jshort': 'short', - 'jshortArray': 'short[]', - 'jint': 'int', - 'jintArray': 'int[]', - 'jlong': 'long', - 'jlongArray': 'long[]', - 'jdouble': 'double', - 'jdoubleArray': 'double[]', - 'jfloat': 'float', - 'jfloatArray': 'float[]', - 'void': 'void', - 'jstring': 'java.lang.String', - 'jobject': 'java.lang.Object', - 'jobjectArray': 'java.lang.Object[]' - } - -# https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/types.html#type_signatures -jni_2_signature_mapping = {'jbyte': 'B', - 'jbyteArray': '[B', - 'jchar': 'C', - 'jcharArray': '[C', - 'jshort': 'S', - 'jshortArray': '[S', - 'jint': 'I', - 'jintArray': '[I', - 'jlong': 'J', - 'jlongArray': '[J', - 'jdouble': 'D', - 'jdoubleArray': '[D', - 'jfloat': 'F', - 'jfloatArray': '[F' - } - -# https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#Get_type_Field_routines -jni_field_accessors = { - 'jbyte': 'ByteField', - 'jbyteArray': 'ObjectField', - 'jchar': 'CharField', - 'jcharArray': 'ObjectField', - 'jshort': 'ShortField', - 'jshortArray': 'ObjectField', - 'jint': 'IntField', - 'jintArray': 'ObjectField', - 'jlong': 'LongField', - 'jlongArray': 'ObjectField', - 'jdouble': 'DoubleField', - 'jdoubleArray': 'ObjectField', - 'jfloat': 'FloatField', - 'jfloatArray': 'ObjectField' -} - # 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[]': 'longArray', 'i64': 'jlong', - 'f64': 'jdouble' + 'u64[]': 'longArray', + '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 = { |