HONEYCOMB-67 Introduce exception handling into JVPP 84/1184/18
authorTibor Sirovatka <tsirovat@cisco.com>
Wed, 18 May 2016 12:54:50 +0000 (14:54 +0200)
committerDave Wallace <dwallacelf@gmail.com>
Thu, 9 Jun 2016 02:22:34 +0000 (02:22 +0000)
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 <tsirovat@cisco.com>
23 files changed:
vpp-api/java/japi/vppjni.c
vpp-api/java/jvpp/gen/dto_gen.py
vpp-api/java/jvpp/gen/jvpp_c_gen.py
vpp-api/java/jvpp/gen/jvpp_callback_facade_gen.py
vpp-api/java/jvpp/gen/jvpp_future_facade_gen.py
vpp-api/java/jvpp/gen/jvpp_impl_gen.py
vpp-api/java/jvpp/gen/util.py
vpp-api/java/jvpp/jvpp.c
vpp-api/java/jvpp/org/openvpp/jvpp/VppBaseCallException.java [new file with mode: 0644]
vpp-api/java/jvpp/org/openvpp/jvpp/VppCallbackException.java [new file with mode: 0644]
vpp-api/java/jvpp/org/openvpp/jvpp/VppInvocationException.java [new file with mode: 0644]
vpp-api/java/jvpp/org/openvpp/jvpp/callback/JVppCallback.java
vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java
vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvoker.java
vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvokerFacade.java
vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackApiTest.java
vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackJVppFacadeTest.java
vpp-api/java/jvpp/org/openvpp/jvpp/test/ControlPingTest.java
vpp-api/java/jvpp/org/openvpp/jvpp/test/CreateSubInterfaceTest.java
vpp-api/java/jvpp/org/openvpp/jvpp/test/FutureApiTest.java
vpp-api/java/jvpp/org/openvpp/jvpp/test/L2AclTest.java
vpp-api/java/jvpp/org/openvpp/jvpp/test/OnErrorCallbackTest.java [new file with mode: 0644]
vpp-api/java/jvpp/org/openvpp/jvpp/test/Readme.txt

index 5645263..f1b8eda 100644 (file)
@@ -41,7 +41,9 @@
 #include <api/vpe_all_api_h.h>
 #undef vl_printfun
 
+#ifndef VPPJNI_DEBUG
 #define VPPJNI_DEBUG 0
+#endif
 
 #if VPPJNI_DEBUG == 1
   #define DEBUG_LOG(...) clib_warning(__VA_ARGS__)
@@ -1683,7 +1685,9 @@ out:
     jm->result_ready = 1;
 }
 
+#ifndef VPPJNI_DEBUG_COUNTERS
 #define VPPJNI_DEBUG_COUNTERS 0
+#endif
 
 static void vl_api_vnet_interface_counters_t_handler
 (vl_api_vnet_interface_counters_t *mp)
index 378d279..05859db 100644 (file)
@@ -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):
index a92dd69..082fd5d 100644 (file)
@@ -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, "<init>", "()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()
 
-
index e8de3fc..acf29eb 100644 (file)
@@ -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;
 
 /**
- * <p>JVppGlobalCallback implementation for Java Callback API.
+ * <p>Implementation of JVppGlobalCallback interface for Java Callback API.
  * <br>It was generated by jvpp_callback_facade_gen.py based on $inputfile
  * <br>(python representation of vpe.api generated by vppapigen).
  */
 public final class CallbackJVppFacadeCallback implements $base_package.$callback_package.JVppGlobalCallback {
 
     private final java.util.Map<Integer, $base_package.$callback_package.JVppCallback> requests;
+    private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(CallbackJVppFacadeCallback.class.getName());
 
     public CallbackJVppFacadeCallback(final java.util.Map<Integer, $base_package.$callback_package.JVppCallback> 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
 }
 """)
index 5574f12..7a5a166 100644 (file)
@@ -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) {
index 4e408c3..dfec6a7 100644 (file)
@@ -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;
     }
 """)
 
index f951bf8..072c9d5 100644 (file)
@@ -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"
 
 
index 56c43c9..00c50f9 100644 (file)
@@ -39,7 +39,9 @@
 #include <api/vpe_all_api_h.h>
 #undef vl_printfun
 
+#ifndef VPPJNI_DEBUG
 #define VPPJNI_DEBUG 0
+#endif
 
 #if VPPJNI_DEBUG == 1
   #define DEBUG_LOG(...) clib_warning(__VA_ARGS__)
