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/jvpp/gen/jvppgen | |
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/jvpp/gen/jvppgen')
-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 |
5 files changed, 627 insertions, 309 deletions
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 = { |