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 <tsirovat@cisco.com>
diff --git a/vpp-api/java/jvpp/jvpp.c b/vpp-api/java/jvpp/jvpp.c
index 56c43c9..00c50f9 100644
--- a/vpp-api/java/jvpp/jvpp.c
+++ b/vpp-api/java/jvpp/jvpp.c
@@ -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 @@
     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 @@
     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: