jvpp: object model for jvpp generator (VPP-1184)
[vpp.git] / src / vpp-api / java / jvpp / gen / jvppgen / jvpp_c_gen.py
diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py
deleted file mode 100644 (file)
index b97a9f9..0000000
+++ /dev/null
@@ -1,389 +0,0 @@
-#!/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 util
-from string import Template
-
-import jni_gen
-
-
-def is_manually_generated(f_name):
-    return f_name in {'control_ping_reply'}
-
-
-class_reference_template = Template("""jclass ${ref_name}Class;
-""")
-
-find_class_invocation_template = Template("""
-    ${ref_name}Class = (jclass)(*env)->NewGlobalRef(env, (*env)->FindClass(env, "io/fd/vpp/jvpp/${plugin_name}/dto/${class_name}"));
-    if ((*env)->ExceptionCheck(env)) {
-        (*env)->ExceptionDescribe(env);
-        return JNI_ERR;
-    }""")
-
-find_class_template = Template("""
-    ${ref_name}Class = (jclass)(*env)->NewGlobalRef(env, (*env)->FindClass(env, "${class_name}"));
-    if ((*env)->ExceptionCheck(env)) {
-        (*env)->ExceptionDescribe(env);
-        return JNI_ERR;
-    }""")
-
-delete_class_invocation_template = Template("""
-    if (${ref_name}Class) {
-        (*env)->DeleteGlobalRef(env, ${ref_name}Class);
-    }""")
-
-class_cache_template = Template("""
-$class_references
-static int cache_class_references(JNIEnv* env) {
-    $find_class_invocations
-    return 0;
-}
-
-static void delete_class_references(JNIEnv* env) {
-    $delete_class_invocations
-}""")
-
-
-def generate_class_cache(func_list, plugin_name):
-    class_references = []
-    find_class_invocations = []
-    delete_class_invocations = []
-    for f in func_list:
-        c_name = f['name']
-        class_name = util.underscore_to_camelcase_upper(c_name)
-        ref_name = util.underscore_to_camelcase(c_name)
-
-        if util.is_control_ping(class_name):
-            continue
-
-        class_references.append(class_reference_template.substitute(
-            ref_name=ref_name))
-        find_class_invocations.append(find_class_invocation_template.substitute(
-            plugin_name=plugin_name,
-            ref_name=ref_name,
-            class_name=class_name))
-        delete_class_invocations.append(delete_class_invocation_template.substitute(ref_name=ref_name))
-
-    # add exception class to class cache
-    ref_name = 'callbackException'
-    class_name = 'io/fd/vpp/jvpp/VppCallbackException'
-    class_references.append(class_reference_template.substitute(
-            ref_name=ref_name))
-    find_class_invocations.append(find_class_template.substitute(
-            ref_name=ref_name,
-            class_name=class_name))
-    delete_class_invocations.append(delete_class_invocation_template.substitute(ref_name=ref_name))
-
-    return class_cache_template.substitute(
-        class_references="".join(class_references), find_class_invocations="".join(find_class_invocations),
-        delete_class_invocations="".join(delete_class_invocations))
-
-
-# TODO: cache method and field identifiers to achieve better performance
-# https://jira.fd.io/browse/HONEYCOMB-42
-request_class_template = Template("""
-    jclass requestClass = (*env)->FindClass(env, "io/fd/vpp/jvpp/${plugin_name}/dto/${java_name_upper}");""")
-
-request_field_identifier_template = Template("""
-    jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${object_name}Class, "${field_name}", "${jni_signature}");
-    ${jni_type} ${field_reference_name} = (*env)->Get${jni_getter}(env, ${object_name}, ${field_reference_name}FieldId);
-    """)
-
-jni_msg_size_template = Template(""" + ${array_length}*sizeof(${element_type})""")
-
-jni_impl_template = Template("""
-/**
- * JNI binding for sending ${c_name} message.
- * Generated based on $inputfile preparsed data:
-$api_data
- */
-JNIEXPORT jint JNICALL Java_io_fd_vpp_jvpp_${plugin_name}_JVpp${java_plugin_name}Impl_${field_name}0
-(JNIEnv * env, jclass clazz$args) {
-    ${plugin_name}_main_t *plugin_main = &${plugin_name}_main;
-    vl_api_${c_name}_t * mp;
-    u32 my_context_id = vppjni_get_context_id (&jvpp_main);
-    $request_class
-
-    $jni_identifiers
-
-    // create message:
-    mp = vl_msg_api_alloc(${msg_size});
-    memset (mp, 0, ${msg_size});
-    mp->_vl_msg_id = ntohs (get_message_id(env, "${c_name}_${crc}"));
-    mp->client_index = plugin_main->my_client_index;
-    mp->context = clib_host_to_net_u32 (my_context_id);
-
-    $msg_initialization
-
-    // send message:
-    if (CLIB_DEBUG > 1)
-        clib_warning ("Sending ${field_name} event message");
-    vl_msg_api_send_shmem (plugin_main->vl_input_queue, (u8 *)&mp);
-    if ((*env)->ExceptionCheck(env)) {
-        return JNI_ERR;
-    }
-    return my_context_id;
-}""")
-
-
-def generate_jni_impl(func_list, plugin_name, inputfile):
-    jni_impl = []
-    for f in func_list:
-        f_name = f['name']
-        camel_case_function_name = util.underscore_to_camelcase(f_name)
-        if is_manually_generated(f_name):
-            # Skip control ping managed by jvpp registry.
-            continue
-        if not (util.is_dump(f_name) or util.is_request(f_name, func_list)):
-            continue
-
-        # Generate jni bindings for sending dump and request messages.
-        arguments = ''
-        request_class = ''
-        jni_identifiers = ''
-        msg_initialization = ''
-        f_name_uppercase = f_name.upper()
-        msg_size = 'sizeof(*mp)'
-
-        if f['args']:
-            arguments = ', jobject request'
-            camel_case_function_name_upper = util.underscore_to_camelcase_upper(f_name)
-
-            request_class = request_class_template.substitute(
-                    java_name_upper=camel_case_function_name_upper,
-                    plugin_name=plugin_name)
-
-            for t in zip(f['types'], f['args'], f['lengths'], f['arg_types']):
-                field_name = util.underscore_to_camelcase(t[1])
-                is_variable_len_array = t[2][1]
-                if is_variable_len_array:
-                    msg_size += jni_msg_size_template.substitute(array_length=util.underscore_to_camelcase(t[2][0]),
-                                                                 element_type=t[3])
-                jni_identifiers += jni_gen.jni_request_identifiers_for_type(field_type=t[0],
-                                                                            field_reference_name=field_name,
-                                                                            field_name=field_name)
-                msg_initialization += jni_gen.jni_request_binding_for_type(field_type=t[0], c_name=t[1],
-                                                                           field_reference_name=field_name,
-                                                                           field_length=t[2][0],
-                                                                           is_variable_len_array=is_variable_len_array)
-
-        jni_impl.append(jni_impl_template.substitute(
-                inputfile=inputfile,
-                api_data=util.api_message_to_javadoc(f),
-                field_reference_name=camel_case_function_name,
-                field_name=camel_case_function_name,
-                c_name_uppercase=f_name_uppercase,
-                c_name=f_name,
-                crc=f['crc'],
-                plugin_name=plugin_name,
-                java_plugin_name=plugin_name.title(),
-                request_class=request_class,
-                jni_identifiers=jni_identifiers,
-                msg_size=msg_size,
-                msg_initialization=msg_initialization,
-                args=arguments))
-
-    return "\n".join(jni_impl)
-
-# code fragment for checking result of the operation before sending request reply
-callback_err_handler_template = Template("""
-    // for negative result don't send callback message but send error callback
-    if (mp->retval<0) {
-        call_on_error("${handler_name}", mp->context, mp->retval, plugin_main->callbackClass, plugin_main->callbackObject, callbackExceptionClass);
-        return;
-    }
-    if (mp->retval == VNET_API_ERROR_IN_PROGRESS) {
-        clib_warning("Result in progress");
-        return;
-    }
-""")
-
-msg_handler_template = Template("""
-/**
- * Handler for ${handler_name} message.
- * Generated based on $inputfile preparsed data:
-$api_data
- */
-static void vl_api_${handler_name}_t_handler (vl_api_${handler_name}_t * mp)
-{
-    ${plugin_name}_main_t *plugin_main = &${plugin_name}_main;
-    JNIEnv *env = jvpp_main.jenv;
-    jthrowable exc;
-    $err_handler
-
-    if (CLIB_DEBUG > 1)
-        clib_warning ("Received ${handler_name} event message");
-
-    jmethodID constructor = (*env)->GetMethodID(env, ${class_ref_name}Class, "<init>", "()V");
-
-    // User does not have to provide callbacks for all VPP messages.
-    // We are ignoring messages that are not supported by user.
-    (*env)->ExceptionClear(env); // just in case exception occurred in different place and was not properly cleared
-    jmethodID callbackMethod = (*env)->GetMethodID(env, plugin_main->callbackClass, "on${dto_name}", "(Lio/fd/vpp/jvpp/${plugin_name}/dto/${dto_name};)V");
-    exc = (*env)->ExceptionOccurred(env);
-    if (exc) {
-        clib_warning("Unable to extract on${dto_name} method reference from ${plugin_name} plugin's callbackClass. Ignoring message.\\n");
-        (*env)->ExceptionDescribe(env);
-        (*env)->ExceptionClear(env);
-        return;
-    }
-
-    jobject dto = (*env)->NewObject(env, ${class_ref_name}Class, constructor);
-    $dto_setters
-
-    (*env)->CallVoidMethod(env, plugin_main->callbackObject, callbackMethod, dto);
-    // free DTO as per http://stackoverflow.com/questions/1340938/memory-leak-when-calling-java-code-from-c-using-jni
-    (*env)->DeleteLocalRef(env, dto);
-}""")
-
-
-def generate_msg_handlers(func_list, plugin_name, inputfile):
-    handlers = []
-    for f in func_list:
-        handler_name = f['name']
-        dto_name = util.underscore_to_camelcase_upper(handler_name)
-        ref_name = util.underscore_to_camelcase(handler_name)
-
-        if is_manually_generated(handler_name):
-            # Skip control ping managed by jvpp registry.
-            continue
-        if util.is_dump(handler_name) or util.is_request(handler_name, func_list):
-            continue
-
-        # Generate msg handlers for all messages except for dumps and requests (handled by vpp, not client).
-        dto_setters = ''
-        err_handler = ''
-        # dto setters
-        for t in zip(f['types'], f['args'], f['lengths']):
-            c_name = t[1]
-            java_name = util.underscore_to_camelcase(c_name)
-            field_length = t[2][0]
-            is_variable_len_array = t[2][1]
-            length_field_type = None
-            if is_variable_len_array:
-                length_field_type = f['types'][f['args'].index(field_length)]
-            dto_setters += jni_gen.jni_reply_handler_for_type(handler_name=handler_name, ref_name=ref_name,
-                                                              field_type=t[0], c_name=t[1],
-                                                              field_reference_name=java_name,
-                                                              field_name=java_name, field_length=field_length,
-                                                              is_variable_len_array=is_variable_len_array,
-                                                              length_field_type=length_field_type)
-
-            # for retval don't generate setters and generate retval check
-            if util.is_retval_field(c_name):
-                err_handler = callback_err_handler_template.substitute(
-                    handler_name=handler_name
-                )
-                continue
-
-        handlers.append(msg_handler_template.substitute(
-            inputfile=inputfile,
-            api_data=util.api_message_to_javadoc(f),
-            handler_name=handler_name,
-            plugin_name=plugin_name,
-            dto_name=dto_name,
-            class_ref_name=ref_name,
-            dto_setters=dto_setters,
-            err_handler=err_handler))
-
-    return "\n".join(handlers)
-
-
-handler_registration_template = Template("""_(${name}_${crc}, ${name}) \\
-""")
-
-
-def generate_handler_registration(func_list):
-    handler_registration = ["#define foreach_api_reply_handler \\\n"]
-    for f in func_list:
-        name = f['name']
-        camelcase_name = util.underscore_to_camelcase(name)
-
-        if util.is_control_ping(camelcase_name):
-            # Skip control ping managed by registry.
-            continue
-        if util.is_dump(name) or util.is_request(name, func_list):
-            continue
-
-        # Generate msg handler registration for all messages except for dumps and requests.
-        handler_registration.append(handler_registration_template.substitute(
-            name=name,
-            crc=f['crc']))
-
-    return "".join(handler_registration)
-
-
-api_verification_template = Template("""_(${name}_${crc}) \\
-""")
-
-
-def generate_api_verification(func_list):
-    api_verification = ["#define foreach_supported_api_message \\\n"]
-    for f in func_list:
-        name = f['name']
-
-        api_verification.append(api_verification_template.substitute(
-            name=name,
-            crc=f['crc']))
-
-    return "".join(api_verification)
-
-
-jvpp_c_template = Template("""/**
- * This file contains JNI bindings for jvpp Java API.
- * It was generated by jvpp_c_gen.py based on $inputfile
- * (python representation of api file generated by vppapigen).
- */
-
-// JAVA class reference cache
-$class_cache
-
-// List of supported API messages used for verification
-$api_verification
-
-// JNI bindings
-$jni_implementations
-
-// Message handlers
-$msg_handlers
-
-// Registration of message handlers in vlib
-$handler_registration
-""")
-
-
-def generate_jvpp(func_list, plugin_name, inputfile, path, logger):
-    """ Generates jvpp C file """
-    logger.debug("Generating jvpp C for %s" % inputfile)
-
-    class_cache = generate_class_cache(func_list, plugin_name)
-    jni_impl = generate_jni_impl(func_list, plugin_name, inputfile)
-    msg_handlers = generate_msg_handlers(func_list, plugin_name, inputfile)
-    handler_registration = generate_handler_registration(func_list)
-    api_verification = generate_api_verification(func_list)
-
-    jvpp_c_file = open("%s/jvpp_%s_gen.h" % (path, plugin_name), 'w')
-    jvpp_c_file.write(jvpp_c_template.substitute(
-            inputfile=inputfile,
-            class_cache=class_cache,
-            api_verification=api_verification,
-            jni_implementations=jni_impl,
-            msg_handlers=msg_handlers,
-            handler_registration=handler_registration))
-    jvpp_c_file.flush()
-    jvpp_c_file.close()
-