@@ -160,6 +162,44 @@ JNIEXPORT void JNICALL Java_org_openvpp_jvpp_VppJNIConnection_clientDisconnect
     vl_client_disconnect_from_vlib();
 }
 
+/**
+* Send error reply to the requestor
+* const char* call  pointer to the request name
+* int context       call context identifier
+* int retval        result of the operation
+*/
+void CallOnError(const char* call, int context, int retval)
+{
+    DEBUG_LOG("\nCallOnError : callback=%s,retval=%d,context=%d\n",call,clib_net_to_host_u32(retval), clib_net_to_host_u32(context));
+    vppjni_main_t * jm = &vppjni_main;
+    JNIEnv *env = jm->jenv;
+    if (!env) printf( "CallOnError : env is null!\n");
+    if (!jm->callbackClass) {
+        DEBUG_LOG( "CallOnError : jm->callbackClass is null!\n");
+        return;
+    }
+
+    jmethodID excConstructor = (*env)->GetMethodID(env, callbackExceptionClass, "<init>", "(Ljava/lang/String;II)V");
+    if (!excConstructor) {
+        DEBUG_LOG( "CallOnError : excConstructor is null!\n");
+        return;
+    }
+    jmethodID callbackExcMethod = (*env)->GetMethodID(env, jm->callbackClass, "onError", "(Lorg/openvpp/jvpp/VppCallbackException;)V");
+    if (!callbackExcMethod) {
+        DEBUG_LOG( "CallOnError : callbackExcMethod is null!\n");
+        return;
+    }
+
+    jobject excObject = (*env)->NewObject(env, callbackExceptionClass, excConstructor,(*env)->NewStringUTF(env, call), clib_net_to_host_u32(context), clib_net_to_host_u32(retval));
+    if (!excObject) {
+        DEBUG_LOG( "CallOnError : excObject is null!\n");
+        return;
+    }
+
+    (*env)->CallVoidMethod(env, jm->callback, callbackExcMethod, excObject);
+    DEBUG_LOG( "CallOnError : Response sent\n");
+}
+
 // control ping needs to be very first thing called
 // to attach rx thread to java thread
 static void vl_api_control_ping_reply_t_handler
