From 42bb61fd162b3dd469c9d98a9dc6d3e2b2eaffce Mon Sep 17 00:00:00 2001 From: Tibor Sirovatka Date: Wed, 18 May 2016 14:54:50 +0200 Subject: HONEYCOMB-67 Introduce exception handling into JVPP Send calls throws VppInvocationException on failure Failed requests (negative retval) reported over onError callback interface method Removed retval attributes from dto/xxxReply.java calls Change-Id: Ibd4e90c320d080e02d75b4bd056a7b11c8e37aa7 Signed-off-by: Tibor Sirovatka --- vpp-api/java/jvpp/gen/dto_gen.py | 8 +++- vpp-api/java/jvpp/gen/jvpp_c_gen.py | 56 ++++++++++++++++++++--- vpp-api/java/jvpp/gen/jvpp_callback_facade_gen.py | 30 ++++++++++-- vpp-api/java/jvpp/gen/jvpp_future_facade_gen.py | 31 ++++++++----- vpp-api/java/jvpp/gen/jvpp_impl_gen.py | 32 ++++++++----- vpp-api/java/jvpp/gen/util.py | 3 ++ 6 files changed, 122 insertions(+), 38 deletions(-) (limited to 'vpp-api/java/jvpp/gen') diff --git a/vpp-api/java/jvpp/gen/dto_gen.py b/vpp-api/java/jvpp/gen/dto_gen.py index 378d279c6d0..05859dbe83a 100644 --- a/vpp-api/java/jvpp/gen/dto_gen.py +++ b/vpp-api/java/jvpp/gen/dto_gen.py @@ -36,7 +36,7 @@ $methods field_template = Template(""" public $type $name;\n""") send_template = Template(""" @Override - public int send(final $base_package.JVpp jvpp) { + public int send(final $base_package.JVpp jvpp) throws org.openvpp.jvpp.VppInvocationException { return jvpp.$method_name($args); }\n""") @@ -58,8 +58,12 @@ def generate_dtos(func_list, base_package, dto_package, inputfile): fields = "" for t in zip(func['types'], func['args']): + # for retval don't generate dto field in Reply + field_name = util.underscore_to_camelcase(t[1]) + if util.is_reply(camel_case_dto_name) and util.is_retval_field(field_name): + continue fields += field_template.substitute(type=util.jni_2_java_type_mapping[t[0]], - name=util.underscore_to_camelcase(t[1])) + name=field_name) methods = "" base_type = "" if util.is_reply(camel_case_dto_name): diff --git a/vpp-api/java/jvpp/gen/jvpp_c_gen.py b/vpp-api/java/jvpp/gen/jvpp_c_gen.py index a92dd69c853..082fd5d73ae 100644 --- a/vpp-api/java/jvpp/gen/jvpp_c_gen.py +++ b/vpp-api/java/jvpp/gen/jvpp_c_gen.py @@ -31,6 +31,13 @@ find_class_invocation_template = Template(""" 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; + }""") + class_cache_template = Template(""" $class_references static int cache_class_references(JNIEnv* env) { @@ -57,6 +64,14 @@ def generate_class_cache(func_list): ref_name=ref_name, class_name=class_name)) + # add exception class to class cache + ref_name = 'callbackException' + class_name = 'org/openvpp/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)) return class_cache_template.substitute( class_references="".join(class_references), find_class_invocations="".join(find_class_invocations)) @@ -147,6 +162,9 @@ JNIEXPORT jint JNICALL Java_org_openvpp_jvpp_JVppImpl_${java_name}0 mp->context = clib_host_to_net_u32 (my_context_id); $struct_setters S; + if ((*env)->ExceptionCheck(env)) { + return JNI_ERR; + } return my_context_id; }""") @@ -273,6 +291,19 @@ dto_field_setter_templates = {'u8': default_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 + if (mp->retval<0) { + CallOnError("${handler_name}",mp->context,mp->retval); + return; + } + if (mp->retval == VNET_API_ERROR_IN_PROGRESS) { + clib_warning("Result in progress"); + return; + } +""") + msg_handler_template = Template(""" /** * Handler for ${handler_name} vpe.api message. @@ -283,6 +314,7 @@ static void vl_api_${handler_name}_t_handler (vl_api_${handler_name}_t * mp) { vppjni_main_t * jm = &vppjni_main; JNIEnv *env = jm->jenv; + $err_handler jmethodID constructor = (*env)->GetMethodID(env, ${class_ref_name}Class, "", "()V"); jmethodID callbackMethod = (*env)->GetMethodID(env, jm->callbackClass, "on${dto_name}", "(Lorg/openvpp/jvpp/dto/${dto_name};)V"); @@ -304,6 +336,7 @@ def generate_msg_handlers(func_list, inputfile): continue dto_setters = '' + err_handler = '' # dto setters for t in zip(f['c_types'], f['types'], f['args'], f['lengths']): c_type = t[0] @@ -311,6 +344,13 @@ def generate_msg_handlers(func_list, inputfile): c_name = t[2] field_length = t[3] + # 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 + 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] @@ -330,12 +370,13 @@ def generate_msg_handlers(func_list, inputfile): field_length=field_length) handlers.append(msg_handler_template.substitute( - inputfile=inputfile, - api_data=util.api_message_to_javadoc(f), - handler_name=handler_name, - dto_name=dto_name, - class_ref_name=ref_name, - dto_setters=dto_setters)) + inputfile=inputfile, + api_data=util.api_message_to_javadoc(f), + handler_name=handler_name, + dto_name=dto_name, + class_ref_name=ref_name, + dto_setters=dto_setters, + err_handler=err_handler)) return "\n".join(handlers) @@ -367,6 +408,8 @@ jvpp_c_template = Template("""/** * (python representation of vpe.api generated by vppapigen). */ +void CallOnError(const char* call, int context, int retval); + // JAVA class reference cache $class_cache @@ -399,4 +442,3 @@ def generate_jvpp(func_list, inputfile): jvpp_c_file.flush() jvpp_c_file.close() - diff --git a/vpp-api/java/jvpp/gen/jvpp_callback_facade_gen.py b/vpp-api/java/jvpp/gen/jvpp_callback_facade_gen.py index e8de3fc10c1..acf29eb85b8 100644 --- a/vpp-api/java/jvpp/gen/jvpp_callback_facade_gen.py +++ b/vpp-api/java/jvpp/gen/jvpp_callback_facade_gen.py @@ -77,16 +77,17 @@ $methods """) method_template = Template( - """ void $name($base_package.$dto_package.$request request, $base_package.$callback_package.$callback callback);""") -method_impl_template = Template(""" public final void $name($base_package.$dto_package.$request request, $base_package.$callback_package.$callback callback) { + """ void $name($base_package.$dto_package.$request request, $base_package.$callback_package.$callback callback) throws org.openvpp.jvpp.VppInvocationException;""") + +method_impl_template = Template(""" public final void $name($base_package.$dto_package.$request request, $base_package.$callback_package.$callback callback) throws org.openvpp.jvpp.VppInvocationException { synchronized (callbacks) { callbacks.put(jvpp.$name(request), callback); } } """) -no_arg_method_template = Template(""" void $name($base_package.$callback_package.$callback callback);""") -no_arg_method_impl_template = Template(""" public final void $name($base_package.$callback_package.$callback callback) { +no_arg_method_template = Template(""" void $name($base_package.$callback_package.$callback callback) throws org.openvpp.jvpp.VppInvocationException;""") +no_arg_method_impl_template = Template(""" public final void $name($base_package.$callback_package.$callback callback) throws org.openvpp.jvpp.VppInvocationException { synchronized (callbacks) { callbacks.put(jvpp.$name(), callback); } @@ -172,18 +173,37 @@ jvpp_facade_callback_template = Template(""" package $base_package.$callback_facade_package; /** - *

JVppGlobalCallback implementation for Java Callback API. + *

Implementation of JVppGlobalCallback interface for Java Callback API. *
It was generated by jvpp_callback_facade_gen.py based on $inputfile *
(python representation of vpe.api generated by vppapigen). */ public final class CallbackJVppFacadeCallback implements $base_package.$callback_package.JVppGlobalCallback { private final java.util.Map requests; + private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(CallbackJVppFacadeCallback.class.getName()); public CallbackJVppFacadeCallback(final java.util.Map requestMap) { this.requests = requestMap; } + @Override + public void onError(org.openvpp.jvpp.VppCallbackException reply) { + + $base_package.$callback_package.JVppCallback failedCall; + synchronized(requests) { + failedCall = requests.remove(reply.getCtxId()); + } + + if(failedCall != null) { + try { + failedCall.onError(reply); + } catch(RuntimeException ex) { + ex.addSuppressed(reply); + LOG.log(java.util.logging.Level.WARNING, String.format("Callback: %s failed while handling exception: %s", failedCall, reply), ex); + } + } + } + $methods } """) diff --git a/vpp-api/java/jvpp/gen/jvpp_future_facade_gen.py b/vpp-api/java/jvpp/gen/jvpp_future_facade_gen.py index 5574f120712..7a5a166733c 100644 --- a/vpp-api/java/jvpp/gen/jvpp_future_facade_gen.py +++ b/vpp-api/java/jvpp/gen/jvpp_future_facade_gen.py @@ -35,6 +35,23 @@ public final class FutureJVppFacadeCallback implements $base_package.$callback_p this.requests = requestMap; } + @Override + public void onError(org.openvpp.jvpp.VppCallbackException reply) { + final java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply> completableFuture; + + synchronized(requests) { + completableFuture = (java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply>) requests.get(reply.getCtxId()); + } + + if(completableFuture != null) { + completableFuture.completeExceptionally(reply); + + synchronized(requests) { + requests.remove(reply.getCtxId()); + } + } + } + $methods } """) @@ -50,12 +67,7 @@ jvpp_facade_callback_method_template = Template(""" } if(completableFuture != null) { - if(reply.retval < 0) { - completableFuture.completeExceptionally(new Exception("Invocation of " + $base_package.$dto_package.$callback_dto.class - + " failed with value " + reply.retval)); - } else { - completableFuture.complete(reply); - } + completableFuture.complete(reply); synchronized(requests) { requests.remove(reply.context); @@ -84,12 +96,7 @@ jvpp_facade_control_ping_method_template = Template(""" requests.remove((($base_package.$future_package.FutureJVppFacade.CompletableDumpFuture) completableFuture).getContextId()); } } else { - if(reply.retval < 0) { - completableFuture.completeExceptionally(new Exception("Invocation of " + $base_package.$dto_package.$callback_dto.class - + " failed with value " + reply.retval)); - } else { - completableFuture.complete(reply); - } + completableFuture.complete(reply); } synchronized(requests) { diff --git a/vpp-api/java/jvpp/gen/jvpp_impl_gen.py b/vpp-api/java/jvpp/gen/jvpp_impl_gen.py index 4e408c364b1..dfec6a743de 100644 --- a/vpp-api/java/jvpp/gen/jvpp_impl_gen.py +++ b/vpp-api/java/jvpp/gen/jvpp_impl_gen.py @@ -39,8 +39,10 @@ public interface JVpp extends java.lang.AutoCloseable { /** * Generic dispatch method for sending requests to VPP + * + * @throws org.openvpp.jvpp.VppInvocationException if send request had failed */ - int send($base_package.$dto_package.JVppRequest request); + int send($base_package.$dto_package.JVppRequest request) throws org.openvpp.jvpp.VppInvocationException; @Override void close(); @@ -76,7 +78,7 @@ public final class JVppImpl implements $base_package.JVpp { } @Override - public int send($base_package.$dto_package.JVppRequest request) { + public int send($base_package.$dto_package.JVppRequest request) throws org.openvpp.jvpp.VppInvocationException { return request.send(this); } @@ -84,23 +86,29 @@ $methods } """) -method_template = Template(""" int $name($base_package.$dto_package.$request request);""") +method_template = Template(""" int $name($base_package.$dto_package.$request request) throws org.openvpp.jvpp.VppInvocationException;""") method_native_template = Template( """ private static native int ${name}0($base_package.$dto_package.$request request);""") -method_impl_template = Template(""" public final int $name($base_package.$dto_package.$request request) { - if(request == null) { - throw new java.lang.NullPointerException("Null request object"); - } +method_impl_template = Template(""" public final int $name($base_package.$dto_package.$request request) throws org.openvpp.jvpp.VppInvocationException { + java.util.Objects.requireNonNull(request,"Null request object"); connection.checkActive(); - return ${name}0(request); + int result=${name}0(request); + if(result<0){ + throw new org.openvpp.jvpp.VppInvocationException("${name}",result); + } + return result; } """) -no_arg_method_template = Template(""" int $name();""") -no_arg_method_native_template = Template(""" private static native int ${name}0();""") -no_arg_method_impl_template = Template(""" public final int $name() { +no_arg_method_template = Template(""" int $name() throws org.openvpp.jvpp.VppInvocationException;""") +no_arg_method_native_template = Template(""" private static native int ${name}0() throws org.openvpp.jvpp.VppInvocationException;""") +no_arg_method_impl_template = Template(""" public final int $name() throws org.openvpp.jvpp.VppInvocationException { connection.checkActive(); - return ${name}0(); + int result=${name}0(); + if(result<0){ + throw new org.openvpp.jvpp.VppInvocationException("${name}",result); + } + return result; } """) diff --git a/vpp-api/java/jvpp/gen/util.py b/vpp-api/java/jvpp/gen/util.py index f951bf828d1..072c9d592f2 100644 --- a/vpp-api/java/jvpp/gen/util.py +++ b/vpp-api/java/jvpp/gen/util.py @@ -45,6 +45,9 @@ def is_reply(name): def is_details(name): return name.lower().endswith(reply_suffixes[1]) or name.lower().endswith(reply_suffixes[2]) +def is_retval_field(name): + return name == 'retval' + dump_suffix = "dump" -- cgit 1.2.3-korg