@@ -192,24 +232,25 @@ static void vl_api_control_ping_reply_t_handler
     if (was_thread_connected == 0) {
         JNIEnv *env = jm->jenv;
 
-        jmethodID constructor = (*env)->GetMethodID(env, controlPingReplyClass, "<init>", "()V");
-        jmethodID callbackMethod = (*env)->GetMethodID(env, jm->callbackClass, "onControlPingReply", "(Lorg/openvpp/jvpp/dto/ControlPingReply;)V");
+        if (mp->retval<0){
+            CallOnError("controlPing", mp->context, mp->retval);
+        } else {
+            jmethodID constructor = (*env)->GetMethodID(env, controlPingReplyClass, "<init>", "()V");
+            jmethodID callbackMethod = (*env)->GetMethodID(env, jm->callbackClass, "onControlPingReply", "(Lorg/openvpp/jvpp/dto/ControlPingReply;)V");
 
-        jobject dto = (*env)->NewObject(env, controlPingReplyClass, constructor);
+            jobject dto = (*env)->NewObject(env, controlPingReplyClass, constructor);
 
-        jfieldID contextFieldId = (*env)->GetFieldID(env, controlPingReplyClass, "context", "I");
-        (*env)->SetIntField(env, dto, contextFieldId, clib_net_to_host_u32(mp->context));
+            jfieldID contextFieldId = (*env)->GetFieldID(env, controlPingReplyClass, "context", "I");
+            (*env)->SetIntField(env, dto, contextFieldId, clib_net_to_host_u32(mp->context));
 
-        jfieldID retvalFieldId = (*env)->GetFieldID(env, controlPingReplyClass, "retval", "I");
-        (*env)->SetIntField(env, dto, retvalFieldId, clib_net_to_host_u32(mp->retval));
+            jfieldID clientIndexFieldId = (*env)->GetFieldID(env, controlPingReplyClass, "clientIndex", "I");
+            (*env)->SetIntField(env, dto, clientIndexFieldId, clib_net_to_host_u32(mp->client_index));
 
-        jfieldID clientIndexFieldId = (*env)->GetFieldID(env, controlPingReplyClass, "clientIndex", "I");
-        (*env)->SetIntField(env, dto, clientIndexFieldId, clib_net_to_host_u32(mp->client_index));
+            jfieldID vpePidFieldId = (*env)->GetFieldID(env, controlPingReplyClass, "vpePid", "I");
+            (*env)->SetIntField(env, dto, vpePidFieldId, clib_net_to_host_u32(mp->vpe_pid));
 
-        jfieldID vpePidFieldId = (*env)->GetFieldID(env, controlPingReplyClass, "vpePid", "I");
-        (*env)->SetIntField(env, dto, vpePidFieldId, clib_net_to_host_u32(mp->vpe_pid));
-
-        (*env)->CallVoidMethod(env, jm->callback, callbackMethod, dto);
+            (*env)->CallVoidMethod(env, jm->callback, callbackMethod, dto);
+        }
     }
 
     out:
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/VppBaseCallException.java b/vpp-api/java/jvpp/org/openvpp/jvpp/VppBaseCallException.java
new file mode 100644 (file)
index 0000000..792af2c
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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 org.openvpp.jvpp;
+
+/**
+ * Base exception representing failed operation of JVpp request call
+ */
+public abstract class VppBaseCallException extends Exception {
+    private final String methodName;
+    private final int errorCode;
+
+    /**
+     * Constructs an VppCallbackException with the specified api method name and error code.
+     *
+     * @param methodName name of a method, which invocation or execution failed
+     * @param errorCode  negative error code value associated with this failure
+     * @throws NullPointerException     if apiMethodName is null
+     */
+    public VppBaseCallException(final String methodName, final int errorCode) {
+        super(String.format("vppApi.%s failed with error code: %d", methodName, errorCode));
+        this.methodName = java.util.Objects.requireNonNull(methodName, "apiMethodName is null!");
+        this.errorCode = errorCode;
+        if(errorCode >= 0) {
+            throw new IllegalArgumentException("Error code must be < 0. Was " + errorCode +
+                    " for " + methodName );
+        }
+    }
+
+    /**
+     * Returns  name of a method, which invocation failed.
+     *
+     * @return method name
+     */
+    public String getMethodName() {
+        return methodName;
+    }
+
+    /**
+     * Returns the error code associated with this failure.
+     *
+     * @return a negative integer error code
+     */
+    public int getErrorCode() {
+        return errorCode;
+    }
+}
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/VppCallbackException.java b/vpp-api/java/jvpp/org/openvpp/jvpp/VppCallbackException.java
new file mode 100644 (file)
index 0000000..3d2a1cb
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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 org.openvpp.jvpp;
+
+/**
+ * Callback Exception representing failed operation of JVpp request call
+ */
+public class VppCallbackException extends VppBaseCallException {
+    private final int ctxId;
+
+    /**
+     * Constructs an VppCallbackException with the specified api method name and error code.
+     *
+     * @param methodName  name of a method, which invocation failed.
+     * @param ctxId      api request context identifier
+     * @param errorCode  negative error code value associated with this failure
+     * @throws NullPointerException     if apiMethodName is null
+     */
+    public VppCallbackException(final String methodName, final int ctxId, final int errorCode ){
+        super(methodName, errorCode);
+        this.ctxId = ctxId;
+    }
+
+    /**
+     * Returns api request context identifier.
+     *
+     * @return value of context identifier
+     */
+    public int getCtxId() {
+        return ctxId;
+    }
+
+}
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/VppInvocationException.java b/vpp-api/java/jvpp/org/openvpp/jvpp/VppInvocationException.java
new file mode 100644 (file)
index 0000000..298bcd0
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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 org.openvpp.jvpp;
+
+/**
+ * Exception thrown when Vpp jAPI method invocation failed.
+ */
+public class VppInvocationException extends VppBaseCallException {
+    /**
+     * Constructs an VppApiInvocationFailedException with the specified api method name and error code.
+     *
+     * @param methodName  name of a method, which invocation failed.
+     * @param errorCode  negative error code value associated with this failure
+     * @throws NullPointerException     if apiMethodName is null
+     */
+    public VppInvocationException(final String methodName, final int errorCode) {
+        super(methodName, errorCode);
+    }
+}
index c17f2e0..f681e37 100644 (file)
  */
 
 package org.openvpp.jvpp.callback;
+import org.openvpp.jvpp.VppCallbackException;
 
 /**
-* Base JVppCallback interface
-*/
+ * Base JVppCallback interface
+ */
 public interface JVppCallback {
+    /**
+     * onError callback handler used to report failing operation
+     * @param ex VppCallbackException object containing details about failing operation
+     */
+    void onError(VppCallbackException ex);
 }
index 8cd1534..273e444 100644 (file)
@@ -17,6 +17,7 @@
 package org.openvpp.jvpp.dto;
 
 import org.openvpp.jvpp.JVpp;
+import org.openvpp.jvpp.VppInvocationException;
 
 /**
 * Base interface for all request DTOs
@@ -28,6 +29,6 @@ public interface JVppRequest {
      *
      * @return context id of this request. Can be used to track incomming response
      */
-    int send(JVpp jvpp);
+    int send(JVpp jvpp) throws VppInvocationException;
 
 }
index 8dab7f5..9219e35 100644 (file)
 package org.openvpp.jvpp.future;
 
 
-import java.util.concurrent.CompletionStage;
 import org.openvpp.jvpp.dto.JVppReply;
 import org.openvpp.jvpp.dto.JVppRequest;
 
+import java.util.concurrent.CompletionStage;
+
 /**
 * Future facade on top of JVpp
 */
@@ -30,6 +31,7 @@ public interface FutureJVppInvoker extends AutoCloseable {
      * Invoke asynchronous operation on VPP
      *
      * @return CompletionStage with future result of an async VPP call
+     * @throws org.openvpp.jvpp.VppInvocationException when send request failed with details
      */
     <REQ extends JVppRequest, REPLY extends JVppReply<REQ>> CompletionStage<REPLY> send(REQ req);
 
index b005b13..69967a1 100644 (file)
 package org.openvpp.jvpp.future;
 
 
+import org.openvpp.jvpp.JVpp;
+import org.openvpp.jvpp.VppInvocationException;
+import org.openvpp.jvpp.dto.*;
+
 import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionStage;
-import org.openvpp.jvpp.JVpp;
-import org.openvpp.jvpp.dto.ControlPing;
-import org.openvpp.jvpp.dto.JVppDump;
-import org.openvpp.jvpp.dto.JVppReply;
-import org.openvpp.jvpp.dto.JVppReplyDump;
-import org.openvpp.jvpp.dto.JVppRequest;
 
 /**
 * Future facade on top of JVpp
@@ -59,20 +57,26 @@ public class FutureJVppInvokerFacade implements FutureJVppInvoker {
     @SuppressWarnings("unchecked")
     public <REQ extends JVppRequest, REPLY extends JVppReply<REQ>> CompletionStage<REPLY> send(REQ req) {
         synchronized(requests) {
-            final int contextId = jvpp.send(req);
-
-            final CompletableFuture<REPLY> replyCompletableFuture;
-            if(req instanceof JVppDump) {
-                replyCompletableFuture = (CompletableFuture<REPLY>) new CompletableDumpFuture<>(contextId);
-            } else {
-                replyCompletableFuture = new CompletableFuture<>();
-            }
-
-            requests.put(contextId, replyCompletableFuture);
-            if(req instanceof JVppDump) {
-                requests.put(jvpp.send(new ControlPing()), replyCompletableFuture);
+            try {
+                final CompletableFuture<REPLY> replyCompletableFuture;
+                final int contextId = jvpp.send(req);
+
+                if(req instanceof JVppDump) {
+                    replyCompletableFuture = (CompletableFuture<REPLY>) new CompletableDumpFuture<>(contextId);
+                } else {
+                    replyCompletableFuture = new CompletableFuture<>();
+                }
+
+                requests.put(contextId, replyCompletableFuture);
+                if(req instanceof JVppDump) {
+                    requests.put(jvpp.send(new ControlPing()), replyCompletableFuture);
+                }
+                return replyCompletableFuture;
+            } catch (VppInvocationException ex) {
+                final CompletableFuture<REPLY> replyCompletableFuture = new CompletableFuture<>();
+                replyCompletableFuture.completeExceptionally(ex);
+                return replyCompletableFuture;
             }
-            return replyCompletableFuture;
         }
     }
 
index c3bb272..8c976db 100644 (file)
@@ -18,16 +18,12 @@ package org.openvpp.jvpp.test;
 
 import org.openvpp.jvpp.JVpp;
 import org.openvpp.jvpp.JVppImpl;
+import org.openvpp.jvpp.VppCallbackException;
 import org.openvpp.jvpp.VppJNIConnection;
 import org.openvpp.jvpp.callback.GetNodeIndexCallback;
 import org.openvpp.jvpp.callback.ShowVersionCallback;
 import org.openvpp.jvpp.callback.SwInterfaceCallback;
-import org.openvpp.jvpp.dto.GetNodeIndex;
-import org.openvpp.jvpp.dto.GetNodeIndexReply;
-import org.openvpp.jvpp.dto.ShowVersion;
-import org.openvpp.jvpp.dto.ShowVersionReply;
-import org.openvpp.jvpp.dto.SwInterfaceDetails;
-import org.openvpp.jvpp.dto.SwInterfaceDump;
+import org.openvpp.jvpp.dto.*;
 
 public class CallbackApiTest {
 
@@ -35,14 +31,14 @@ public class CallbackApiTest {
 
         @Override
         public void onGetNodeIndexReply(final GetNodeIndexReply msg) {
-            System.out.printf("Received GetNodeIndexReply: context=%d, retval=%d, nodeIndex=%d\n",
-                    msg.context, msg.retval, msg.nodeIndex);
+            System.out.printf("Received GetNodeIndexReply: context=%d, nodeIndex=%d\n",
+                    msg.context, msg.nodeIndex);
         }
         @Override
-        public void onShowVersionReply(final ShowVersionReply msg) {
-            System.out.printf("Received ShowVersionReply: context=%d, retval=%d, program=%s, version=%s, " +
+        public void onShowVersionReply(final ShowVersionReply msg)  {
+            System.out.printf("Received ShowVersionReply: context=%d, program=%s, version=%s, " +
                     "buildDate=%s, buildDirectory=%s\n",
-                    msg.context, msg.retval, new String(msg.program), new String(msg.version),
+                    msg.context, new String(msg.program), new String(msg.version),
                     new String(msg.buildDate), new String(msg.buildDirectory));
         }
 
@@ -53,12 +49,17 @@ public class CallbackApiTest {
                     new String(msg.interfaceName), msg.l2AddressLength, msg.adminUpDown,
                     msg.linkUpDown, msg.linkSpeed, (int)msg.linkMtu);
         }
+
+        @Override
+        public void onError(VppCallbackException ex) {
+            System.out.printf("Received onError exception: call=%s, context=%d, retval=%d\n", ex.getMethodName(), ex.getCtxId(), ex.getErrorCode());
+        }
     }
 
     private static void testCallbackApi() throws Exception {
         System.out.println("Testing Java callback API");
-        JVpp jvpp = new JVppImpl( new VppJNIConnection("CallbackApiTest"));
-        jvpp.connect( new TestCallback());
+        JVpp jvpp = new JVppImpl(new VppJNIConnection("CallbackApiTest"));
+        jvpp.connect(new TestCallback());
         System.out.println("Successfully connected to VPP");
 
         System.out.println("Sending ShowVersion request...");
index b5e5057..bb06c76 100644 (file)
@@ -18,9 +18,14 @@ package org.openvpp.jvpp.test;
 
 import org.openvpp.jvpp.JVpp;
 import org.openvpp.jvpp.JVppImpl;
+import org.openvpp.jvpp.VppCallbackException;
 import org.openvpp.jvpp.VppJNIConnection;
+import org.openvpp.jvpp.callback.GetNodeIndexCallback;
 import org.openvpp.jvpp.callback.ShowVersionCallback;
 import org.openvpp.jvpp.callfacade.CallbackJVppFacade;
+import org.openvpp.jvpp.dto.GetNodeIndex;
+import org.openvpp.jvpp.dto.GetNodeIndexReply;
+import org.openvpp.jvpp.dto.ShowVersionReply;
 
 /**
  * CallbackJVppFacade together with CallbackJVppFacadeCallback allow for setting different callback for each request.
@@ -28,15 +33,51 @@ import org.openvpp.jvpp.callfacade.CallbackJVppFacade;
  */
 public class CallbackJVppFacadeTest {
 
-    private static ShowVersionCallback showVersionCallback1 = msg ->
-            System.out.printf("ShowVersionCallback1 received ShowVersionReply: context=%d, retval=%d, program=%s," +
-                            "version=%s, buildDate=%s, buildDirectory=%s\n", msg.context, msg.retval, new String(msg.program),
-                    new String(msg.version), new String(msg.buildDate), new String(msg.buildDirectory));
+    private static ShowVersionCallback showVersionCallback1;
+    private static ShowVersionCallback showVersionCallback2;
+    private static GetNodeIndexCallback getNodeIndexCallback;
 
-    private static ShowVersionCallback showVersionCallback2 = msg ->
-            System.out.printf("ShowVersionCallback2 received ShowVersionReply: context=%d, retval=%d, program=%s," +
-                            "version=%s, buildDate=%s, buildDirectory=%s\n", msg.context, msg.retval, new String(msg.program),
-                    new String(msg.version), new String(msg.buildDate), new String(msg.buildDirectory));
+    static {
+        getNodeIndexCallback = new GetNodeIndexCallback() {
+            @Override
+            public void onGetNodeIndexReply(final GetNodeIndexReply msg) {
+                System.out.printf("Received GetNodeIndexReply: context=%d, nodeIndex=%d\n",
+                        msg.context, msg.nodeIndex);
+            }
+
+            @Override
+            public void onError(VppCallbackException ex) {
+                System.out.printf("Received onError exception in getNodeIndexCallback: call=%s, reply=%d, context=%d\n", ex.getMethodName(), ex.getErrorCode(), ex.getCtxId());
+            }
+        };
+        showVersionCallback2 = new ShowVersionCallback() {
+            @Override
+            public void onShowVersionReply(final ShowVersionReply msg) {
+                System.out.printf("ShowVersionCallback1 received ShowVersionReply: context=%d, program=%s," +
+                                "version=%s, buildDate=%s, buildDirectory=%s\n", msg.context, new String(msg.program),
+                        new String(msg.version), new String(msg.buildDate), new String(msg.buildDirectory));
+            }
+
+            @Override
+            public void onError(VppCallbackException ex) {
+                System.out.printf("Received onError exception in showVersionCallback2: call=%s, reply=%d, context=%d\n", ex.getMethodName(), ex.getErrorCode(), ex.getCtxId());
+            }
+
+        };
+        showVersionCallback1 = new ShowVersionCallback() {
+            @Override
+            public void onShowVersionReply(final ShowVersionReply msg) {
+                System.out.printf("ShowVersionCallback1 received ShowVersionReply: context=%d, program=%s," +
+                                "version=%s, buildDate=%s, buildDirectory=%s\n", msg.context, new String(msg.program),
+                        new String(msg.version), new String(msg.buildDate), new String(msg.buildDirectory));
+            }
+
+            @Override
+            public void onError(VppCallbackException ex) {
+                System.out.printf("Received onError exception in showVersionCallback1: call=%s, reply=%d, context=%d\n", ex.getMethodName(), ex.getErrorCode(), ex.getCtxId());
+            }
+        };
+    }
 
     private static void testCallbackFacade() throws Exception {
         System.out.println("Testing CallbackJVppFacade");
@@ -49,6 +90,9 @@ public class CallbackJVppFacadeTest {
         jvppCallbackFacade.showVersion(showVersionCallback1);
         jvppCallbackFacade.showVersion(showVersionCallback2);
 
+        GetNodeIndex getNodeIndexRequest = new GetNodeIndex();
+        getNodeIndexRequest.nodeName = "dummyNode".getBytes();
+        jvppCallbackFacade.getNodeIndex(getNodeIndexRequest, getNodeIndexCallback);
 
         Thread.sleep(2000);
 
index bec302b..514bb3e 100644 (file)
@@ -18,6 +18,7 @@ package org.openvpp.jvpp.test;
 
 import org.openvpp.jvpp.JVpp;
 import org.openvpp.jvpp.JVppImpl;
+import org.openvpp.jvpp.VppCallbackException;
 import org.openvpp.jvpp.VppJNIConnection;
 import org.openvpp.jvpp.callback.ControlPingCallback;
 import org.openvpp.jvpp.dto.ControlPing;
@@ -32,9 +33,15 @@ public class ControlPingTest {
         jvpp.connect( new ControlPingCallback() {
             @Override
             public void onControlPingReply(final ControlPingReply reply) {
-                System.out.printf("Received ControlPingReply: context=%d, retval=%d, clientIndex=%d vpePid=%d\n",
-                        reply.context, reply.retval, reply.clientIndex, reply.vpePid);
+                System.out.printf("Received ControlPingReply: context=%d, clientIndex=%d vpePid=%d\n",
+                        reply.context, reply.clientIndex, reply.vpePid);
             }
+
+            @Override
+            public void onError(VppCallbackException ex) {
+                System.out.printf("Received onError exception: call=%s, reply=%d, context=%d ", ex.getMethodName(), ex.getErrorCode(), ex.getCtxId());
+            }
+
         });
         System.out.println("Successfully connected to VPP");
         Thread.sleep(1000);
index f61867e..b3dc1f4 100644 (file)
@@ -16,8 +16,6 @@
 
 package org.openvpp.jvpp.test;
 
-import static java.util.Objects.requireNonNull;
-
 import org.openvpp.jvpp.JVppImpl;
 import org.openvpp.jvpp.VppJNIConnection;
 import org.openvpp.jvpp.dto.CreateSubif;
@@ -26,6 +24,8 @@ import org.openvpp.jvpp.dto.SwInterfaceDetailsReplyDump;
 import org.openvpp.jvpp.dto.SwInterfaceDump;
 import org.openvpp.jvpp.future.FutureJVppFacade;
 
+import static java.util.Objects.requireNonNull;
+
 /**
  * <p>Tests sub-interface creation.<br> Equivalent to:<br>
  *
@@ -76,9 +76,8 @@ public class CreateSubInterfaceTest {
     }
 
     private static void print(CreateSubifReply reply) {
-        System.out.printf("CreateSubifReply: context=%d, retval=%d, swIfIndex=%d\n",
+        System.out.printf("CreateSubifReply: context=%d, swIfIndex=%d\n",
                 reply.context,
-                reply.retval,
                 reply.swIfIndex);
     }
 
index 745482d..0000bcd 100644 (file)
 
 package org.openvpp.jvpp.test;
 
-import java.util.Objects;
-import java.util.concurrent.Future;
 import org.openvpp.jvpp.VppJNIConnection;
-import org.openvpp.jvpp.dto.GetNodeIndex;
-import org.openvpp.jvpp.dto.GetNodeIndexReply;
-import org.openvpp.jvpp.dto.ShowVersion;
-import org.openvpp.jvpp.dto.ShowVersionReply;
-import org.openvpp.jvpp.dto.SwInterfaceDetails;
-import org.openvpp.jvpp.dto.SwInterfaceDetailsReplyDump;
-import org.openvpp.jvpp.dto.SwInterfaceDump;
+import org.openvpp.jvpp.dto.*;
 import org.openvpp.jvpp.future.FutureJVppFacade;
 
+import java.util.Objects;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
 public class FutureApiTest {
 
     private static void testShowVersion(final FutureJVppFacade jvpp) {
@@ -38,12 +34,12 @@ public class FutureApiTest {
             Objects.requireNonNull(replyFuture,"replyFuture is null");
             final ShowVersionReply reply = replyFuture.get();
             Objects.requireNonNull(reply,"reply is null");
-            System.out.printf("Received ShowVersionReply: context=%d, retval=%d, program=%s, " +
+            System.out.printf("Received ShowVersionReply: context=%d, program=%s, " +
                             "version=%s, buildDate=%s, buildDirectory=%s\n",
-                    reply.context, reply.retval, new String(reply.program), new String(reply.version),
+                    reply.context, new String(reply.program), new String(reply.version),
                     new String(reply.buildDate), new String(reply.buildDirectory));
         } catch (Exception e) {
-            System.err.printf("ShowVersion request failed:\n");
+            System.err.printf("ShowVersion request failed:"+e.getCause());
             e.printStackTrace();
         }
     }
@@ -62,10 +58,12 @@ public class FutureApiTest {
             Objects.requireNonNull(replyFuture,"replyFuture is null");
             final GetNodeIndexReply reply = replyFuture.get();
             Objects.requireNonNull(reply,"reply is null");
-            System.out.printf("Received GetNodeIndexReply: context=%d, retval=%d, nodeIndex=%d\n",
-                    reply.context, reply.retval, reply.nodeIndex);
+            System.out.printf("Received GetNodeIndexReply: context=%d, nodeIndex=%d\n",
+                    reply.context, reply.nodeIndex);
+        } catch (ExecutionException e) {
+            System.err.printf("GetNodeIndex request failed:"+e.getCause());
         } catch (Exception e) {
-            System.err.printf("GetNodeIndex request failed:\n");
+            System.err.printf("GetNodeIndex request failed:"+e.getCause());
             e.printStackTrace();
         }
     }
@@ -91,7 +89,7 @@ public class FutureApiTest {
         } catch(NullPointerException e) {
             throw new IllegalStateException(e.getMessage());
         } catch (Exception e) {
-            System.err.printf("SwInterfaceDump request failed:\n");
+            System.err.printf("SwInterfaceDump request failed:"+e.getCause());
             e.printStackTrace();
         }
     }
@@ -103,7 +101,6 @@ public class FutureApiTest {
                 new org.openvpp.jvpp.JVppImpl(new VppJNIConnection("FutureApiTest"));
         final FutureJVppFacade jvppFacade = new FutureJVppFacade(impl);
         System.out.println("Successfully connected to VPP");
-
         testShowVersion(jvppFacade);
         testGetNodeIndex(jvppFacade);
         testSwInterfaceDump(jvppFacade);
index e92b4f5..d8d04ed 100644 (file)
@@ -83,25 +83,22 @@ public class L2AclTest {
     }
 
     private static void print(ClassifyAddDelTableReply reply) {
-        System.out.printf("ClassifyAddDelTableReply: context=%d, retval=%d, " +
+        System.out.printf("ClassifyAddDelTableReply: context=%d, " +
                         "newTableIndex=%d, skipNVectors=%d, matchNVectors=%d\n",
                 reply.context,
-                reply.retval,
                 reply.newTableIndex,
                 reply.skipNVectors,
                 reply.matchNVectors);
     }
 
     private static void print(ClassifyAddDelSessionReply reply) {
-        System.out.printf("ClassifyAddDelSessionReply: context=%d, retval=%d\n",
-                reply.context,
-                reply.retval);
+        System.out.printf("ClassifyAddDelSessionReply: context=%d\n",
+                reply.context);
     }
 
     private static void print(final InputAclSetInterfaceReply reply) {
-        System.out.printf("InputAclSetInterfaceReply: context=%d, retval=%d\n",
-                reply.context,
-                reply.retval);
+        System.out.printf("InputAclSetInterfaceReply: context=%d\n",
+                reply.context);
 
     }
 
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/test/OnErrorCallbackTest.java b/vpp-api/java/jvpp/org/openvpp/jvpp/test/OnErrorCallbackTest.java
new file mode 100644 (file)
index 0000000..46d8558
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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 org.openvpp.jvpp.test;
+
+import org.openvpp.jvpp.JVpp;
+import org.openvpp.jvpp.JVppImpl;
+import org.openvpp.jvpp.VppCallbackException;
+import org.openvpp.jvpp.VppJNIConnection;
+import org.openvpp.jvpp.callback.GetNodeIndexCallback;
+import org.openvpp.jvpp.callback.ShowVersionCallback;
+import org.openvpp.jvpp.dto.*;
+
+public class OnErrorCallbackTest {
+
+    private static class TestCallback implements GetNodeIndexCallback, ShowVersionCallback{
+
+        @Override
+        public void onGetNodeIndexReply(final GetNodeIndexReply msg) {
+            System.out.printf("Received GetNodeIndexReply: context=%d, nodeIndex=%d\n",
+                    msg.context, msg.nodeIndex);
+        }
+        @Override
+        public void onShowVersionReply(final ShowVersionReply msg) {
+            System.out.printf("Received ShowVersionReply: context=%d, program=%s, version=%s, " +
+                    "buildDate=%s, buildDirectory=%s\n",
+                    msg.context, new String(msg.program), new String(msg.version),
+                    new String(msg.buildDate), new String(msg.buildDirectory));
+        }
+
+        @Override
+        public void onError(VppCallbackException ex) {
+            System.out.printf("Received onError exception: call=%s, context=%d, retval=%d\n", ex.getMethodName(), ex.getCtxId(), ex.getErrorCode());
+        }
+    }
+
+    private static void testCallbackApi() throws Exception {
+        System.out.println("Testing Java callback API");
+        JVpp jvpp = new JVppImpl(new VppJNIConnection("CallbackApiTest"));
+        jvpp.connect(new TestCallback());
+        System.out.println("Successfully connected to VPP");
+
+        System.out.println("Sending ShowVersion request...");
+        jvpp.send(new ShowVersion());
+
+        System.out.println("Sending GetNodeIndex request...");
+        GetNodeIndex getNodeIndexRequest = new GetNodeIndex();
+        getNodeIndexRequest.nodeName = "dummyNode".getBytes();
+        jvpp.send(getNodeIndexRequest);
+
+        Thread.sleep(5000);
+
+        System.out.println("Disconnecting...");
+        jvpp.close();
+        Thread.sleep(1000);
+    }
+
+    public static void main(String[] args) throws Exception {
+        testCallbackApi();
+    }
+}
index d1ce749..f9c67dd 100644 (file)
@@ -10,4 +10,5 @@ CallbackApiTest - Similar to ControlPingTest, invokes more complex calls (e.g. i
 FutureApiTest - Execution of more complex calls using Future based JVpp facade
 CallbackJVppFacadeTest - Execution of more complex calls using Callback based JVpp facade
 L2AclTest - Tests L2 ACL creation
-CreateSubInterfaceTest - Tests sub-interface creation
\ No newline at end of file
+CreateSubInterfaceTest - Tests sub-interface creation
+OnErrorCallbackTest - simple test failing with onError