VPP-205: jvpp plugin support.

Splits jvpp into two jars
jvpp-registry.jar - base jvpp functionality
jvpp-core.jar - Java wrapper for vpe.api

Plugins can be generated the same way jvpp-core.jar is.
Example (nsh):
https://gerrit.fd.io/r/#/c/2118/

Change-Id: I2254f90b2c3e423563bb91bf70877979f1e90a7d
Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
diff --git a/vpp-api/java/Makefile.am b/vpp-api/java/Makefile.am
index d3f3c4f..aea5c0a 100644
--- a/vpp-api/java/Makefile.am
+++ b/vpp-api/java/Makefile.am
@@ -22,51 +22,99 @@
 lib_LTLIBRARIES = 
 
 #
-# jVpp binding
+# jvpp-common
 #
 
 nobase_include_HEADERS =		\
-  jvpp/org_openvpp_jvpp_VppJNIConnection.h
+  jvpp-common/jvpp_common.h
 
-lib_LTLIBRARIES += libjvpp.la
+lib_LTLIBRARIES += libjvpp_common.la
 
-libjvpp_la_SOURCES = jvpp/jvpp.c
-libjvpp_la_LIBADD = -lvlibmemoryclient -lvlibapi -lsvm -lvppinfra \
+libjvpp_common_la_SOURCES = jvpp-common/jvpp_common.c
+libjvpp_common_la_LIBADD = -lvlibmemoryclient -lvlibapi -lsvm -lvppinfra \
 	              -lpthread -lm -lrt
-libjvpp_la_LDFLAGS = -module
-libjvpp_la_CPPFLAGS = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux
+libjvpp_common_la_LDFLAGS = -module
+libjvpp_common_la_CPPFLAGS = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux
 
-# todo make two jars api jar and impl jar
-jarfile_jvpp = jvpp-$(PACKAGE_VERSION).jar
-packagedir_jvpp = org/openvpp/jvpp
-JAVAROOT = .
 
-BUILT_SOURCES += jvpp/org_openvpp_jvpp_VppJNIConnection.h jvpp/jvpp.c
+#
+# jvpp-registry (connection management + plugin registry)
+#
+lib_LTLIBRARIES += libjvpp_registry.la
 
-jvpp/org_openvpp_jvpp_VppJNIConnection.h: $(prefix)/../vpp/vpp-api/vpe.api
-	@echo "  jVpp API";				\
-	cp -rf @srcdir@/jvpp/* -t jvpp/;			\
-	mkdir -p jvpp/gen/target/org/openvpp/jvpp;				\
-	cp -rf jvpp/org/openvpp/jvpp/* -t jvpp/gen/target/org/openvpp/jvpp/;	\
-	$(CC) $(CPPFLAGS) -E -P -C -x c $<			                  \
-	| vppapigen --input - --python defs_vpp_papi.py; 				\
-	mkdir -p dto future callfacade callback notification; 	\
-	./jvpp/gen/jvpp_gen.py -i defs_vpp_papi.py;				\
-	cp -rf dto future callfacade callback notification *.java -t jvpp/gen/target/org/openvpp/jvpp/;	\
-	cp -rf jvpp_gen.h -t jvpp/gen/target;	\
-	rm -rf dto future callfacade callback notification *.java jvpp_gen.h;	\
-	$(JAVAC) -classpath . -d . jvpp/gen/target/org/openvpp/jvpp/*.java \
-		jvpp/gen/target/org/openvpp/jvpp/dto/*.java  \
-		jvpp/gen/target/org/openvpp/jvpp/callback/*.java \
-		jvpp/gen/target/org/openvpp/jvpp/notification/*.java \
-		jvpp/gen/target/org/openvpp/jvpp/callfacade/*.java \
-		jvpp/gen/target/org/openvpp/jvpp/future/*.java 	\
-		jvpp/gen/target/org/openvpp/jvpp/test/*.java	\
-		|| (echo "JVpp compilation failed: $$?"; exit 1);	\
-	$(JAVAH) -classpath . -d jvpp org.openvpp.jvpp.VppJNIConnection ;	\
-	$(JAVAH) -classpath . -d jvpp org.openvpp.jvpp.JVppImpl ;
+libjvpp_registry_la_SOURCES = jvpp-registry/jvpp_registry.c
+libjvpp_registry_la_LIBADD = -lvlibmemoryclient -lvlibapi -lsvm -lvppinfra \
+	              -lpthread -lm -lrt -ljvpp_common
+libjvpp_registry_la_LDFLAGS = -module
+libjvpp_registry_la_CPPFLAGS = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux
 
-$(jarfile_jvpp): libjvpp.la
-	cd .libs ; $(JAR) cf $(JARFLAGS) ../$@ libjvpp.so.0.0.0 ../$(packagedir_jvpp)/* ; cd ..;
+jarfile_jvpp_registry = jvpp-registry-$(PACKAGE_VERSION).jar
+packagedir_jvpp_registry = org/openvpp/jvpp
 
-all-local: $(jarfile_jvpp)
+BUILT_SOURCES += jvpp-registry/org_openvpp_jvpp_VppJNIConnection.h
+
+
+jvpp-registry/org_openvpp_jvpp_VppJNIConnection.h:
+	@echo " jvpp-registry.jar generation ";				\
+	mkdir -p jvpp-registry/target;				\
+	cp -rf @srcdir@/jvpp-registry/* -t jvpp-registry/;
+	$(JAVAC) -d jvpp-registry/target jvpp-registry/$(packagedir_jvpp_registry)/*.java \
+		jvpp-registry/$(packagedir_jvpp_registry)/dto/*.java  \
+		jvpp-registry/$(packagedir_jvpp_registry)/callback/*.java \
+		jvpp-registry/$(packagedir_jvpp_registry)/notification/*.java \
+		jvpp-registry/$(packagedir_jvpp_registry)/future/*.java 	\
+		jvpp-registry/$(packagedir_jvpp_registry)/test/*.java 	\
+		|| (echo "jvpp-registry compilation failed: $$?"; exit 1);	\
+	$(JAVAH) -classpath jvpp-registry/target -d jvpp-registry org.openvpp.jvpp.VppJNIConnection ;
+	$(JAVAH) -classpath jvpp-registry/target -d jvpp-registry org.openvpp.jvpp.JVppRegistryImpl ;
+
+$(jarfile_jvpp_registry): libjvpp_registry.la
+	cp .libs/libjvpp_registry.so.0.0.0 jvpp-registry/target;	\
+	$(JAR) cf $(JARFLAGS) $@ -C jvpp-registry/target .;
+
+#
+# jvpp-core (Java wrapper for vpe.api)
+#
+lib_LTLIBRARIES += libjvpp_core.la
+
+libjvpp_core_la_SOURCES = jvpp-core/jvpp_core.c jvpp-core/jvpp_core_gen.h
+libjvpp_core_la_LIBADD = -lvlibmemoryclient -lvlibapi -lsvm -lvppinfra \
+	              -lpthread -lm -lrt -ljvpp_common
+libjvpp_core_la_LDFLAGS = -module
+libjvpp_core_la_CPPFLAGS = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux
+
+jarfile_jvpp_core = jvpp-core-$(PACKAGE_VERSION).jar
+packagedir_jvpp_core = org/openvpp/jvpp/core
+api_file = $(prefix)/../vpp/vpp-api/vpe.api
+
+BUILT_SOURCES += jvpp-core/org_openvpp_jvpp_core_JVppCoreImpl.h
+
+
+defs_vpp_papi.py:
+	@echo "jVpp API";				\
+	vppapigen --input $(api_file) --python jvpp-core/defs_vpp_papi.py;
+
+jvpp-core/org_openvpp_jvpp_core_JVppCoreImpl.h: defs_vpp_papi.py
+	cp -rf @srcdir@/jvpp-core/* -t jvpp-core/; \
+	mkdir -p jvpp-core/target; \
+	cd jvpp-core; \
+	mkdir dto future callfacade callback notification; \
+	@srcdir@/jvpp/gen/jvpp_gen.py -i defs_vpp_papi.py --plugin_name core; \
+	cp -rf dto future callfacade callback notification *.java -t $(packagedir_jvpp_core); \
+	rm -rf dto future callfacade callback notification *.java; \
+	cd ..; \
+	$(JAVAC) -classpath jvpp-registry/target -d jvpp-core/target jvpp-core/$(packagedir_jvpp_core)/*.java \
+		jvpp-core/$(packagedir_jvpp_core)/dto/*.java \
+		jvpp-core/$(packagedir_jvpp_core)/callback/*.java \
+		jvpp-core/$(packagedir_jvpp_core)/notification/*.java \
+		jvpp-core/$(packagedir_jvpp_core)/future/*.java 	\
+		jvpp-core/$(packagedir_jvpp_core)/callfacade/*.java 	\
+		jvpp-core/$(packagedir_jvpp_core)/test/*.java \
+		|| (echo "jvpp-core compilation failed: $$?"; exit 1); \
+	$(JAVAH) -classpath jvpp-registry/target:jvpp-core/target -d jvpp-core org.openvpp.jvpp.core.JVppCoreImpl ;
+	
+$(jarfile_jvpp_core): libjvpp_core.la
+	cp .libs/libjvpp_core.so.0.0.0 jvpp-core/target;	\
+	$(JAR) cf $(JARFLAGS) $@ -C jvpp-core/target .;
+
+all-local: $(jarfile_jvpp_registry) $(jarfile_jvpp_core)
diff --git a/vpp-api/java/jvpp/Readme.txt b/vpp-api/java/Readme.txt
similarity index 97%
rename from vpp-api/java/jvpp/Readme.txt
rename to vpp-api/java/Readme.txt
index 9b759e0..be540b0 100644
--- a/vpp-api/java/jvpp/Readme.txt
+++ b/vpp-api/java/Readme.txt
@@ -10,6 +10,11 @@
 * Lightweight
 
 == Architecture
+
+FIXME: update the file after plugin support is merged
+Current architecture is documented on the wiki page:
+https://wiki.fd.io/view/VPP/Java_API/Plugin_support
+
 JVpp and JNI
 
 
diff --git a/vpp-api/java/jvpp-common/jvpp_common.c b/vpp-api/java/jvpp-common/jvpp_common.c
new file mode 100644
index 0000000..ebec9e9
--- /dev/null
+++ b/vpp-api/java/jvpp-common/jvpp_common.c
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+#define _GNU_SOURCE /* for strcasestr(3) */
+
+#include "jvpp_common.h"
+
+#ifndef JVPP_DEBUG
+#define JVPP_DEBUG 0
+#endif
+
+#if JVPP_DEBUG == 1
+#define DEBUG_LOG(...) clib_warning(__VA_ARGS__)
+#else
+#define DEBUG_LOG(...)
+#endif
+
+/* shared jvpp main structure */
+jvpp_main_t jvpp_main __attribute__((aligned (64)));
+
+void call_on_error(const char* callName, int contextId, int retval,
+        jclass callbackClass, jobject callbackObject,
+        jclass callbackExceptionClass) {
+    DEBUG_LOG("\nCallOnError : callback=%s, retval=%d, context=%d\n", callName,
+            clib_net_to_host_u32(retval), clib_net_to_host_u32(context));
+    JNIEnv *env = jvpp_main.jenv;
+    if (!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, 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, callName),
+            clib_net_to_host_u32(contextId), clib_net_to_host_u32(retval));
+    if (!excObject) {
+        DEBUG_LOG("CallOnError : excObject is null!\n");
+        return;
+    }
+
+    (*env)->CallVoidMethod(env, callbackObject, callbackExcMethod, excObject);
+    DEBUG_LOG("CallOnError : Response sent\n");
+}
diff --git a/vpp-api/java/jvpp-common/jvpp_common.h b/vpp-api/java/jvpp-common/jvpp_common.h
new file mode 100644
index 0000000..bbb203e
--- /dev/null
+++ b/vpp-api/java/jvpp-common/jvpp_common.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+#ifndef __included_jvpp_common_h__
+#define __included_jvpp_common_h__
+//
+#include <vppinfra/types.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+#include <jni.h>
+
+typedef struct {
+    /* Unique identifier used for matching replays with requests  */
+    volatile u32 context_id;
+
+    /* Spinlock */
+    volatile u32 lock;
+    u32 tag;
+
+    /* JNI Native Method Interface pointer for message handlers */
+    JNIEnv *jenv;
+
+    /* JNI Invoke Interface pointer for attachment of rx thread to java thread */
+    JavaVM *jvm;
+
+    /* Convenience */
+    unix_shared_memory_queue_t * vl_input_queue;
+    u32 my_client_index;
+} jvpp_main_t;
+
+extern jvpp_main_t jvpp_main __attribute__((aligned (64)));
+
+static_always_inline u32 vppjni_get_context_id(jvpp_main_t * jm) {
+    return __sync_add_and_fetch(&jm->context_id, 1);
+}
+
+static_always_inline void vppjni_lock(jvpp_main_t * jm, u32 tag) {
+    while (__sync_lock_test_and_set(&jm->lock, 1))
+        ;
+    jm->tag = tag;
+}
+
+static_always_inline void vppjni_unlock(jvpp_main_t * jm) {
+    jm->tag = 0;
+    CLIB_MEMORY_BARRIER();
+    jm->lock = 0;
+}
+
+/**
+ * Calls onError callback on callbackObject reference. Passes instance of callbackExceptionClass as parameter.
+ */
+void call_on_error(const char* callName, int contextId, int retval,
+        jclass callbackClass, jobject callbackObject,
+        jclass callbackExceptionClass);
+
+#endif /* __included_jvpp_common_h__ */
diff --git a/vpp-api/java/jvpp-core/jvpp_core.c b/vpp-api/java/jvpp-core/jvpp_core.c
new file mode 100644
index 0000000..cc1f9b5
--- /dev/null
+++ b/vpp-api/java/jvpp-core/jvpp_core.c
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+#include <vnet/vnet.h>
+
+#include <vpp-api/vpe_msg_enum.h>
+#define vl_typedefs             /* define message structures */
+#include <vpp-api/vpe_all_api_h.h>
+#undef vl_typedefs
+
+#define vl_endianfun
+#include <vpp-api/vpe_all_api_h.h>
+#undef vl_endianfun
+
+#define vl_print(handle, ...)
+#define vl_printfun
+#include <vpp-api/vpe_all_api_h.h>
+#undef vl_printfun
+
+#include <vnet/api_errno.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+#include <jni.h>
+
+#include <jvpp-common/jvpp_common.h>
+
+// TODO: generate jvpp_plugin_name.c files (or at least reuse plugin's main structure)
+typedef struct {
+    /* Base message index for the nsh plugin */
+    u16 msg_id_base;
+
+    /* Pointer to shared memory queue */
+    unix_shared_memory_queue_t * vl_input_queue;
+
+    /* VPP api client index */
+    u32 my_client_index;
+
+    /* Callback object and class references enabling asynchronous Java calls */
+    jobject callbackObject;
+    jclass callbackClass;
+
+} core_main_t;
+
+core_main_t core_main __attribute__((aligned (64)));
+
+#include "org_openvpp_jvpp_core_JVppCoreImpl.h"
+#include "jvpp_core_gen.h"
+
+JNIEXPORT void JNICALL Java_org_openvpp_jvpp_core_JVppCoreImpl_init0
+(JNIEnv * env, jclass clazz, jobject callback, jlong queue_address, jint my_client_index) {
+    core_main_t * plugin_main = &core_main;
+    plugin_main->my_client_index = my_client_index;
+    plugin_main->vl_input_queue = (unix_shared_memory_queue_t *)queue_address;
+
+    plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback);
+    plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback));
+
+    #define _(N,n)                                  \
+        vl_msg_api_set_handlers(VL_API_##N, #n,     \
+                vl_api_##n##_t_handler,             \
+                vl_noop_handler,                    \
+                vl_api_##n##_t_endian,              \
+                vl_api_##n##_t_print,               \
+                sizeof(vl_api_##n##_t), 1);
+        foreach_api_reply_handler;
+    #undef _
+}
+
+JNIEXPORT void JNICALL Java_org_openvpp_jvpp_core_JVppCoreImpl_close0
+(JNIEnv *env, jclass clazz) {
+    core_main_t * plugin_main = &core_main;
+
+    // cleanup:
+    (*env)->DeleteGlobalRef(env, plugin_main->callbackClass);
+    (*env)->DeleteGlobalRef(env, plugin_main->callbackObject);
+
+    plugin_main->callbackClass = NULL;
+    plugin_main->callbackObject = NULL;
+}
+
+jint JNI_OnLoad(JavaVM *vm, void *reserved) {
+    JNIEnv* env;
+
+    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) {
+        return JNI_EVERSION;
+    }
+
+    if (cache_class_references(env) != 0) {
+        clib_warning ("Failed to cache class references\n");
+        return JNI_ERR;
+    }
+
+    return JNI_VERSION_1_8;
+}
+
+void JNI_OnUnload(JavaVM *vm, void *reserved) {
+    JNIEnv* env;
+    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) {
+        return;
+    }
+    delete_class_references(env);
+}
+
+
+
diff --git a/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackApiTest.java b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackApiTest.java
new file mode 100644
index 0000000..cfa2456
--- /dev/null
+++ b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackApiTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.core.test;
+
+import org.openvpp.jvpp.JVpp;
+import org.openvpp.jvpp.JVppRegistry;
+import org.openvpp.jvpp.JVppRegistryImpl;
+import org.openvpp.jvpp.VppCallbackException;
+import org.openvpp.jvpp.core.JVppCoreImpl;
+import org.openvpp.jvpp.core.callback.GetNodeIndexCallback;
+import org.openvpp.jvpp.core.callback.ShowVersionCallback;
+import org.openvpp.jvpp.core.callback.SwInterfaceCallback;
+import org.openvpp.jvpp.core.dto.GetNodeIndex;
+import org.openvpp.jvpp.core.dto.GetNodeIndexReply;
+import org.openvpp.jvpp.core.dto.ShowVersion;
+import org.openvpp.jvpp.core.dto.ShowVersionReply;
+import org.openvpp.jvpp.core.dto.SwInterfaceDetails;
+import org.openvpp.jvpp.core.dto.SwInterfaceDump;
+
+public class CallbackApiTest {
+
+    static class TestCallback implements GetNodeIndexCallback, ShowVersionCallback, SwInterfaceCallback {
+
+        @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 onSwInterfaceDetails(final SwInterfaceDetails msg) {
+            System.out.printf("Received SwInterfaceDetails: interfaceName=%s, l2AddressLength=%d, adminUpDown=%d, "
+                    + "linkUpDown=%d, linkSpeed=%d, linkMtu=%d\n",
+                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());
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        testCallbackApi();
+    }
+
+    private static void testCallbackApi() throws Exception {
+        System.out.println("Testing Java callback API with JVppRegistry");
+        JVppRegistry registry = new JVppRegistryImpl("CallbackApiTest");
+        JVpp jvpp = new JVppCoreImpl();
+
+        registry.register(jvpp, new TestCallback());
+
+        System.out.println("Sending ShowVersion request...");
+        final int result = jvpp.send(new ShowVersion());
+        System.out.printf("ShowVersion send result = %d\n", result);
+
+        System.out.println("Sending GetNodeIndex request...");
+        GetNodeIndex getNodeIndexRequest = new GetNodeIndex();
+        getNodeIndexRequest.nodeName = "non-existing-node".getBytes();
+        jvpp.send(getNodeIndexRequest);
+
+        System.out.println("Sending SwInterfaceDump request...");
+        SwInterfaceDump swInterfaceDumpRequest = new SwInterfaceDump();
+        swInterfaceDumpRequest.nameFilterValid = 0;
+        swInterfaceDumpRequest.nameFilter = "".getBytes();
+        jvpp.send(swInterfaceDumpRequest);
+
+        Thread.sleep(1000);
+
+        System.out.println("Disconnecting...");
+        registry.close();
+        Thread.sleep(1000);
+    }
+}
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackJVppFacadeNotificationTest.java b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackJVppFacadeNotificationTest.java
similarity index 81%
rename from vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackJVppFacadeNotificationTest.java
rename to vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackJVppFacadeNotificationTest.java
index 430ce88..542a561 100644
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackJVppFacadeNotificationTest.java
+++ b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackJVppFacadeNotificationTest.java
@@ -14,24 +14,26 @@
  * limitations under the License.
  */
 
-package org.openvpp.jvpp.test;
+package org.openvpp.jvpp.core.test;
 
-import org.openvpp.jvpp.JVpp;
-import org.openvpp.jvpp.JVppImpl;
+import org.openvpp.jvpp.JVppRegistry;
+import org.openvpp.jvpp.JVppRegistryImpl;
 import org.openvpp.jvpp.VppCallbackException;
-import org.openvpp.jvpp.VppJNIConnection;
-import org.openvpp.jvpp.callback.WantInterfaceEventsCallback;
-import org.openvpp.jvpp.callfacade.CallbackJVppFacade;
-import org.openvpp.jvpp.dto.WantInterfaceEventsReply;
+import org.openvpp.jvpp.core.JVppCore;
+import org.openvpp.jvpp.core.JVppCoreImpl;
+import org.openvpp.jvpp.core.callback.WantInterfaceEventsCallback;
+import org.openvpp.jvpp.core.callfacade.CallbackJVppCoreFacade;
+import org.openvpp.jvpp.core.dto.WantInterfaceEventsReply;
 
 public class CallbackJVppFacadeNotificationTest {
 
     private static void testCallbackFacade() throws Exception {
         System.out.println("Testing CallbackJVppFacade for notifications");
 
-        JVpp jvpp = new JVppImpl(new VppJNIConnection("CallbackApiTest"));
+        final JVppRegistry registry = new JVppRegistryImpl("CallbackFacadeTest");
+        final JVppCore jvpp = new JVppCoreImpl();
 
-        CallbackJVppFacade jvppCallbackFacade = new CallbackJVppFacade(jvpp);
+        CallbackJVppCoreFacade jvppCallbackFacade = new CallbackJVppCoreFacade(registry, jvpp);
         System.out.println("Successfully connected to VPP");
 
         final AutoCloseable notificationListenerReg =
@@ -77,7 +79,7 @@
         Thread.sleep(2000);
 
         System.out.println("Disconnecting...");
-        jvpp.close();
+        registry.close();
         Thread.sleep(1000);
     }
 
diff --git a/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackJVppFacadeTest.java b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackJVppFacadeTest.java
new file mode 100644
index 0000000..7499502
--- /dev/null
+++ b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackJVppFacadeTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.core.test;
+
+import org.openvpp.jvpp.JVppRegistry;
+import org.openvpp.jvpp.JVppRegistryImpl;
+import org.openvpp.jvpp.VppCallbackException;
+import org.openvpp.jvpp.core.JVppCore;
+import org.openvpp.jvpp.core.JVppCoreImpl;
+import org.openvpp.jvpp.core.callback.GetNodeIndexCallback;
+import org.openvpp.jvpp.core.callback.ShowVersionCallback;
+import org.openvpp.jvpp.core.callfacade.CallbackJVppCoreFacade;
+import org.openvpp.jvpp.core.dto.GetNodeIndex;
+import org.openvpp.jvpp.core.dto.GetNodeIndexReply;
+import org.openvpp.jvpp.core.dto.ShowVersionReply;
+
+/**
+ * CallbackJVppFacade together with CallbackJVppFacadeCallback allow for setting different callback for each request.
+ * This is more convenient than the approach shown in CallbackApiTest.
+ */
+public class CallbackJVppFacadeTest {
+
+    private static ShowVersionCallback 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 ShowVersionCallback showVersionCallback2 = new ShowVersionCallback() {
+        @Override
+        public void onShowVersionReply(final ShowVersionReply msg) {
+            System.out.printf("ShowVersionCallback2 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());
+        }
+
+    };
+
+    private static GetNodeIndexCallback 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());
+        }
+    };
+
+    private static void testCallbackFacade() throws Exception {
+        System.out.println("Testing CallbackJVppFacade");
+
+        final JVppRegistry registry = new JVppRegistryImpl("CallbackFacadeTest");
+        final JVppCore jvpp = new JVppCoreImpl();
+
+        CallbackJVppCoreFacade jvppCallbackFacade = new CallbackJVppCoreFacade(registry, jvpp);
+        System.out.println("Successfully connected to VPP");
+
+        jvppCallbackFacade.showVersion(showVersionCallback1);
+        jvppCallbackFacade.showVersion(showVersionCallback2);
+
+        GetNodeIndex getNodeIndexRequest = new GetNodeIndex();
+        getNodeIndexRequest.nodeName = "dummyNode".getBytes();
+        jvppCallbackFacade.getNodeIndex(getNodeIndexRequest, getNodeIndexCallback);
+
+        Thread.sleep(2000);
+
+        System.out.println("Disconnecting...");
+        registry.close();
+        Thread.sleep(1000);
+    }
+
+    public static void main(String[] args) throws Exception {
+        testCallbackFacade();
+    }
+}
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackNotificationApiTest.java b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackNotificationApiTest.java
similarity index 69%
rename from vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackNotificationApiTest.java
rename to vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackNotificationApiTest.java
index 5bf2b21..a11cce6 100644
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackNotificationApiTest.java
+++ b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackNotificationApiTest.java
@@ -14,23 +14,24 @@
  * limitations under the License.
  */
 
-package org.openvpp.jvpp.test;
+package org.openvpp.jvpp.core.test;
 
-import static org.openvpp.jvpp.test.NotificationUtils.getChangeInterfaceState;
-import static org.openvpp.jvpp.test.NotificationUtils.getDisableInterfaceNotificationsReq;
-import static org.openvpp.jvpp.test.NotificationUtils.getEnableInterfaceNotificationsReq;
-import static org.openvpp.jvpp.test.NotificationUtils.printNotification;
+import static org.openvpp.jvpp.core.test.NotificationUtils.getChangeInterfaceState;
+import static org.openvpp.jvpp.core.test.NotificationUtils.getDisableInterfaceNotificationsReq;
+import static org.openvpp.jvpp.core.test.NotificationUtils.getEnableInterfaceNotificationsReq;
+import static org.openvpp.jvpp.core.test.NotificationUtils.printNotification;
 
 import org.openvpp.jvpp.JVpp;
-import org.openvpp.jvpp.JVppImpl;
+import org.openvpp.jvpp.JVppRegistry;
+import org.openvpp.jvpp.JVppRegistryImpl;
 import org.openvpp.jvpp.VppCallbackException;
-import org.openvpp.jvpp.VppJNIConnection;
-import org.openvpp.jvpp.callback.SwInterfaceSetFlagsCallback;
-import org.openvpp.jvpp.callback.SwInterfaceSetFlagsNotificationCallback;
-import org.openvpp.jvpp.callback.WantInterfaceEventsCallback;
-import org.openvpp.jvpp.dto.SwInterfaceSetFlagsNotification;
-import org.openvpp.jvpp.dto.SwInterfaceSetFlagsReply;
-import org.openvpp.jvpp.dto.WantInterfaceEventsReply;
+import org.openvpp.jvpp.core.JVppCoreImpl;
+import org.openvpp.jvpp.core.callback.SwInterfaceSetFlagsCallback;
+import org.openvpp.jvpp.core.callback.SwInterfaceSetFlagsNotificationCallback;
+import org.openvpp.jvpp.core.callback.WantInterfaceEventsCallback;
+import org.openvpp.jvpp.core.dto.SwInterfaceSetFlagsNotification;
+import org.openvpp.jvpp.core.dto.SwInterfaceSetFlagsReply;
+import org.openvpp.jvpp.core.dto.WantInterfaceEventsReply;
 
 public class CallbackNotificationApiTest {
 
@@ -63,8 +64,10 @@
 
     private static void testCallbackApi() throws Exception {
         System.out.println("Testing Java callback API for notifications");
-        JVpp jvpp = new JVppImpl( new VppJNIConnection("CallbackApiTest"));
-        jvpp.connect( new TestCallback());
+        JVppRegistry registry = new JVppRegistryImpl("CallbackNotificationTest");
+        JVpp jvpp = new JVppCoreImpl();
+
+        registry.register(jvpp, new TestCallback());
         System.out.println("Successfully connected to VPP");
 
         getEnableInterfaceNotificationsReq().send(jvpp);
@@ -74,7 +77,7 @@
         System.out.println("Changing interface configuration");
         getChangeInterfaceState().send(jvpp);
 
-        // Notification is received
+        // Notifications are received
         Thread.sleep(500);
 
         getDisableInterfaceNotificationsReq().send(jvpp);
@@ -83,7 +86,7 @@
         Thread.sleep(2000);
 
         System.out.println("Disconnecting...");
-        jvpp.close();
+        registry.close();
         Thread.sleep(1000);
     }
 
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/test/ControlPingTest.java b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/ControlPingTest.java
similarity index 69%
rename from vpp-api/java/jvpp/org/openvpp/jvpp/test/ControlPingTest.java
rename to vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/ControlPingTest.java
index 514bb3e..12ded2e 100644
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/ControlPingTest.java
+++ b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/ControlPingTest.java
@@ -14,12 +14,13 @@
  * limitations under the License.
  */
 
-package org.openvpp.jvpp.test;
+package org.openvpp.jvpp.core.test;
 
 import org.openvpp.jvpp.JVpp;
-import org.openvpp.jvpp.JVppImpl;
+import org.openvpp.jvpp.JVppRegistry;
+import org.openvpp.jvpp.JVppRegistryImpl;
 import org.openvpp.jvpp.VppCallbackException;
-import org.openvpp.jvpp.VppJNIConnection;
+import org.openvpp.jvpp.core.JVppCoreImpl;
 import org.openvpp.jvpp.callback.ControlPingCallback;
 import org.openvpp.jvpp.dto.ControlPing;
 import org.openvpp.jvpp.dto.ControlPingReply;
@@ -28,30 +29,38 @@
 
     private static void testControlPing() throws Exception {
         System.out.println("Testing ControlPing using Java callback API");
+        JVppRegistry registry = new JVppRegistryImpl("ControlPingTest");
+        JVpp jvpp = new JVppCoreImpl();
 
-        JVpp jvpp = new JVppImpl( new VppJNIConnection("ControlPingTest"));
-        jvpp.connect( new ControlPingCallback() {
+        registry.register(jvpp, new ControlPingCallback() {
             @Override
             public void onControlPingReply(final ControlPingReply reply) {
                 System.out.printf("Received ControlPingReply: context=%d, clientIndex=%d vpePid=%d\n",
-                        reply.context, reply.clientIndex, reply.vpePid);
+                    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.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);
 
+        System.out.println("Sending control ping using JVppRegistry");
+        registry.controlPing(jvpp.getClass());
+
+        Thread.sleep(2000);
+
+        System.out.println("Sending control ping using JVpp plugin");
         jvpp.send(new ControlPing());
 
         Thread.sleep(2000);
 
         System.out.println("Disconnecting...");
-        jvpp.close();
+        registry.close();
         Thread.sleep(1000);
     }
 
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/test/CreateSubInterfaceTest.java b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CreateSubInterfaceTest.java
similarity index 71%
rename from vpp-api/java/jvpp/org/openvpp/jvpp/test/CreateSubInterfaceTest.java
rename to vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CreateSubInterfaceTest.java
index b3dc1f4..9719a8c 100644
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/CreateSubInterfaceTest.java
+++ b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CreateSubInterfaceTest.java
@@ -14,18 +14,20 @@
  * limitations under the License.
  */
 
-package org.openvpp.jvpp.test;
-
-import org.openvpp.jvpp.JVppImpl;
-import org.openvpp.jvpp.VppJNIConnection;
-import org.openvpp.jvpp.dto.CreateSubif;
-import org.openvpp.jvpp.dto.CreateSubifReply;
-import org.openvpp.jvpp.dto.SwInterfaceDetailsReplyDump;
-import org.openvpp.jvpp.dto.SwInterfaceDump;
-import org.openvpp.jvpp.future.FutureJVppFacade;
+package org.openvpp.jvpp.core.test;
 
 import static java.util.Objects.requireNonNull;
 
+import org.openvpp.jvpp.JVpp;
+import org.openvpp.jvpp.JVppRegistry;
+import org.openvpp.jvpp.JVppRegistryImpl;
+import org.openvpp.jvpp.core.JVppCoreImpl;
+import org.openvpp.jvpp.core.dto.CreateSubif;
+import org.openvpp.jvpp.core.dto.CreateSubifReply;
+import org.openvpp.jvpp.core.dto.SwInterfaceDetailsReplyDump;
+import org.openvpp.jvpp.core.dto.SwInterfaceDump;
+import org.openvpp.jvpp.core.future.FutureJVppCoreFacade;
+
 /**
  * <p>Tests sub-interface creation.<br> Equivalent to:<br>
  *
@@ -42,7 +44,6 @@
  */
 public class CreateSubInterfaceTest {
 
-
     private static SwInterfaceDump createSwInterfaceDumpRequest(final String ifaceName) {
         SwInterfaceDump request = new SwInterfaceDump();
         request.nameFilter = ifaceName.getBytes();
@@ -53,8 +54,8 @@
     private static void requireSingleIface(final SwInterfaceDetailsReplyDump response, final String ifaceName) {
         if (response.swInterfaceDetails.size() != 1) {
             throw new IllegalStateException(
-                    String.format("Expected one interface matching filter %s but was %d", ifaceName,
-                            response.swInterfaceDetails.size()));
+                String.format("Expected one interface matching filter %s but was %d", ifaceName,
+                    response.swInterfaceDetails.size()));
         }
     }
 
@@ -76,23 +77,22 @@
     }
 
     private static void print(CreateSubifReply reply) {
-        System.out.printf("CreateSubifReply: context=%d, swIfIndex=%d\n",
-                reply.context,
-                reply.swIfIndex);
+        System.out.printf("CreateSubifReply: context=%d, swIfIndex=%d\n", reply.context, reply.swIfIndex);
     }
 
     private static void testCreateSubInterface() throws Exception {
         System.out.println("Testing sub-interface creation using Java callback API");
-        final JVppImpl jvpp = new JVppImpl(new VppJNIConnection("SubIfaceTest"));
-        final FutureJVppFacade jvppFacade = new FutureJVppFacade(jvpp);
+        final JVppRegistry registry = new JVppRegistryImpl("CreateSubInterface");
+        final JVpp jvpp = new JVppCoreImpl();
+        final FutureJVppCoreFacade jvppFacade = new FutureJVppCoreFacade(registry, jvpp);
 
         System.out.println("Successfully connected to VPP");
         Thread.sleep(1000);
 
-        final String ifaceName = "GigabitEthernet0/9/0";
+        final String ifaceName = "GigabitEthernet0/8/0";
 
         final SwInterfaceDetailsReplyDump swInterfaceDetails =
-                jvppFacade.swInterfaceDump(createSwInterfaceDumpRequest(ifaceName)).toCompletableFuture().get();
+            jvppFacade.swInterfaceDump(createSwInterfaceDumpRequest(ifaceName)).toCompletableFuture().get();
 
         requireNonNull(swInterfaceDetails, "swInterfaceDump returned null");
         requireNonNull(swInterfaceDetails.swInterfaceDetails, "swInterfaceDetails is null");
@@ -102,18 +102,18 @@
         final int subId = 1;
 
         final CreateSubifReply createSubifReply =
-                jvppFacade.createSubif(createSubifRequest(swIfIndex, subId)).toCompletableFuture().get();
+            jvppFacade.createSubif(createSubifRequest(swIfIndex, subId)).toCompletableFuture().get();
         print(createSubifReply);
 
-        final String subIfaceName = "GigabitEthernet0/9/0." + subId;
+        final String subIfaceName = "GigabitEthernet0/8/0." + subId;
         final SwInterfaceDetailsReplyDump subIface =
-                jvppFacade.swInterfaceDump(createSwInterfaceDumpRequest(subIfaceName)).toCompletableFuture().get();
+            jvppFacade.swInterfaceDump(createSwInterfaceDumpRequest(subIfaceName)).toCompletableFuture().get();
         requireNonNull(swInterfaceDetails, "swInterfaceDump returned null");
         requireNonNull(subIface.swInterfaceDetails, "swInterfaceDump returned null");
         requireSingleIface(swInterfaceDetails, ifaceName);
 
         System.out.println("Disconnecting...");
-        jvpp.close();
+        registry.close();
         Thread.sleep(1000);
     }
 
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/test/FutureApiNotificationTest.java b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/FutureApiNotificationTest.java
similarity index 63%
rename from vpp-api/java/jvpp/org/openvpp/jvpp/test/FutureApiNotificationTest.java
rename to vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/FutureApiNotificationTest.java
index c48f86d..2decf6e 100644
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/FutureApiNotificationTest.java
+++ b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/FutureApiNotificationTest.java
@@ -14,27 +14,32 @@
  * limitations under the License.
  */
 
-package org.openvpp.jvpp.test;
+package org.openvpp.jvpp.core.test;
 
-import static org.openvpp.jvpp.test.NotificationUtils.getChangeInterfaceState;
-import static org.openvpp.jvpp.test.NotificationUtils.getDisableInterfaceNotificationsReq;
-import static org.openvpp.jvpp.test.NotificationUtils.getEnableInterfaceNotificationsReq;
+import static org.openvpp.jvpp.core.test.NotificationUtils.getChangeInterfaceState;
+import static org.openvpp.jvpp.core.test.NotificationUtils.getDisableInterfaceNotificationsReq;
+import static org.openvpp.jvpp.core.test.NotificationUtils.getEnableInterfaceNotificationsReq;
 
-import org.openvpp.jvpp.VppJNIConnection;
-import org.openvpp.jvpp.future.FutureJVppFacade;
+import org.openvpp.jvpp.JVpp;
+import org.openvpp.jvpp.JVppRegistry;
+import org.openvpp.jvpp.JVppRegistryImpl;
+import org.openvpp.jvpp.core.JVppCoreImpl;
+import org.openvpp.jvpp.core.future.FutureJVppCoreFacade;
 
 public class FutureApiNotificationTest {
 
     private static void testFutureApi() throws Exception {
         System.out.println("Testing Java future API for notifications");
 
-        final org.openvpp.jvpp.JVppImpl impl =
-                new org.openvpp.jvpp.JVppImpl(new VppJNIConnection("FutureApiTest"));
-        final FutureJVppFacade jvppFacade = new FutureJVppFacade(impl);
+        final JVppRegistry registry = new JVppRegistryImpl("FutureApiNotificationTest");
+        final JVpp jvpp = new JVppCoreImpl();
+        final FutureJVppCoreFacade jvppFacade = new FutureJVppCoreFacade(registry, jvpp);
+
         System.out.println("Successfully connected to VPP");
 
         final AutoCloseable notificationListenerReg =
-            jvppFacade.getNotificationRegistry().registerSwInterfaceSetFlagsNotificationCallback(NotificationUtils::printNotification);
+            jvppFacade.getNotificationRegistry()
+                .registerSwInterfaceSetFlagsNotificationCallback(NotificationUtils::printNotification);
 
         jvppFacade.wantInterfaceEvents(getEnableInterfaceNotificationsReq()).toCompletableFuture().get();
         System.out.println("Interface events started");
@@ -50,8 +55,7 @@
         notificationListenerReg.close();
 
         System.out.println("Disconnecting...");
-        // TODO we should consider adding jvpp.close(); to the facade
-        impl.close();
+        registry.close();
     }
 
     public static void main(String[] args) throws Exception {
diff --git a/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/FutureApiTest.java b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/FutureApiTest.java
new file mode 100644
index 0000000..7a67173
--- /dev/null
+++ b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/FutureApiTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.core.test;
+
+import java.util.Objects;
+import java.util.concurrent.Future;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.openvpp.jvpp.JVpp;
+import org.openvpp.jvpp.JVppRegistry;
+import org.openvpp.jvpp.JVppRegistryImpl;
+import org.openvpp.jvpp.core.JVppCoreImpl;
+import org.openvpp.jvpp.core.dto.GetNodeIndex;
+import org.openvpp.jvpp.core.dto.GetNodeIndexReply;
+import org.openvpp.jvpp.core.dto.ShowVersion;
+import org.openvpp.jvpp.core.dto.ShowVersionReply;
+import org.openvpp.jvpp.core.dto.SwInterfaceDetails;
+import org.openvpp.jvpp.core.dto.SwInterfaceDetailsReplyDump;
+import org.openvpp.jvpp.core.dto.SwInterfaceDump;
+import org.openvpp.jvpp.core.future.FutureJVppCoreFacade;
+
+public class FutureApiTest {
+
+    private static final Logger LOG = Logger.getLogger(FutureApiTest.class.getName());
+
+    private static void testShowVersion(final FutureJVppCoreFacade jvpp) throws Exception {
+        LOG.info("Sending ShowVersion request...");
+        final Future<ShowVersionReply> replyFuture = jvpp.showVersion(new ShowVersion()).toCompletableFuture();
+        final ShowVersionReply reply = replyFuture.get();
+        LOG.info(
+            String.format(
+                "Received ShowVersionReply: context=%d, program=%s, version=%s, buildDate=%s, buildDirectory=%s\n",
+                reply.context, new String(reply.program), new String(reply.version), new String(reply.buildDate),
+                new String(reply.buildDirectory)));
+    }
+
+    private static void testGetNodeIndex(final FutureJVppCoreFacade jvpp) {
+        LOG.info("Sending GetNodeIndex request...");
+        final GetNodeIndex request = new GetNodeIndex();
+        request.nodeName = "non-existing-node".getBytes();
+        final Future<GetNodeIndexReply> replyFuture = jvpp.getNodeIndex(request).toCompletableFuture();
+        try {
+            final GetNodeIndexReply reply = replyFuture.get();
+            LOG.info(
+                String.format(
+                    "Received GetNodeIndexReply: context=%d, nodeIndex=%d\n", reply.context, reply.nodeIndex));
+        } catch (Exception e) {
+            LOG.log(Level.SEVERE, "GetNodeIndex request failed", e);
+        }
+    }
+
+    private static void testSwInterfaceDump(final FutureJVppCoreFacade jvpp) throws Exception {
+        LOG.info("Sending SwInterfaceDump request...");
+        final SwInterfaceDump request = new SwInterfaceDump();
+        request.nameFilterValid = 0;
+        request.nameFilter = "".getBytes();
+
+        final Future<SwInterfaceDetailsReplyDump> replyFuture = jvpp.swInterfaceDump(request).toCompletableFuture();
+        final SwInterfaceDetailsReplyDump reply = replyFuture.get();
+        for (SwInterfaceDetails details : reply.swInterfaceDetails) {
+            Objects.requireNonNull(details, "reply.swInterfaceDetails contains null element!");
+            LOG.info(
+                String.format("Received SwInterfaceDetails: interfaceName=%s, l2AddressLength=%d, adminUpDown=%d, "
+                        + "linkUpDown=%d, linkSpeed=%d, linkMtu=%d\n",
+                    new String(details.interfaceName), details.l2AddressLength, details.adminUpDown,
+                    details.linkUpDown, details.linkSpeed, (int) details.linkMtu));
+        }
+    }
+
+    private static void testFutureApi() throws Exception {
+        LOG.info("Testing Java future API");
+
+        final JVppRegistry registry = new JVppRegistryImpl("FutureApiTest");
+        final JVpp jvpp = new JVppCoreImpl();
+        final FutureJVppCoreFacade jvppFacade = new FutureJVppCoreFacade(registry, jvpp);
+        LOG.info("Successfully connected to VPP");
+
+        testShowVersion(jvppFacade);
+        testGetNodeIndex(jvppFacade);
+        testSwInterfaceDump(jvppFacade);
+
+        LOG.info("Disconnecting...");
+        registry.close();
+    }
+
+    public static void main(String[] args) throws Exception {
+        testFutureApi();
+    }
+}
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/test/L2AclTest.java b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/L2AclTest.java
similarity index 84%
rename from vpp-api/java/jvpp/org/openvpp/jvpp/test/L2AclTest.java
rename to vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/L2AclTest.java
index 802df63..fc353f1 100644
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/L2AclTest.java
+++ b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/L2AclTest.java
@@ -14,28 +14,30 @@
  * limitations under the License.
  */
 
-package org.openvpp.jvpp.test;
+package org.openvpp.jvpp.core.test;
 
 import java.util.Arrays;
 import javax.xml.bind.DatatypeConverter;
-import org.openvpp.jvpp.JVppImpl;
-import org.openvpp.jvpp.VppJNIConnection;
-import org.openvpp.jvpp.dto.ClassifyAddDelSession;
-import org.openvpp.jvpp.dto.ClassifyAddDelSessionReply;
-import org.openvpp.jvpp.dto.ClassifyAddDelTable;
-import org.openvpp.jvpp.dto.ClassifyAddDelTableReply;
-import org.openvpp.jvpp.dto.ClassifySessionDetails;
-import org.openvpp.jvpp.dto.ClassifySessionDetailsReplyDump;
-import org.openvpp.jvpp.dto.ClassifySessionDump;
-import org.openvpp.jvpp.dto.ClassifyTableByInterface;
-import org.openvpp.jvpp.dto.ClassifyTableByInterfaceReply;
-import org.openvpp.jvpp.dto.ClassifyTableIds;
-import org.openvpp.jvpp.dto.ClassifyTableIdsReply;
-import org.openvpp.jvpp.dto.ClassifyTableInfo;
-import org.openvpp.jvpp.dto.ClassifyTableInfoReply;
-import org.openvpp.jvpp.dto.InputAclSetInterface;
-import org.openvpp.jvpp.dto.InputAclSetInterfaceReply;
-import org.openvpp.jvpp.future.FutureJVppFacade;
+import org.openvpp.jvpp.JVpp;
+import org.openvpp.jvpp.JVppRegistry;
+import org.openvpp.jvpp.JVppRegistryImpl;
+import org.openvpp.jvpp.core.JVppCoreImpl;
+import org.openvpp.jvpp.core.dto.ClassifyAddDelSession;
+import org.openvpp.jvpp.core.dto.ClassifyAddDelSessionReply;
+import org.openvpp.jvpp.core.dto.ClassifyAddDelTable;
+import org.openvpp.jvpp.core.dto.ClassifyAddDelTableReply;
+import org.openvpp.jvpp.core.dto.ClassifySessionDetails;
+import org.openvpp.jvpp.core.dto.ClassifySessionDetailsReplyDump;
+import org.openvpp.jvpp.core.dto.ClassifySessionDump;
+import org.openvpp.jvpp.core.dto.ClassifyTableByInterface;
+import org.openvpp.jvpp.core.dto.ClassifyTableByInterfaceReply;
+import org.openvpp.jvpp.core.dto.ClassifyTableIds;
+import org.openvpp.jvpp.core.dto.ClassifyTableIdsReply;
+import org.openvpp.jvpp.core.dto.ClassifyTableInfo;
+import org.openvpp.jvpp.core.dto.ClassifyTableInfoReply;
+import org.openvpp.jvpp.core.dto.InputAclSetInterface;
+import org.openvpp.jvpp.core.dto.InputAclSetInterfaceReply;
+import org.openvpp.jvpp.core.future.FutureJVppCoreFacade;
 
 /**
  * <p>Tests L2 ACL creation and read.<br> Equivalent to the following vppctl commands:<br>
@@ -111,8 +113,8 @@
     }
 
     private static void print(ClassifyAddDelTableReply reply) {
-        System.out.printf("ClassifyAddDelTableReply: context=%d, " +
-                "newTableIndex=%d, skipNVectors=%d, matchNVectors=%d\n",
+        System.out.printf("ClassifyAddDelTableReply: context=%d, "
+                + "newTableIndex=%d, skipNVectors=%d, matchNVectors=%d\n",
             reply.context, reply.newTableIndex, reply.skipNVectors, reply.matchNVectors);
     }
 
@@ -164,14 +166,15 @@
     }
 
     private static void print(final ClassifyTableByInterfaceReply reply) {
-        System.out.printf("ClassifyAddDelTableReply: context=%d, swIfIndex=%d, l2TableId=%d, ip4TableId=%d," +
-            "ip6TableId=%d\n", reply.context, reply.swIfIndex, reply.l2TableId, reply.ip4TableId, reply.ip6TableId);
+        System.out.printf("ClassifyAddDelTableReply: context=%d, swIfIndex=%d, l2TableId=%d, ip4TableId=%d,"
+            + "ip6TableId=%d\n", reply.context, reply.swIfIndex, reply.l2TableId, reply.ip4TableId, reply.ip6TableId);
     }
 
     private static void testL2Acl() throws Exception {
         System.out.println("Testing L2 ACLs using Java callback API");
-        final JVppImpl jvpp = new JVppImpl(new VppJNIConnection("L2AclTest"));
-        final FutureJVppFacade jvppFacade = new FutureJVppFacade(jvpp);
+        final JVppRegistry registry = new JVppRegistryImpl("L2AclTest");
+        final JVpp jvpp = new JVppCoreImpl();
+        final FutureJVppCoreFacade jvppFacade = new FutureJVppCoreFacade(registry, jvpp);
 
         System.out.println("Successfully connected to VPP");
         Thread.sleep(1000);
@@ -208,7 +211,7 @@
         print(classifyTableByInterfaceReply);
 
         System.out.println("Disconnecting...");
-        jvpp.close();
+        registry.close();
         Thread.sleep(1000);
     }
 
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/test/NotificationUtils.java b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/NotificationUtils.java
similarity index 60%
rename from vpp-api/java/jvpp/org/openvpp/jvpp/test/NotificationUtils.java
rename to vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/NotificationUtils.java
index 9c24d57..2e4d810 100644
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/NotificationUtils.java
+++ b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/NotificationUtils.java
@@ -1,9 +1,25 @@
-package org.openvpp.jvpp.test;
+/*
+ * 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.core.test;
 
 import java.io.PrintStream;
-import org.openvpp.jvpp.dto.SwInterfaceSetFlags;
-import org.openvpp.jvpp.dto.SwInterfaceSetFlagsNotification;
-import org.openvpp.jvpp.dto.WantInterfaceEvents;
+import org.openvpp.jvpp.core.dto.SwInterfaceSetFlags;
+import org.openvpp.jvpp.core.dto.SwInterfaceSetFlagsNotification;
+import org.openvpp.jvpp.core.dto.WantInterfaceEvents;
 
 final class NotificationUtils {
 
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/test/Readme.txt b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/Readme.txt
similarity index 83%
rename from vpp-api/java/jvpp/org/openvpp/jvpp/test/Readme.txt
rename to vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/Readme.txt
index e0aa4f4..016bde1 100644
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/Readme.txt
+++ b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/Readme.txt
@@ -2,16 +2,15 @@
 
 - Make sure VPP is running
 - From VPP's build-root/ folder execute:
-  - sudo java -cp build-vpp-native/vpp-api/java/jvpp-16.09.jar org.openvpp.jvpp.test.[test name]
+  - sudo java-cp build-vpp_debug-native/vpp-api/java/jvpp-registry-16.09.jar:build-vpp_debug-native/vpp-api/java/jvpp-core-16.09.jar org.openvpp.jvpp.core.test.[test name]
 
 Available tests:
-ControlPingTest - Simple test executing a single control ping using low level JVpp APIs
 CallbackApiTest - Similar to ControlPingTest, invokes more complex calls (e.g. interface dump) using low level JVpp APIs
-CallbackNotificationApiTest - Tests interface notifications using low level JVpp APIs
-FutureApiTest - Execution of more complex calls using Future based JVpp facade
-FutureApiNotificationTest - Tests interface notifications using Future based JVpp facade
-CallbackJVppFacadeTest - Execution of more complex calls using Callback based JVpp facade
 CallbackJVppFacadeNotificationTest - Tests interface notifications using Callback based JVpp facade
-L2AclTest - Tests L2 ACL creation
+CallbackJVppFacadeTest - Execution of more complex calls using Callback based JVpp facade
+CallbackNotificationApiTest - Tests interface notifications using low level JVpp APIs
+ControlPingTest - Simple test executing a single control ping using low level JVpp APIs
 CreateSubInterfaceTest - Tests sub-interface creation
-OnErrorCallbackTest - simple test failing with onError
+FutureApiNotificationTest - Tests interface notifications using Future based JVpp facade
+FutureApiTest - Execution of more complex calls using Future based JVpp facade
+L2AclTest - Tests L2 ACL creation
diff --git a/vpp-api/java/jvpp-registry/jvpp_registry.c b/vpp-api/java/jvpp-registry/jvpp_registry.c
new file mode 100644
index 0000000..1c9871b
--- /dev/null
+++ b/vpp-api/java/jvpp-registry/jvpp_registry.c
@@ -0,0 +1,349 @@
+/*
+ * 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.
+ */
+#define _GNU_SOURCE /* for strcasestr(3) */
+#include <vnet/vnet.h>
+
+#define vl_api_version(n,v) static u32 vpe_api_version = (v);
+#include <vpp-api/vpe.api.h>
+#undef vl_api_version
+
+#include <jni.h>
+#include <jvpp-common/jvpp_common.h>
+#include "org_openvpp_jvpp_VppJNIConnection.h"
+#include "org_openvpp_jvpp_JVppRegistryImpl.h"
+
+#include <vpp-api/vpe_msg_enum.h>
+#define vl_typedefs             /* define message structures */
+#include <vpp-api/vpe_all_api_h.h>
+#undef vl_typedefs
+
+#define vl_endianfun
+#include <vpp-api/vpe_all_api_h.h>
+#undef vl_endianfun
+
+/* instantiate all the print functions we know about */
+#define vl_print(handle, ...)
+#define vl_printfun
+#include <vpp-api/vpe_all_api_h.h>
+#undef vl_printfun
+
+/*
+ * The Java runtime isn't compile w/ -fstack-protector,
+ * so we have to supply missing external references for the
+ * regular vpp libraries.
+ */
+void __stack_chk_guard(void) __attribute__((weak));
+void __stack_chk_guard(void) {
+}
+
+typedef struct {
+    /* UThread attachment */
+    volatile u32 control_ping_result_ready;
+    volatile i32 control_ping_retval;
+
+    /* Control poing callback */
+    jobject registryObject;
+    jclass registryClass;
+    jclass controlPingReplyClass;
+    jclass callbackExceptionClass;
+
+    /* Thread cleanup */
+    pthread_key_t cleanup_rx_thread_key;
+
+    /* Connected indication */
+    volatile u8 is_connected;
+} jvpp_registry_main_t;
+
+jvpp_registry_main_t jvpp_registry_main __attribute__((aligned (64)));
+
+void vl_client_add_api_signatures(vl_api_memclnt_create_t *mp) {
+    /*
+     * Send the main API signature in slot 0. This bit of code must
+     * match the checks in ../vpe/api/api.c: vl_msg_api_version_check().
+     */
+    mp->api_versions[0] = clib_host_to_net_u32(vpe_api_version);
+}
+
+/* cleanup handler for RX thread */
+static_always_inline void cleanup_rx_thread(void *arg) {
+    jvpp_main_t * jm = &jvpp_main;
+    jvpp_registry_main_t * rm = &jvpp_registry_main;
+
+    vppjni_lock(jm, 99);
+
+    int getEnvStat = (*jm->jvm)->GetEnv(jm->jvm, (void **) &(jm->jenv),
+    JNI_VERSION_1_8);
+    if (getEnvStat == JNI_EVERSION) {
+        clib_warning("Unsupported JNI version\n");
+        rm->control_ping_retval = VNET_API_ERROR_UNSUPPORTED_JNI_VERSION;
+        goto out;
+    } else if (getEnvStat != JNI_EDETACHED) {
+        (*jm->jvm)->DetachCurrentThread(jm->jvm);
+    }
+    out: vppjni_unlock(jm);
+}
+
+static void vl_api_control_ping_reply_t_handler(
+        vl_api_control_ping_reply_t * mp) {
+    jvpp_main_t * jm = &jvpp_main;
+    jvpp_registry_main_t * rm = &jvpp_registry_main;
+    char was_thread_connected = 0;
+
+    // attach to java thread if not attached
+    int getEnvStat = (*jm->jvm)->GetEnv(jm->jvm, (void **) &(jm->jenv),
+            JNI_VERSION_1_8);
+    if (getEnvStat == JNI_EDETACHED) {
+        if ((*jm->jvm)->AttachCurrentThread(jm->jvm, (void **) &(jm->jenv),
+                NULL) != 0) {
+            clib_warning("Failed to attach thread\n");
+            rm->control_ping_retval =
+                    VNET_API_ERROR_FAILED_TO_ATTACH_TO_JAVA_THREAD;
+            goto out;
+        }
+
+        // workaround as we can't use pthread_cleanup_push
+        pthread_key_create(&rm->cleanup_rx_thread_key, cleanup_rx_thread);
+        // destructor is only called if the value of key is non null
+        pthread_setspecific(rm->cleanup_rx_thread_key, (void *) 1);
+        was_thread_connected = 1;
+    } else if (getEnvStat == JNI_EVERSION) {
+        clib_warning("Unsupported JNI version\n");
+        rm->control_ping_retval = VNET_API_ERROR_UNSUPPORTED_JNI_VERSION;
+        goto out;
+    }
+
+    if (was_thread_connected == 0) {
+        JNIEnv *env = jm->jenv;
+        if (mp->retval < 0) {
+            call_on_error("controlPing", mp->context, mp->retval,
+                    rm->registryClass, rm->registryObject,
+                    rm->callbackExceptionClass);
+        } else {
+            jmethodID constructor = (*env)->GetMethodID(env,
+                    rm->controlPingReplyClass, "<init>", "()V");
+            jmethodID callbackMethod = (*env)->GetMethodID(env,
+                    rm->registryClass, "onControlPingReply",
+                    "(Lorg/openvpp/jvpp/dto/ControlPingReply;)V");
+
+            jobject dto = (*env)->NewObject(env, rm->controlPingReplyClass,
+                    constructor);
+
+            jfieldID contextFieldId = (*env)->GetFieldID(env,
+                    rm->controlPingReplyClass, "context", "I");
+            (*env)->SetIntField(env, dto, contextFieldId,
+                    clib_net_to_host_u32(mp->context));
+
+            jfieldID clientIndexFieldId = (*env)->GetFieldID(env,
+                    rm->controlPingReplyClass, "clientIndex", "I");
+            (*env)->SetIntField(env, dto, clientIndexFieldId,
+                    clib_net_to_host_u32(mp->client_index));
+
+            jfieldID vpePidFieldId = (*env)->GetFieldID(env,
+                    rm->controlPingReplyClass, "vpePid", "I");
+            (*env)->SetIntField(env, dto, vpePidFieldId,
+                    clib_net_to_host_u32(mp->vpe_pid));
+
+            (*env)->CallVoidMethod(env, rm->registryObject, callbackMethod,
+                    dto);
+        }
+    }
+
+    out: rm->control_ping_result_ready = 1;
+}
+
+static int send_initial_control_ping() {
+    f64 timeout;
+    clib_time_t clib_time;
+    vl_api_control_ping_t * mp;
+    jvpp_main_t * jm = &jvpp_main;
+    jvpp_registry_main_t * rm = &jvpp_registry_main;
+
+    clib_time_init(&clib_time);
+
+    rm->control_ping_result_ready = 0;
+    mp = vl_msg_api_alloc(sizeof(*mp));
+    memset(mp, 0, sizeof(*mp));
+    mp->_vl_msg_id = ntohs(VL_API_CONTROL_PING);
+    mp->client_index = jm->my_client_index;
+
+    // send message:
+    vl_msg_api_send_shmem(jm->vl_input_queue, (u8 *) &mp);
+
+    // wait for results: Current time + 10 seconds is the timeout
+    timeout = clib_time_now(&clib_time) + 10.0;
+    int rv = VNET_API_ERROR_RESPONSE_NOT_READY;
+    while (clib_time_now(&clib_time) < timeout) {
+        if (rm->control_ping_result_ready == 1) {
+            rv = rm->control_ping_retval;
+            break;
+        }
+    }
+
+    if (rv != 0) {
+        clib_warning("common: first control ping failed: %d", rv);
+    }
+
+    return rv;
+}
+
+static int connect_to_vpe(char *name) {
+    jvpp_main_t * jm = &jvpp_main;
+    api_main_t * am = &api_main;
+
+    if (vl_client_connect_to_vlib("/vpe-api", name, 32) < 0)
+        return -1;
+
+    jm->my_client_index = am->my_client_index;
+
+    jm->vl_input_queue = am->shmem_hdr->vl_input_queue;
+
+    vl_msg_api_set_handlers(VL_API_CONTROL_PING_REPLY, "control_ping_reply",
+            vl_api_control_ping_reply_t_handler, vl_noop_handler,
+            vl_api_control_ping_reply_t_endian,
+            vl_api_control_ping_reply_t_print,
+            sizeof(vl_api_control_ping_reply_t), 1);
+
+    send_initial_control_ping();
+
+    return 0;
+}
+
+JNIEXPORT jobject JNICALL Java_org_openvpp_jvpp_VppJNIConnection_clientConnect(
+        JNIEnv *env, jclass obj, jstring clientName) {
+    int rv;
+    const char *client_name;
+    void vl_msg_reply_handler_hookup(void);
+    jvpp_main_t * jm = &jvpp_main;
+    jvpp_registry_main_t * rm = &jvpp_registry_main;
+
+    jclass connectionInfoClass = (*env)->FindClass(env,
+            "org/openvpp/jvpp/VppJNIConnection$ConnectionInfo");
+    jmethodID connectionInfoConstructor = (*env)->GetMethodID(env,
+            connectionInfoClass, "<init>", "(JII)V");
+
+    /*
+     * Bail out now if we're not running as root
+     */
+    if (geteuid() != 0) {
+        return (*env)->NewObject(env, connectionInfoClass,
+                connectionInfoConstructor, 0, 0,
+                VNET_API_ERROR_NOT_RUNNING_AS_ROOT);
+    }
+
+    if (rm->is_connected) {
+        return (*env)->NewObject(env, connectionInfoClass,
+                connectionInfoConstructor, 0, 0,
+                VNET_API_ERROR_ALREADY_CONNECTED);
+    }
+
+    client_name = (*env)->GetStringUTFChars(env, clientName, 0);
+    if (!client_name) {
+        return (*env)->NewObject(env, connectionInfoClass,
+                connectionInfoConstructor, 0, 0, VNET_API_ERROR_INVALID_VALUE);
+    }
+
+    rv = connect_to_vpe((char *) client_name);
+
+    if (rv < 0)
+        clib_warning("connection failed, rv %d", rv);
+
+    (*env)->ReleaseStringUTFChars(env, clientName, client_name);
+
+    return (*env)->NewObject(env, connectionInfoClass,
+            connectionInfoConstructor, (jlong) jm->vl_input_queue,
+            (jint) jm->my_client_index, (jint) rv);
+}
+
+JNIEXPORT jint JNICALL Java_org_openvpp_jvpp_JVppRegistryImpl_controlPing0(
+        JNIEnv *env, jobject regstryObject) {
+    jvpp_main_t * jm = &jvpp_main;
+    vl_api_control_ping_t * mp;
+    u32 my_context_id = vppjni_get_context_id(&jvpp_main);
+    jvpp_registry_main_t * rm = &jvpp_registry_main;
+
+    if (rm->registryObject == 0) {
+        rm->registryObject = (*env)->NewGlobalRef(env, regstryObject);
+    }
+    if (rm->registryClass == 0) {
+        rm->registryClass = (jclass) (*env)->NewGlobalRef(env,
+                (*env)->GetObjectClass(env, regstryObject));
+    }
+
+    mp = vl_msg_api_alloc(sizeof(*mp));
+    memset(mp, 0, sizeof(*mp));
+    mp->_vl_msg_id = ntohs(VL_API_CONTROL_PING);
+    mp->client_index = jm->my_client_index;
+    mp->context = clib_host_to_net_u32(my_context_id);
+
+    // send message:
+    vl_msg_api_send_shmem(jm->vl_input_queue, (u8 *) &mp);
+    return my_context_id;
+}
+
+JNIEXPORT void JNICALL Java_org_openvpp_jvpp_VppJNIConnection_clientDisconnect(
+        JNIEnv *env, jclass clazz) {
+    jvpp_registry_main_t * rm = &jvpp_registry_main;
+    rm->is_connected = 0; // TODO make thread safe
+    vl_client_disconnect_from_vlib();
+
+    // cleanup:
+    if (rm->registryObject) {
+        (*env)->DeleteGlobalRef(env, rm->registryObject);
+        rm->registryObject = 0;
+    }
+    if (rm->registryClass) {
+        (*env)->DeleteGlobalRef(env, rm->registryClass);
+        rm->registryClass = 0;
+    }
+}
+
+jint JNI_OnLoad(JavaVM *vm, void *reserved) {
+    jvpp_main_t * jm = &jvpp_main;
+    jvpp_registry_main_t * rm = &jvpp_registry_main;
+    JNIEnv* env;
+
+    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) {
+        return JNI_EVERSION;
+    }
+
+    rm->controlPingReplyClass = (jclass) (*env)->NewGlobalRef(env,
+            (*env)->FindClass(env, "org/openvpp/jvpp/dto/ControlPingReply"));
+    if ((*env)->ExceptionCheck(env)) {
+        (*env)->ExceptionDescribe(env);
+        clib_warning("Failed to cache class references\n");
+        return JNI_ERR;
+    }
+
+    rm->callbackExceptionClass = (jclass) (*env)->NewGlobalRef(env,
+            (*env)->FindClass(env, "org/openvpp/jvpp/VppCallbackException"));
+    if ((*env)->ExceptionCheck(env)) {
+        (*env)->ExceptionDescribe(env);
+        return JNI_ERR;
+    }
+
+    jm->jvm = vm;
+    return JNI_VERSION_1_8;
+}
+
+void JNI_OnUnload(JavaVM *vm, void *reserved) {
+    jvpp_main_t * jm = &jvpp_main;
+    JNIEnv* env;
+    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) {
+        return;
+    }
+
+    jm->jenv = NULL;
+    jm->jvm = NULL;
+}
diff --git a/vpp-api/java/jvpp-registry/org/openvpp/jvpp/JVpp.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/JVpp.java
new file mode 100644
index 0000000..53bae04
--- /dev/null
+++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/JVpp.java
@@ -0,0 +1,56 @@
+/*
+ * 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;
+
+import org.openvpp.jvpp.callback.JVppCallback;
+import org.openvpp.jvpp.dto.ControlPing;
+import org.openvpp.jvpp.dto.JVppRequest;
+
+/**
+ * Base interface for plugin's Java API.
+ */
+public interface JVpp extends AutoCloseable {
+
+    /**
+     * Sends request to vpp.
+     *
+     * @param request request to be sent
+     * @return unique identifer of message in message queue
+     * @throws VppInvocationException when message could not be sent
+     */
+    int send(final JVppRequest request) throws VppInvocationException;
+
+    /**
+     * Initializes plugin's Java API.
+     *
+     * @param registry     plugin registry
+     * @param callback     called by vpe.api message handlers
+     * @param queueAddress address of vpp shared memory queue
+     * @param clientIndex  vpp client identifier
+     */
+    void init(final JVppRegistry registry, final JVppCallback callback, final long queueAddress,
+              final int clientIndex);
+
+    /**
+     * Sends control_ping message.
+     *
+     * @param controlPing request DTO
+     * @return unique identifer of message in message queue
+     * @throws VppInvocationException when message could not be sent
+     */
+    int controlPing(final ControlPing controlPing) throws VppInvocationException;
+}
diff --git a/vpp-api/java/jvpp-registry/org/openvpp/jvpp/JVppRegistry.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/JVppRegistry.java
new file mode 100644
index 0000000..c25b653
--- /dev/null
+++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/JVppRegistry.java
@@ -0,0 +1,69 @@
+/*
+ * 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;
+
+import org.openvpp.jvpp.callback.JVppCallback;
+
+/**
+ * Manages VPP connection and stores plugin callbacks.
+ */
+public interface JVppRegistry extends AutoCloseable {
+
+    /**
+     * Vpp connection managed by the registry.
+     *
+     * @return representation of vpp connection
+     */
+    VppConnection getConnection();
+
+    /**
+     * Registers callback and initializes Java API for given plugin.
+     *
+     * @param jvpp     plugin name
+     * @param callback callback provided by the plugin
+     * @throws NullPointerException     if name or callback is null
+     * @throws IllegalArgumentException if plugin was already registered
+     */
+    void register(final JVpp jvpp, final JVppCallback callback);
+
+    /**
+     * Unregisters callback for the given plugin.
+     *
+     * @param name plugin name
+     * @throws NullPointerException     if name is null
+     * @throws IllegalArgumentException if plugin was not registered
+     */
+    void unregister(final String name);
+
+    /**
+     * Returns callback registered for the plugin.
+     *
+     * @param name plugin name
+     * @return callback provided by the plugin
+     * @throws NullPointerException     if name is null
+     * @throws IllegalArgumentException if plugin was not registered
+     */
+    JVppCallback get(final String name);
+
+    /**
+     * Sends control ping. Reply handler calls callback registered for give plugin.
+     *
+     * @param clazz identifies plugin that should receive ping callback
+     * @return unique identifer of message in message queue
+     */
+    int controlPing(final Class<? extends JVpp> clazz) throws VppInvocationException;
+}
diff --git a/vpp-api/java/jvpp-registry/org/openvpp/jvpp/JVppRegistryImpl.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/JVppRegistryImpl.java
new file mode 100644
index 0000000..bb6730f
--- /dev/null
+++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/JVppRegistryImpl.java
@@ -0,0 +1,133 @@
+/*
+ * 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;
+
+import static java.util.Objects.requireNonNull;
+
+import java.io.IOException;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.openvpp.jvpp.callback.ControlPingCallback;
+import org.openvpp.jvpp.callback.JVppCallback;
+import org.openvpp.jvpp.dto.ControlPingReply;
+
+/**
+ * Default implementation of JVppRegistry.
+ */
+public final class JVppRegistryImpl implements JVppRegistry, ControlPingCallback {
+
+    private static final Logger LOG = Logger.getLogger(JVppRegistryImpl.class.getName());
+
+    private final VppJNIConnection connection;
+    private final ConcurrentMap<String, JVppCallback> pluginRegistry;
+    private final ConcurrentMap<Integer, ControlPingCallback> pingCalls;
+
+    public JVppRegistryImpl(final String clientName) throws IOException {
+        connection = new VppJNIConnection(clientName);
+        connection.connect();
+        pluginRegistry = new ConcurrentHashMap<>();
+        pingCalls = new ConcurrentHashMap<>();
+    }
+
+    @Override
+    public VppConnection getConnection() {
+        return connection;
+    }
+
+    @Override
+    public void register(final JVpp jvpp, final JVppCallback callback) {
+        requireNonNull(jvpp, "jvpp should not be null");
+        requireNonNull(callback, "Callback should not be null");
+        final String name = jvpp.getClass().getName();
+        if (pluginRegistry.putIfAbsent(name, callback) != null) {
+            throw new IllegalArgumentException(String.format("Callback for plugin %s was already registered", name));
+        }
+        jvpp.init(this, callback, connection.getConnectionInfo().queueAddress,
+            connection.getConnectionInfo().clientIndex);
+    }
+
+    @Override
+    public void unregister(final String name) {
+        requireNonNull(name, "Plugin name should not be null");
+        final JVppCallback previous = pluginRegistry.remove(name);
+        assertPluginWasRegistered(name, previous);
+    }
+
+    @Override
+    public JVppCallback get(final String name) {
+        requireNonNull(name, "Plugin name should not be null");
+        JVppCallback value = pluginRegistry.get(name);
+        assertPluginWasRegistered(name, value);
+        return value;
+    }
+
+    private native int controlPing0() throws VppInvocationException;
+
+    @Override
+    public int controlPing(final Class<? extends JVpp> clazz) throws VppInvocationException {
+        connection.checkActive();
+        final String name = clazz.getName();
+
+        final ControlPingCallback callback = (ControlPingCallback) pluginRegistry.get(clazz.getName());
+        assertPluginWasRegistered(name, callback);
+
+        int context = controlPing0();
+        if (context < 0) {
+            throw new VppInvocationException("controlPing", context);
+        }
+
+        pingCalls.put(context, callback);
+        return context;
+    }
+
+
+    @Override
+    public void onControlPingReply(final ControlPingReply reply) {
+        final ControlPingCallback callback = pingCalls.get(reply.context);
+        if (callback == null) {
+            LOG.log(Level.WARNING, "No callback was registered for reply id={0} ", reply.context);
+            return;
+        }
+        // pass the reply to the callback registered by the ping caller
+        callback.onControlPingReply(reply);
+    }
+
+    @Override
+    public void onError(final VppCallbackException ex) {
+        final int ctxId = ex.getCtxId();
+        final ControlPingCallback callback = pingCalls.get(ctxId);
+        if (callback == null) {
+            LOG.log(Level.WARNING, "No callback was registered for reply id={0} ", ctxId);
+            return;
+        }
+        // pass the error to the callback registered by the ping caller
+        callback.onError(ex);
+    }
+
+    private static void assertPluginWasRegistered(final String name, final JVppCallback value) {
+        if (value == null) {
+            throw new IllegalArgumentException(String.format("Callback for plugin %s is not registered", name));
+        }
+    }
+
+    @Override
+    public void close() throws Exception {
+        connection.close();
+    }
+}
diff --git a/vpp-api/java/jvpp-registry/org/openvpp/jvpp/NativeLibraryLoader.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/NativeLibraryLoader.java
new file mode 100644
index 0000000..d00c41d
--- /dev/null
+++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/NativeLibraryLoader.java
@@ -0,0 +1,73 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Utility class for loading JNI libraries.
+ */
+public final class NativeLibraryLoader {
+
+    private static final Logger LOG = Logger.getLogger(NativeLibraryLoader.class.getName());
+
+    private NativeLibraryLoader() {
+        throw new UnsupportedOperationException("This utility class cannot be instantiated.");
+    }
+
+    /**
+     * Loads JNI library using class loader of the given class.
+     *
+     * @param libName name of the library to be loaded
+     */
+    public static void loadLibrary(final String libName, final Class clazz) throws IOException {
+        java.util.Objects.requireNonNull(libName, "libName should not be null");
+        java.util.Objects.requireNonNull(clazz, "clazz should not be null");
+        try (final InputStream is = clazz.getResourceAsStream('/' + libName)) {
+            if (is == null) {
+                throw new IOException("Failed to open library resource " + libName);
+            }
+            loadStream(libName, is);
+        }
+    }
+
+    private static void loadStream(final String libName, final InputStream is) throws IOException {
+        final Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rwxr-x---");
+        final Path p = Files.createTempFile(libName, null, PosixFilePermissions.asFileAttribute(perms));
+        try {
+            Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING);
+            Runtime.getRuntime().load(p.toString());
+        } catch (Exception e) {
+            throw new IOException("Failed to load library " + p, e);
+        } finally {
+            try {
+                Files.deleteIfExists(p);
+            } catch (IOException e) {
+                LOG.log(Level.WARNING, String.format("Failed to delete temporary file %s.", p), e);
+            }
+        }
+    }
+}
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/VppBaseCallException.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppBaseCallException.java
similarity index 100%
rename from vpp-api/java/jvpp/org/openvpp/jvpp/VppBaseCallException.java
rename to vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppBaseCallException.java
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/VppCallbackException.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppCallbackException.java
similarity index 100%
rename from vpp-api/java/jvpp/org/openvpp/jvpp/VppCallbackException.java
rename to vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppCallbackException.java
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/VppConnection.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppConnection.java
similarity index 76%
rename from vpp-api/java/jvpp/org/openvpp/jvpp/VppConnection.java
rename to vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppConnection.java
index 1973398..e7055f9 100644
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/VppConnection.java
+++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppConnection.java
@@ -20,21 +20,18 @@
 
 /**
  * Representation of a management connection to VPP.
- * Connection is initiated when instance is created, closed with close().
  */
 public interface VppConnection extends AutoCloseable {
 
     /**
-     * Open VppConnection for communication with VPP
-     *
-     * @param callback instance handling responses
+     * Opens VppConnection for communication with VPP.
      *
      * @throws IOException if connection is not established
      */
-    void connect(final org.openvpp.jvpp.callback.JVppCallback callback) throws IOException;
+    void connect() throws IOException;
 
     /**
-     * Check if this instance connection is active.
+     * Checks if this instance connection is active.
      *
      * @throws IllegalStateException if this instance was disconnected.
      */
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/VppInvocationException.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppInvocationException.java
similarity index 100%
rename from vpp-api/java/jvpp/org/openvpp/jvpp/VppInvocationException.java
rename to vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppInvocationException.java
diff --git a/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppJNIConnection.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppJNIConnection.java
new file mode 100644
index 0000000..f352987
--- /dev/null
+++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppJNIConnection.java
@@ -0,0 +1,137 @@
+/*
+ * 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;
+
+import static org.openvpp.jvpp.NativeLibraryLoader.loadLibrary;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * JNI based representation of a management connection to VPP.
+ */
+public final class VppJNIConnection implements VppConnection {
+    private static final Logger LOG = Logger.getLogger(VppJNIConnection.class.getName());
+
+    static {
+        final String libName = "libjvpp_registry.so.0.0.0";
+        try {
+            loadLibrary(libName, VppJNIConnection.class);
+        } catch (IOException e) {
+            LOG.log(Level.SEVERE, String.format("Can't find vpp jni library: %s", libName), e);
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+
+    private ConnectionInfo connectionInfo;
+
+    private final String clientName;
+    private volatile boolean disconnected = false;
+
+    /**
+     * Create VPPJNIConnection instance for client connecting to VPP.
+     *
+     * @param clientName client name instance to be used for communication. Single connection per clientName is
+     *                   allowed.
+     */
+    public VppJNIConnection(final String clientName) {
+        this.clientName = Objects.requireNonNull(clientName, "Null clientName");
+    }
+
+    /**
+     * Guarded by VppJNIConnection.class
+     */
+    private static final Map<String, VppJNIConnection> connections = new HashMap<>();
+
+    /**
+     * Initiate VPP connection for current instance
+     *
+     * Multiple instances are allowed since this class is not a singleton (VPP allows multiple management connections).
+     *
+     * However only a single connection per clientName is allowed.
+     *
+     * @throws IOException in case the connection could not be established
+     */
+
+    @Override
+    public void connect() throws IOException {
+        _connect();
+    }
+
+    private void _connect() throws IOException {
+        synchronized (VppJNIConnection.class) {
+            if (connections.containsKey(clientName)) {
+                throw new IOException("Client " + clientName + " already connected");
+            }
+
+            connectionInfo = clientConnect(clientName);
+            if (connectionInfo.status != 0) {
+                throw new IOException("Connection returned error " + connectionInfo.status);
+            }
+            connections.put(clientName, this);
+        }
+    }
+
+    @Override
+    public final void checkActive() {
+        if (disconnected) {
+            throw new IllegalStateException("Disconnected client " + clientName);
+        }
+    }
+
+    @Override
+    public final synchronized void close() {
+        if (!disconnected) {
+            disconnected = true;
+            try {
+                clientDisconnect();
+            } finally {
+                synchronized (VppJNIConnection.class) {
+                    connections.remove(clientName);
+                }
+            }
+        }
+    }
+
+    public ConnectionInfo getConnectionInfo() {
+        return connectionInfo;
+    }
+
+    /**
+     * VPP connection information used by plugins to reuse the connection.
+     */
+    public static final class ConnectionInfo {
+        public final long queueAddress;
+        public final int clientIndex;
+        public final int status; // FIXME throw exception instead
+
+        public ConnectionInfo(long queueAddress, int clientIndex, int status) {
+            this.queueAddress = queueAddress;
+            this.clientIndex = clientIndex;
+            this.status = status;
+        }
+    }
+
+    private static native ConnectionInfo clientConnect(String clientName);
+
+    private static native void clientDisconnect();
+
+}
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/callback/ControlPingCallback.java
similarity index 60%
copy from vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java
copy to vpp-api/java/jvpp-registry/org/openvpp/jvpp/callback/ControlPingCallback.java
index 273e444..529ea22 100644
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java
+++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/callback/ControlPingCallback.java
@@ -14,21 +14,16 @@
  * limitations under the License.
  */
 
-package org.openvpp.jvpp.dto;
+package org.openvpp.jvpp.callback;
 
-import org.openvpp.jvpp.JVpp;
-import org.openvpp.jvpp.VppInvocationException;
+import org.openvpp.jvpp.dto.ControlPingReply;
 
 /**
-* Base interface for all request DTOs
-*/
-public interface JVppRequest {
+ * Represents callback for control_ping message.
+ */
+public interface ControlPingCallback extends JVppCallback {
 
-    /**
-     * Invoke current operation asynchronously on VPP
-     *
-     * @return context id of this request. Can be used to track incomming response
-     */
-    int send(JVpp jvpp) throws VppInvocationException;
+    void onControlPingReply(ControlPingReply reply);
 
 }
+
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/callback/JVppCallback.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/callback/JVppCallback.java
similarity index 100%
rename from vpp-api/java/jvpp/org/openvpp/jvpp/callback/JVppCallback.java
rename to vpp-api/java/jvpp-registry/org/openvpp/jvpp/callback/JVppCallback.java
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/callback/JVppNotificationCallback.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/callback/JVppNotificationCallback.java
similarity index 100%
rename from vpp-api/java/jvpp/org/openvpp/jvpp/callback/JVppNotificationCallback.java
rename to vpp-api/java/jvpp-registry/org/openvpp/jvpp/callback/JVppNotificationCallback.java
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/ControlPing.java
similarity index 71%
copy from vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java
copy to vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/ControlPing.java
index 273e444..cc59836 100644
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java
+++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/ControlPing.java
@@ -20,15 +20,15 @@
 import org.openvpp.jvpp.VppInvocationException;
 
 /**
-* Base interface for all request DTOs
-*/
-public interface JVppRequest {
+ * Represents request DTO for control_ping message.
+ */
+public final class ControlPing implements JVppRequest {
 
-    /**
-     * Invoke current operation asynchronously on VPP
-     *
-     * @return context id of this request. Can be used to track incomming response
-     */
-    int send(JVpp jvpp) throws VppInvocationException;
+    @Override
+    public int send(final JVpp jvpp) throws VppInvocationException {
+        return jvpp.controlPing(this);
+    }
 
 }
+
+
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/ControlPingReply.java
similarity index 63%
copy from vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java
copy to vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/ControlPingReply.java
index 273e444..e7efd85 100644
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java
+++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/ControlPingReply.java
@@ -16,19 +16,15 @@
 
 package org.openvpp.jvpp.dto;
 
-import org.openvpp.jvpp.JVpp;
-import org.openvpp.jvpp.VppInvocationException;
-
 /**
-* Base interface for all request DTOs
-*/
-public interface JVppRequest {
+ * Represents reply DTO for control_ping message.
+ */
+public final class ControlPingReply implements JVppReply<ControlPing> {
 
-    /**
-     * Invoke current operation asynchronously on VPP
-     *
-     * @return context id of this request. Can be used to track incomming response
-     */
-    int send(JVpp jvpp) throws VppInvocationException;
+    public int context;
+    public int clientIndex;
+    public int vpePid;
+
 
 }
+
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppDump.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppDump.java
similarity index 100%
rename from vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppDump.java
rename to vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppDump.java
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppNotification.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppNotification.java
similarity index 100%
rename from vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppNotification.java
rename to vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppNotification.java
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppReply.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppReply.java
similarity index 100%
rename from vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppReply.java
rename to vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppReply.java
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppReplyDump.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppReplyDump.java
similarity index 100%
rename from vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppReplyDump.java
rename to vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppReplyDump.java
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppRequest.java
similarity index 97%
rename from vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java
rename to vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppRequest.java
index 273e444..1216edf 100644
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java
+++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppRequest.java
@@ -27,7 +27,7 @@
     /**
      * Invoke current operation asynchronously on VPP
      *
-     * @return context id of this request. Can be used to track incomming response
+     * @return context id of this request. Can be used to track incoming response
      */
     int send(JVpp jvpp) throws VppInvocationException;
 
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvokerFacade.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/future/AbstractFutureJVppInvoker.java
similarity index 69%
rename from vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvokerFacade.java
rename to vpp-api/java/jvpp-registry/org/openvpp/jvpp/future/AbstractFutureJVppInvoker.java
index a60e1b2..d8b105f 100644
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvokerFacade.java
+++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/future/AbstractFutureJVppInvoker.java
@@ -17,34 +17,37 @@
 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.notification.NotificationRegistryProviderContext;
+import org.openvpp.jvpp.JVpp;
+import org.openvpp.jvpp.JVppRegistry;
+import org.openvpp.jvpp.VppInvocationException;
+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
 */
-public class FutureJVppInvokerFacade extends NotificationRegistryProviderContext implements FutureJVppInvoker {
+public abstract class AbstractFutureJVppInvoker implements FutureJVppInvoker {
 
     private final JVpp jvpp;
+    private final JVppRegistry registry;
 
     /**
      * Guarded by self
      */
     private final Map<Integer, CompletableFuture<? extends JVppReply<?>>> requests;
 
-    public FutureJVppInvokerFacade(final JVpp jvpp,
-                                   final Map<Integer, CompletableFuture<? extends JVppReply<?>>> requestMap) {
-        this.jvpp =  Objects.requireNonNull(jvpp, "Null jvpp");
+    protected AbstractFutureJVppInvoker(final JVpp jvpp, final JVppRegistry registry,
+                                     final Map<Integer, CompletableFuture<? extends JVppReply<?>>> requestMap) {
+        this.jvpp =  Objects.requireNonNull(jvpp, "jvpp should not be null");
+        this.registry =  Objects.requireNonNull(registry, "registry should not be null");
         // Request map represents the shared state between this facade and it's callback
         // where facade puts futures in and callback completes + removes them
-        // TODO what if the call never completes ?
         this.requests = Objects.requireNonNull(requestMap, "Null requestMap");
     }
 
@@ -70,8 +73,13 @@
 
                 requests.put(contextId, replyCompletableFuture);
                 if(req instanceof JVppDump) {
-                    requests.put(jvpp.send(new ControlPing()), replyCompletableFuture);
+                    requests.put(registry.controlPing(jvpp.getClass()), replyCompletableFuture);
                 }
+
+                // TODO in case of timeouts/missing replies, requests from the map are not removed
+                // consider adding cancel method, that would remove requests from the map and cancel
+                // associated replyCompletableFuture
+
                 return replyCompletableFuture;
             } catch (VppInvocationException ex) {
                 final CompletableFuture<REPLY> replyCompletableFuture = new CompletableFuture<>();
@@ -81,32 +89,32 @@
         }
     }
 
-    static final class CompletableDumpFuture<T extends JVppReplyDump<?, ?>> extends CompletableFuture<T> {
+    public static final class CompletableDumpFuture<T extends JVppReplyDump<?, ?>> extends CompletableFuture<T> {
         // The reason why this is not final is the instantiation of ReplyDump DTOs
         // Their instantiation must be generated, so currently the DTOs are created in callback and set when first dump reponses
         // is handled in the callback.
         private T replyDump;
         private final long contextId;
 
-        CompletableDumpFuture(final long contextId) {
+        public CompletableDumpFuture(final long contextId) {
             this.contextId = contextId;
         }
 
-        long getContextId() {
+        public long getContextId() {
             return contextId;
         }
 
-        T getReplyDump() {
+        public T getReplyDump() {
             return replyDump;
         }
 
-        void setReplyDump(final T replyDump) {
+        public void setReplyDump(final T replyDump) {
             this.replyDump = replyDump;
         }
     }
 
     @Override
     public void close() throws Exception {
-        // NOOP
+        jvpp.close();
     }
 }
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvoker.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/future/FutureJVppInvoker.java
similarity index 100%
rename from vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvoker.java
rename to vpp-api/java/jvpp-registry/org/openvpp/jvpp/future/FutureJVppInvoker.java
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/notification/NotificationRegistry.java
similarity index 60%
copy from vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java
copy to vpp-api/java/jvpp-registry/org/openvpp/jvpp/notification/NotificationRegistry.java
index 273e444..27349f2 100644
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java
+++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/notification/NotificationRegistry.java
@@ -14,21 +14,12 @@
  * limitations under the License.
  */
 
-package org.openvpp.jvpp.dto;
-
-import org.openvpp.jvpp.JVpp;
-import org.openvpp.jvpp.VppInvocationException;
+package org.openvpp.jvpp.notification;
 
 /**
-* Base interface for all request DTOs
-*/
-public interface JVppRequest {
+ * Base registry for notification callbacks.
+ */
+public interface NotificationRegistry extends AutoCloseable {
 
-    /**
-     * Invoke current operation asynchronously on VPP
-     *
-     * @return context id of this request. Can be used to track incomming response
-     */
-    int send(JVpp jvpp) throws VppInvocationException;
-
+    void close();
 }
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/notification/NotificationRegistryProvider.java
similarity index 62%
copy from vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java
copy to vpp-api/java/jvpp-registry/org/openvpp/jvpp/notification/NotificationRegistryProvider.java
index 273e444..46c534a 100644
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java
+++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/notification/NotificationRegistryProvider.java
@@ -14,21 +14,15 @@
  * limitations under the License.
  */
 
-package org.openvpp.jvpp.dto;
-
-import org.openvpp.jvpp.JVpp;
-import org.openvpp.jvpp.VppInvocationException;
+package org.openvpp.jvpp.notification;
 
 /**
-* Base interface for all request DTOs
-*/
-public interface JVppRequest {
+ * Provides notification registry
+ */
+public interface NotificationRegistryProvider {
 
     /**
-     * Invoke current operation asynchronously on VPP
-     *
-     * @return context id of this request. Can be used to track incomming response
+     * Get current notification registry instance
      */
-    int send(JVpp jvpp) throws VppInvocationException;
-
+    NotificationRegistry getNotificationRegistry();
 }
diff --git a/vpp-api/java/jvpp-registry/org/openvpp/jvpp/test/ConnectionTest.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/test/ConnectionTest.java
new file mode 100644
index 0000000..d134a1c
--- /dev/null
+++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/test/ConnectionTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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.JVppRegistry;
+import org.openvpp.jvpp.JVppRegistryImpl;
+
+/**
+ * Run using:
+ * sudo java -cp build-vpp-native/vpp-api/java/jvpp-registry-16.09.jar org.openvpp.jvpp.test.ConnectionTest
+ */
+public class ConnectionTest {
+
+    private static void testConnect() throws Exception {
+        System.out.println("Testing JNI connection with JVppRegistry");
+        JVppRegistry registry = new JVppRegistryImpl("ConnectionTest");
+        System.out.println("Successfully connected to vpp");
+
+        Thread.sleep(5000);
+
+        System.out.println("Disconnecting...");
+        registry.close();
+        Thread.sleep(1000);
+    }
+
+    public static void main(String[] args) throws Exception {
+        testConnect();
+    }
+}
diff --git a/vpp-api/java/jvpp/gen/jvpp_gen.py b/vpp-api/java/jvpp/gen/jvpp_gen.py
index 6f531de..551ce7d 100755
--- a/vpp-api/java/jvpp/gen/jvpp_gen.py
+++ b/vpp-api/java/jvpp/gen/jvpp_gen.py
@@ -41,7 +41,8 @@
 
 parser = argparse.ArgumentParser(description='VPP Java API generator')
 parser.add_argument('-i', action="store", dest="inputfile")
-parser.add_argument('--base_package', action="store", dest="base_package", default='org.openvpp.jvpp')
+parser.add_argument('--plugin_name', action="store", dest="plugin_name")
+parser.add_argument('--control_ping_class', action="store", dest="control_ping_class", default="ControlPing")
 args = parser.parse_args()
 
 sys.path.append(".")
@@ -52,7 +53,10 @@
 inputfile = os.path.basename(args.inputfile)
 inputfile = inputfile.replace('.py', '')
 print "inputfile %s" % inputfile
-base_package = args.base_package
+plugin_name = args.plugin_name
+print "plugin_name %s" % plugin_name
+control_ping_class = args.control_ping_class
+print "control_ping_class %s" % control_ping_class
 sys.path.append(importdir)
 cfg = importlib.import_module(inputfile, package=None)
 
@@ -133,17 +137,20 @@
 
 func_list, func_name = get_definitions()
 
+base_package = 'org.openvpp.jvpp'
+plugin_package = base_package + '.' + plugin_name
 dto_package = 'dto'
 callback_package = 'callback'
 notification_package = 'notification'
 future_package = 'future'
 # TODO find better package name
 callback_facade_package = 'callfacade'
+control_ping_class_fqn = "%s.%s.%s" % (plugin_package, dto_package, control_ping_class)
 
-dto_gen.generate_dtos(func_list, base_package, dto_package, args.inputfile)
-jvpp_impl_gen.generate_jvpp(func_list, base_package, dto_package, args.inputfile)
-callback_gen.generate_callbacks(func_list, base_package, callback_package, dto_package, args.inputfile)
-notification_gen.generate_notification_registry(func_list, base_package, notification_package, callback_package, dto_package, args.inputfile)
-jvpp_c_gen.generate_jvpp(func_list, args.inputfile)
-jvpp_future_facade_gen.generate_jvpp(func_list, base_package, dto_package, callback_package, notification_package, future_package, args.inputfile)
-jvpp_callback_facade_gen.generate_jvpp(func_list, base_package, dto_package, callback_package, notification_package, callback_facade_package, args.inputfile)
+dto_gen.generate_dtos(func_list, base_package, plugin_package, plugin_name.title(), dto_package, args.inputfile)
+jvpp_impl_gen.generate_jvpp(func_list, base_package, plugin_package, plugin_name, control_ping_class_fqn, dto_package, args.inputfile)
+callback_gen.generate_callbacks(func_list, base_package, plugin_package, plugin_name.title(), callback_package, dto_package, args.inputfile)
+notification_gen.generate_notification_registry(func_list, base_package, plugin_package, plugin_name.title(), notification_package, callback_package, dto_package, args.inputfile)
+jvpp_c_gen.generate_jvpp(func_list, plugin_name, args.inputfile)
+jvpp_future_facade_gen.generate_jvpp(func_list, base_package, plugin_package, plugin_name.title(), dto_package, callback_package, notification_package, future_package, args.inputfile)
+jvpp_callback_facade_gen.generate_jvpp(func_list, base_package, plugin_package, plugin_name.title(), dto_package, callback_package, notification_package, callback_facade_package, args.inputfile)
diff --git a/vpp-api/java/jvpp/gen/jvppgen/callback_gen.py b/vpp-api/java/jvpp/gen/jvppgen/callback_gen.py
index eadf3b5..68f7012 100644
--- a/vpp-api/java/jvpp/gen/jvppgen/callback_gen.py
+++ b/vpp-api/java/jvpp/gen/jvppgen/callback_gen.py
@@ -22,10 +22,10 @@
 callback_suffix = "Callback"
 
 callback_template = Template("""
-package $base_package.$callback_package;
+package $plugin_package.$callback_package;
 
 /**
- * <p>Represents callback for vpe.api message.
+ * <p>Represents callback for plugin's api file message.
  * <br>It was generated by callback_gen.py based on $inputfile preparsed data:
  * <pre>
 $docs
@@ -39,19 +39,19 @@
 """)
 
 global_callback_template = Template("""
-package $base_package.$callback_package;
+package $plugin_package.$callback_package;
 
 /**
  * <p>Global aggregated callback interface.
  * <br>It was generated by callback_gen.py based on $inputfile
- * <br>(python representation of vpe.api generated by vppapigen).
+ * <br>(python representation of api file generated by vppapigen).
  */
-public interface JVppGlobalCallback extends $callbacks {
+public interface JVpp${plugin_name}GlobalCallback extends $base_package.$callback_package.ControlPingCallback, $callbacks {
 }
 """)
 
 
-def generate_callbacks(func_list, base_package, callback_package, dto_package, inputfile):
+def generate_callbacks(func_list, base_package, plugin_package, plugin_name, callback_package, dto_package, inputfile):
     """ Generates callback interfaces """
     print "Generating Callback interfaces"
 
@@ -61,10 +61,10 @@
     callbacks = []
     for func in func_list:
 
-        if util.is_ignored(func['name']):
-            continue
-
         camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name'])
+
+        if util.is_ignored(func['name']) or util.is_control_ping(camel_case_name_with_suffix):
+            continue
         if not util.is_reply(camel_case_name_with_suffix) and not util.is_notification(func['name']):
             continue
 
@@ -76,11 +76,11 @@
             camel_case_name = camel_case_name_with_suffix
             callback_type = "JVppNotificationCallback"
 
-        callbacks.append("{0}.{1}.{2}".format(base_package, callback_package, camel_case_name + callback_suffix))
+        callbacks.append("{0}.{1}.{2}".format(plugin_package, callback_package, camel_case_name + callback_suffix))
         callback_path = os.path.join(callback_package, camel_case_name + callback_suffix + ".java")
         callback_file = open(callback_path, 'w')
 
-        reply_type = "%s.%s.%s" % (base_package, dto_package, camel_case_name_with_suffix)
+        reply_type = "%s.%s.%s" % (plugin_package, dto_package, camel_case_name_with_suffix)
         method = "void on{0}({1} reply);".format(camel_case_name_with_suffix, reply_type)
         callback_file.write(
             callback_template.substitute(inputfile=inputfile,
@@ -88,15 +88,18 @@
                                          cls_name=camel_case_name + callback_suffix,
                                          callback_method=method,
                                          base_package=base_package,
+                                         plugin_package=plugin_package,
                                          callback_package=callback_package,
                                          callback_type=callback_type))
         callback_file.flush()
         callback_file.close()
 
-    callback_file = open(os.path.join(callback_package, "JVppGlobalCallback.java"), 'w')
+    callback_file = open(os.path.join(callback_package, "JVpp%sGlobalCallback.java" % plugin_name), 'w')
     callback_file.write(global_callback_template.substitute(inputfile=inputfile,
                                                             callbacks=", ".join(callbacks),
                                                             base_package=base_package,
+                                                            plugin_package=plugin_package,
+                                                            plugin_name=plugin_name,
                                                             callback_package=callback_package))
     callback_file.flush()
     callback_file.close()
diff --git a/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py b/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py
index 426cd96..785e47e 100644
--- a/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py
+++ b/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py
@@ -19,7 +19,7 @@
 import util
 
 dto_template = Template("""
-package $base_package.$dto_package;
+package $plugin_package.$dto_package;
 
 /**
  * <p>This class represents $description.
@@ -39,11 +39,11 @@
 
 send_template = Template("""    @Override
     public int send(final $base_package.JVpp jvpp) throws org.openvpp.jvpp.VppInvocationException {
-        return jvpp.$method_name($args);
+        return (($plugin_package.JVpp${plugin_name})jvpp).$method_name($args);
     }\n""")
 
 
-def generate_dtos(func_list, base_package, dto_package, inputfile):
+def generate_dtos(func_list, base_package, plugin_package, plugin_name, dto_package, inputfile):
     """ Generates dto objects in a dedicated package """
     print "Generating DTOs"
 
@@ -55,7 +55,7 @@
         camel_case_method_name = util.underscore_to_camelcase(func['name'])
         dto_path = os.path.join(dto_package, camel_case_dto_name + ".java")
 
-        if util.is_ignored(func['name']):
+        if util.is_ignored(func['name']) or util.is_control_ping(camel_case_dto_name):
             continue
 
         fields = ""
@@ -72,44 +72,46 @@
         # Generate request/reply or dump/dumpReply even if structure can be used as notification
         if not util.is_just_notification(func["name"]):
             if util.is_reply(camel_case_dto_name):
-                description = "vpe.api reply DTO"
+                description = "reply DTO"
                 request_dto_name = get_request_name(camel_case_dto_name, func['name'])
                 if util.is_details(camel_case_dto_name):
                     # FIXME assumption that dump calls end with "Dump" suffix. Not enforced in vpe.api
-                    base_type += "JVppReply<%s.%s.%s>" % (base_package, dto_package, request_dto_name + "Dump")
-                    generate_dump_reply_dto(request_dto_name, base_package, dto_package, camel_case_dto_name,
+                    base_type += "JVppReply<%s.%s.%s>" % (plugin_package, dto_package, request_dto_name + "Dump")
+                    generate_dump_reply_dto(request_dto_name, base_package, plugin_package, dto_package, camel_case_dto_name,
                                             camel_case_method_name, func)
                 else:
-                    base_type += "JVppReply<%s.%s.%s>" % (base_package, dto_package, request_dto_name)
+                    base_type += "JVppReply<%s.%s.%s>" % (plugin_package, dto_package, request_dto_name)
             else:
                 args = "" if fields is "" else "this"
                 methods = send_template.substitute(method_name=camel_case_method_name,
                                                    base_package=base_package,
+                                                   plugin_package=plugin_package,
+                                                   plugin_name=plugin_name,
                                                    args=args)
                 if util.is_dump(camel_case_dto_name):
                     base_type += "JVppDump"
-                    description = "vpe.api dump request DTO"
+                    description = "dump request DTO"
                 else:
                     base_type += "JVppRequest"
-                    description = "vpe.api request DTO"
+                    description = "request DTO"
 
-            write_dto_file(base_package, base_type, camel_case_dto_name, description, dto_package, dto_path, fields, func,
+            write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, description, dto_package, dto_path, fields, func,
                            inputfile, methods)
 
         # for structures that are also used as notifications, generate dedicated notification DTO
         if util.is_notification(func["name"]):
             base_type = "JVppNotification"
-            description = "vpe.api notification DTO"
+            description = "notification DTO"
             camel_case_dto_name = util.add_notification_suffix(camel_case_dto_name)
             methods = ""
             dto_path = os.path.join(dto_package, camel_case_dto_name + ".java")
-            write_dto_file(base_package, base_type, camel_case_dto_name, description, dto_package, dto_path, fields, func,
+            write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, description, dto_package, dto_path, fields, func,
                            inputfile, methods)
 
     flush_dump_reply_dtos(inputfile)
 
 
-def write_dto_file(base_package, base_type, camel_case_dto_name, description, dto_package, dto_path, fields, func,
+def write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, description, dto_package, dto_path, fields, func,
                    inputfile, methods):
     dto_file = open(dto_path, 'w')
     dto_file.write(dto_template.substitute(inputfile=inputfile,
@@ -119,6 +121,7 @@
                                            fields=fields,
                                            methods=methods,
                                            base_package=base_package,
+                                           plugin_package=plugin_package,
                                            base_type=base_type,
                                            dto_package=dto_package))
     dto_file.flush()
@@ -141,11 +144,12 @@
                                 dump_reply_artificial_dto['cls_name'] + ".java")
         dto_file = open(dto_path, 'w')
         dto_file.write(dto_template.substitute(inputfile=inputfile,
-                                               description="vpe.api dump reply wrapper",
+                                               description="dump reply wrapper",
                                                docs=dump_reply_artificial_dto['docs'],
                                                cls_name=dump_reply_artificial_dto['cls_name'],
                                                fields=dump_reply_artificial_dto['fields'],
                                                methods=dump_reply_artificial_dto['methods'],
+                                               plugin_package=dump_reply_artificial_dto['plugin_package'],
                                                base_package=dump_reply_artificial_dto['base_package'],
                                                base_type=dump_reply_artificial_dto['base_type'],
                                                dto_package=dump_reply_artificial_dto['dto_package']))
@@ -153,11 +157,11 @@
         dto_file.close()
 
 
-def generate_dump_reply_dto(request_dto_name, base_package, dto_package, camel_case_dto_name, camel_case_method_name,
+def generate_dump_reply_dto(request_dto_name, base_package, plugin_package, dto_package, camel_case_dto_name, camel_case_method_name,
                             func):
     base_type = "JVppReplyDump<%s.%s.%s, %s.%s.%s>" % (
-        base_package, dto_package, util.remove_reply_suffix(camel_case_dto_name) + "Dump",
-        base_package, dto_package, camel_case_dto_name)
+        plugin_package, dto_package, util.remove_reply_suffix(camel_case_dto_name) + "Dump",
+        plugin_package, dto_package, camel_case_dto_name)
     fields = "    public java.util.List<%s> %s = new java.util.ArrayList<>();" % (camel_case_dto_name, camel_case_method_name)
     cls_name = camel_case_dto_name + dump_dto_suffix
 
@@ -171,6 +175,7 @@
                                                          'cls_name': cls_name,
                                                          'fields': fields,
                                                          'methods': "",
+                                                         'plugin_package': plugin_package,
                                                          'base_package': base_package,
                                                          'base_type': base_type,
                                                          'dto_package': dto_package,
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 1796ac1..cd3a356 100644
--- a/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py
+++ b/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py
@@ -17,7 +17,7 @@
 import os, util
 from string import Template
 
-def is_manually_generated(f_name):
+def is_manually_generated(f_name, plugin_name):
     return f_name in {'control_ping_reply'}
 
 
@@ -25,7 +25,7 @@
 """)
 
 find_class_invocation_template = Template("""
-    ${ref_name}Class = (jclass)(*env)->NewGlobalRef(env, (*env)->FindClass(env, "org/openvpp/jvpp/dto/${class_name}"));
+    ${ref_name}Class = (jclass)(*env)->NewGlobalRef(env, (*env)->FindClass(env, "org/openvpp/jvpp/${plugin_name}/dto/${class_name}"));
     if ((*env)->ExceptionCheck(env)) {
         (*env)->ExceptionDescribe(env);
         return JNI_ERR;
@@ -38,53 +38,71 @@
         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):
+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_ignored(c_name):
+        if util.is_ignored(c_name) or util.is_control_ping(class_name):
             continue
 
         if util.is_reply(class_name):
             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))
         elif util.is_notification(c_name):
             class_references.append(class_reference_template.substitute(
                 ref_name=util.add_notification_suffix(ref_name)))
             find_class_invocations.append(find_class_invocation_template.substitute(
+                plugin_name=plugin_name,
                 ref_name=util.add_notification_suffix(ref_name),
                 class_name=util.add_notification_suffix(class_name)))
+            delete_class_invocations.append(delete_class_invocation_template.substitute(
+                ref_name=util.add_notification_suffix(ref_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))
+            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))
+        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, "org/openvpp/jvpp/dto/${java_name_upper}");""")
+    jclass requestClass = (*env)->FindClass(env, "org/openvpp/jvpp/${plugin_name}/dto/${java_name_upper}");""")
 
 request_field_identifier_template = Template("""
     jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, requestClass, "${java_name}", "${jni_signature}");
@@ -178,37 +196,40 @@
 
 jni_impl_template = Template("""
 /**
- * JNI binding for sending ${c_name} vpe.api message.
+ * JNI binding for sending ${c_name} message.
  * Generated based on $inputfile preparsed data:
 $api_data
  */
-JNIEXPORT jint JNICALL Java_org_openvpp_jvpp_JVppImpl_${java_name}0
+JNIEXPORT jint JNICALL Java_org_openvpp_jvpp_${plugin_name}_JVpp${java_plugin_name}Impl_${java_name}0
 (JNIEnv * env, jclass clazz$args) {
-    vppjni_main_t *jm = &vppjni_main;
+    ${plugin_name}_main_t *plugin_main = &${plugin_name}_main;
     vl_api_${c_name}_t * mp;
-    u32 my_context_id;
-    int rv;
-    rv = vppjni_sanity_check (jm);
-    if (rv) return rv;
-    my_context_id = vppjni_get_context_id (jm);
+    u32 my_context_id = vppjni_get_context_id (&jvpp_main);
     $request_class
     $field_identifiers
-    M(${c_name_uppercase}, ${c_name});
+
+    // create message:
+    mp = vl_msg_api_alloc(sizeof(*mp));
+    memset (mp, 0, sizeof (*mp));
+    mp->_vl_msg_id = ntohs (VL_API_${c_name_uppercase} + plugin_main->msg_id_base);
+    mp->client_index = plugin_main->my_client_index;
     mp->context = clib_host_to_net_u32 (my_context_id);
+
     $struct_setters
-    S;
+    // send 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, inputfile):
+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) or util.is_reply(camel_case_function_name) \
+        if is_manually_generated(f_name, plugin_name) or util.is_reply(camel_case_function_name) \
                 or util.is_ignored(f_name) or util.is_just_notification(f_name):
             continue
 
@@ -222,7 +243,9 @@
             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)
+            request_class = request_class_template.substitute(
+                    java_name_upper=camel_case_function_name_upper,
+                    plugin_name=plugin_name)
 
             # field identifiers
             for t in zip(f['types'], f['args']):
@@ -261,6 +284,8 @@
                 java_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,
@@ -357,7 +382,7 @@
 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);
+        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) {
@@ -368,32 +393,34 @@
 
 msg_handler_template = Template("""
 /**
- * Handler for ${handler_name} vpe.api message.
+ * 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)
 {
-    vppjni_main_t * jm = &vppjni_main;
-    JNIEnv *env = jm->jenv;
+    ${plugin_name}_main_t *plugin_main = &${plugin_name}_main;
+    JNIEnv *env = jvpp_main.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");
+    jmethodID callbackMethod = (*env)->GetMethodID(env, plugin_main->callbackClass, "on${dto_name}", "(Lorg/openvpp/jvpp/${plugin_name}/dto/${dto_name};)V");
 
     jobject dto = (*env)->NewObject(env, ${class_ref_name}Class, constructor);
     $dto_setters
-    (*env)->CallVoidMethod(env, jm->callback, callbackMethod, dto);
+
+    (*env)->CallVoidMethod(env, plugin_main->callbackObject, callbackMethod, dto);
 }""")
 
-def generate_msg_handlers(func_list, inputfile):
+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) or util.is_ignored(handler_name):
+        if is_manually_generated(handler_name, plugin_name) or util.is_ignored(handler_name):
             continue
 
         if not util.is_reply(dto_name) and not util.is_notification(handler_name):
@@ -455,6 +482,7 @@
             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,
@@ -468,12 +496,13 @@
 
 
 def generate_handler_registration(func_list):
-    handler_registration = ["#define foreach_vpe_api_msg \\\n"]
+    handler_registration = ["#define foreach_api_reply_handler \\\n"]
     for f in func_list:
         name = f['name']
         camelcase_name = util.underscore_to_camelcase(f['name'])
 
-        if (not util.is_reply(camelcase_name) and not util.is_notification(name)) or util.is_ignored(name):
+        if (not util.is_reply(camelcase_name) and not util.is_notification(name)) or util.is_ignored(name) \
+                or util.is_control_ping(camelcase_name):
             continue
 
         handler_registration.append(handler_registration_template.substitute(
@@ -486,11 +515,9 @@
 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 vpe.api generated by vppapigen).
+ * (python representation of api file generated by vppapigen).
  */
 
-void CallOnError(const char* call, int context, int retval);
-
 // JAVA class reference cache
 $class_cache
 
@@ -504,16 +531,16 @@
 $handler_registration
 """)
 
-def generate_jvpp(func_list, inputfile):
+def generate_jvpp(func_list, plugin_name, inputfile):
     """ Generates jvpp C file """
     print "Generating jvpp C"
 
-    class_cache = generate_class_cache(func_list)
-    jni_impl = generate_jni_impl(func_list, inputfile)
-    msg_handlers = generate_msg_handlers(func_list, 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)
 
-    jvpp_c_file = open("jvpp_gen.h", 'w')
+    jvpp_c_file = open("jvpp_%s_gen.h" % plugin_name, 'w')
     jvpp_c_file.write(jvpp_c_template.substitute(
             inputfile=inputfile,
             class_cache=class_cache,
diff --git a/vpp-api/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py b/vpp-api/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py
index 7df1748..ac096a7 100644
--- a/vpp-api/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py
+++ b/vpp-api/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py
@@ -20,17 +20,14 @@
 import dto_gen
 
 jvpp_ifc_template = Template("""
-package $base_package.$callback_facade_package;
+package $plugin_package.$callback_facade_package;
 
 /**
- * <p>Callback Java API representation of vpe.api.
+ * <p>Callback Java API representation of $plugin_package plugin.
  * <br>It was generated by jvpp_callback_facade_gen.py based on $inputfile
- * <br>(python representation of vpe.api generated by vppapigen).
+ * <br>(python representation of api file generated by vppapigen).
  */
-public interface CallbackJVpp extends $base_package.$notification_package.NotificationRegistryProvider, java.lang.AutoCloseable {
-
-    @Override
-    void close();
+public interface CallbackJVpp${plugin_name} extends $base_package.$notification_package.NotificationRegistryProvider, java.lang.AutoCloseable {
 
     // TODO add send
 
@@ -39,20 +36,20 @@
 """)
 
 jvpp_impl_template = Template("""
-package $base_package.$callback_facade_package;
+package $plugin_package.$callback_facade_package;
 
 /**
- * <p>Default implementation of CallbackJVpp interface.
+ * <p>Default implementation of Callback${plugin_name}JVpp interface.
  * <br>It was generated by jvpp_callback_facade_gen.py based on $inputfile
- * <br>(python representation of vpe.api generated by vppapigen).
+ * <br>(python representation of api file generated by vppapigen).
  */
-public final class CallbackJVppFacade extends $base_package.$notification_package.NotificationRegistryProviderContext implements $base_package.$callback_facade_package.CallbackJVpp {
+public final class CallbackJVpp${plugin_name}Facade implements CallbackJVpp${plugin_name} {
 
-    private final $base_package.JVpp jvpp;
+    private final $plugin_package.JVpp${plugin_name} jvpp;
     private final java.util.Map<Integer, $base_package.$callback_package.JVppCallback> callbacks;
-
+    private final $plugin_package.$notification_package.${plugin_name}NotificationRegistryImpl notificationRegistry = new $plugin_package.$notification_package.${plugin_name}NotificationRegistryImpl();
     /**
-     * <p>Create CallbackJVppFacade object for provided JVpp instance.
+     * <p>Create CallbackJVpp${plugin_name}Facade object for provided JVpp instance.
      * Constructor internally creates CallbackJVppFacadeCallback class for processing callbacks
      * and then connects to provided JVpp instance
      *
@@ -60,14 +57,21 @@
      *
      * @throws java.io.IOException in case instance cannot connect to JVPP
      */
-    public CallbackJVppFacade(final $base_package.JVpp jvpp) throws java.io.IOException {
+    public CallbackJVpp${plugin_name}Facade(final $base_package.JVppRegistry registry, final $plugin_package.JVpp${plugin_name} jvpp) throws java.io.IOException {
         this.jvpp = java.util.Objects.requireNonNull(jvpp,"jvpp is null");
         this.callbacks = new java.util.HashMap<>();
-        this.jvpp.connect(new CallbackJVppFacadeCallback(this.callbacks, getNotificationCallback()));
+        java.util.Objects.requireNonNull(registry, "JVppRegistry should not be null");
+        registry.register(jvpp, new CallbackJVpp${plugin_name}FacadeCallback(this.callbacks, notificationRegistry));
     }
 
     @Override
-    public void close() {
+    public $plugin_package.$notification_package.${plugin_name}NotificationRegistry getNotificationRegistry() {
+        return notificationRegistry;
+    }
+
+    @Override
+    public void close() throws Exception {
+        jvpp.close();
     }
 
     // TODO add send()
@@ -77,17 +81,17 @@
 """)
 
 method_template = Template(
-    """    void $name($base_package.$dto_package.$request request, $base_package.$callback_package.$callback callback) throws org.openvpp.jvpp.VppInvocationException;""")
+    """    void $name($plugin_package.$dto_package.$request request, $plugin_package.$callback_package.$callback callback) throws $base_package.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 {
+method_impl_template = Template("""    public final void $name($plugin_package.$dto_package.$request request, $plugin_package.$callback_package.$callback callback) throws $base_package.VppInvocationException {
         synchronized (callbacks) {
             callbacks.put(jvpp.$name(request), 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 {
+no_arg_method_template = Template("""    void $name($plugin_package.$callback_package.$callback callback) throws $base_package.VppInvocationException;""")
+no_arg_method_impl_template = Template("""    public final void $name($plugin_package.$callback_package.$callback callback) throws $base_package.VppInvocationException {
         synchronized (callbacks) {
             callbacks.put(jvpp.$name(), callback);
         }
@@ -95,7 +99,7 @@
 """)
 
 
-def generate_jvpp(func_list, base_package, dto_package, callback_package, notification_package, callback_facade_package, inputfile):
+def generate_jvpp(func_list, base_package, plugin_package, plugin_name, dto_package, callback_package, notification_package, callback_facade_package, inputfile):
     """ Generates callback facade """
     print "Generating JVpp callback facade"
 
@@ -109,12 +113,11 @@
     for func in func_list:
 
         if util.is_notification(func['name']) or util.is_ignored(func['name']):
-            # TODO handle notifications
             continue
 
         camel_case_name = util.underscore_to_camelcase(func['name'])
         camel_case_name_upper = util.underscore_to_camelcase_upper(func['name'])
-        if util.is_reply(camel_case_name):
+        if util.is_reply(camel_case_name) or util.is_control_ping(camel_case_name):
             continue
 
         # Strip suffix for dump calls
@@ -123,11 +126,13 @@
         if len(func['args']) == 0:
             methods.append(no_arg_method_template.substitute(name=camel_case_name,
                                                              base_package=base_package,
+                                                             plugin_package=plugin_package,
                                                              dto_package=dto_package,
                                                              callback_package=callback_package,
                                                              callback=callback_type))
             methods_impl.append(no_arg_method_impl_template.substitute(name=camel_case_name,
                                                                        base_package=base_package,
+                                                                       plugin_package=plugin_package,
                                                                        dto_package=dto_package,
                                                                        callback_package=callback_package,
                                                                        callback=callback_type))
@@ -135,32 +140,38 @@
             methods.append(method_template.substitute(name=camel_case_name,
                                                       request=camel_case_name_upper,
                                                       base_package=base_package,
+                                                      plugin_package=plugin_package,
                                                       dto_package=dto_package,
                                                       callback_package=callback_package,
                                                       callback=callback_type))
             methods_impl.append(method_impl_template.substitute(name=camel_case_name,
                                                                 request=camel_case_name_upper,
                                                                 base_package=base_package,
+                                                                plugin_package=plugin_package,
                                                                 dto_package=dto_package,
                                                                 callback_package=callback_package,
                                                                 callback=callback_type))
 
-    join = os.path.join(callback_facade_package, "CallbackJVpp.java")
+    join = os.path.join(callback_facade_package, "CallbackJVpp%s.java" % plugin_name)
     jvpp_file = open(join, 'w')
     jvpp_file.write(
         jvpp_ifc_template.substitute(inputfile=inputfile,
                                      methods="\n".join(methods),
                                      base_package=base_package,
+                                     plugin_package=plugin_package,
+                                     plugin_name=plugin_name,
                                      dto_package=dto_package,
                                      notification_package=notification_package,
                                      callback_facade_package=callback_facade_package))
     jvpp_file.flush()
     jvpp_file.close()
 
-    jvpp_file = open(os.path.join(callback_facade_package, "CallbackJVppFacade.java"), 'w')
+    jvpp_file = open(os.path.join(callback_facade_package, "CallbackJVpp%sFacade.java" % plugin_name), 'w')
     jvpp_file.write(jvpp_impl_template.substitute(inputfile=inputfile,
                                                   methods="\n".join(methods_impl),
                                                   base_package=base_package,
+                                                  plugin_package=plugin_package,
+                                                  plugin_name=plugin_name,
                                                   dto_package=dto_package,
                                                   notification_package=notification_package,
                                                   callback_package=callback_package,
@@ -168,31 +179,31 @@
     jvpp_file.flush()
     jvpp_file.close()
 
-    generate_callback(func_list, base_package, dto_package, callback_package, notification_package, callback_facade_package, inputfile)
+    generate_callback(func_list, base_package, plugin_package, plugin_name, dto_package, callback_package, notification_package, callback_facade_package, inputfile)
 
 
 jvpp_facade_callback_template = Template("""
-package $base_package.$callback_facade_package;
+package $plugin_package.$callback_facade_package;
 
 /**
  * <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).
+ * <br>(python representation of api file generated by vppapigen).
  */
-public final class CallbackJVppFacadeCallback implements $base_package.$callback_package.JVppGlobalCallback {
+public final class CallbackJVpp${plugin_name}FacadeCallback implements $plugin_package.$callback_package.JVpp${plugin_name}GlobalCallback {
 
     private final java.util.Map<Integer, $base_package.$callback_package.JVppCallback> requests;
-    private final $base_package.$notification_package.GlobalNotificationCallback notificationCallback;
-    private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(CallbackJVppFacadeCallback.class.getName());
+    private final $plugin_package.$notification_package.Global${plugin_name}NotificationCallback notificationCallback;
+    private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(CallbackJVpp${plugin_name}FacadeCallback.class.getName());
 
-    public CallbackJVppFacadeCallback(final java.util.Map<Integer, $base_package.$callback_package.JVppCallback> requestMap,
-                                      final $base_package.$notification_package.GlobalNotificationCallback notificationCallback) {
+    public CallbackJVpp${plugin_name}FacadeCallback(final java.util.Map<Integer, $base_package.$callback_package.JVppCallback> requestMap,
+                                      final $plugin_package.$notification_package.Global${plugin_name}NotificationCallback notificationCallback) {
         this.requests = requestMap;
         this.notificationCallback = notificationCallback;
     }
 
     @Override
-    public void onError(org.openvpp.jvpp.VppCallbackException reply) {
+    public void onError($base_package.VppCallbackException reply) {
 
         $base_package.$callback_package.JVppCallback failedCall;
         synchronized(requests) {
@@ -209,6 +220,20 @@
         }
     }
 
+    @Override
+    @SuppressWarnings("unchecked")
+    public void onControlPingReply($base_package.$dto_package.ControlPingReply reply) {
+
+        $base_package.$callback_package.ControlPingCallback callback;
+        synchronized(requests) {
+            callback = ($base_package.$callback_package.ControlPingCallback) requests.remove(reply.context);
+        }
+
+        if(callback != null) {
+            callback.onControlPingReply(reply);
+        }
+    }
+
 $methods
 }
 """)
@@ -216,11 +241,11 @@
 jvpp_facade_callback_method_template = Template("""
     @Override
     @SuppressWarnings("unchecked")
-    public void on$callback_dto($base_package.$dto_package.$callback_dto reply) {
+    public void on$callback_dto($plugin_package.$dto_package.$callback_dto reply) {
 
-        $base_package.$callback_package.$callback callback;
+        $plugin_package.$callback_package.$callback callback;
         synchronized(requests) {
-            callback = ($base_package.$callback_package.$callback) requests.remove(reply.context);
+            callback = ($plugin_package.$callback_package.$callback) requests.remove(reply.context);
         }
 
         if(callback != null) {
@@ -232,23 +257,23 @@
 jvpp_facade_callback_notification_method_template = Template("""
     @Override
     @SuppressWarnings("unchecked")
-    public void on$callback_dto($base_package.$dto_package.$callback_dto notification) {
+    public void on$callback_dto($plugin_package.$dto_package.$callback_dto notification) {
         notificationCallback.on$callback_dto(notification);
     }
 """)
 
 
-def generate_callback(func_list, base_package, dto_package, callback_package, notification_package, callback_facade_package, inputfile):
+def generate_callback(func_list, base_package, plugin_package, plugin_name, dto_package, callback_package, notification_package, callback_facade_package, inputfile):
     callbacks = []
     for func in func_list:
 
-        if util.is_ignored(func['name']):
-            continue
-
         camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name'])
 
+        if util.is_ignored(func['name']) or util.is_control_ping(camel_case_name_with_suffix):
+            continue
+
         if util.is_reply(camel_case_name_with_suffix):
-            callbacks.append(jvpp_facade_callback_method_template.substitute(base_package=base_package,
+            callbacks.append(jvpp_facade_callback_method_template.substitute(plugin_package=plugin_package,
                                                                              dto_package=dto_package,
                                                                              callback_package=callback_package,
                                                                              callback=util.remove_reply_suffix(camel_case_name_with_suffix) + callback_gen.callback_suffix,
@@ -256,15 +281,17 @@
 
         if util.is_notification(func["name"]):
             with_notification_suffix = util.add_notification_suffix(camel_case_name_with_suffix)
-            callbacks.append(jvpp_facade_callback_notification_method_template.substitute(base_package=base_package,
+            callbacks.append(jvpp_facade_callback_notification_method_template.substitute(plugin_package=plugin_package,
                                                                              dto_package=dto_package,
                                                                              callback_package=callback_package,
                                                                              callback=with_notification_suffix + callback_gen.callback_suffix,
                                                                              callback_dto=with_notification_suffix))
 
-    jvpp_file = open(os.path.join(callback_facade_package, "CallbackJVppFacadeCallback.java"), 'w')
+    jvpp_file = open(os.path.join(callback_facade_package, "CallbackJVpp%sFacadeCallback.java" % plugin_name), 'w')
     jvpp_file.write(jvpp_facade_callback_template.substitute(inputfile=inputfile,
                                                              base_package=base_package,
+                                                             plugin_package=plugin_package,
+                                                             plugin_name=plugin_name,
                                                              dto_package=dto_package,
                                                              notification_package=notification_package,
                                                              callback_package=callback_package,
diff --git a/vpp-api/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py b/vpp-api/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py
index e1ca4d0..06c1073 100644
--- a/vpp-api/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py
+++ b/vpp-api/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py
@@ -20,27 +20,28 @@
 import util
 
 jvpp_facade_callback_template = Template("""
-package $base_package.$future_package;
+package $plugin_package.$future_package;
 
 /**
  * <p>Async facade callback setting values to future objects
  * <br>It was generated by jvpp_future_facade_gen.py based on $inputfile
- * <br>(python representation of vpe.api generated by vppapigen).
+ * <br>(python representation of api file generated by vppapigen).
  */
-public final class FutureJVppFacadeCallback implements $base_package.$callback_package.JVppGlobalCallback {
+public final class FutureJVpp${plugin_name}FacadeCallback implements $plugin_package.$callback_package.JVpp${plugin_name}GlobalCallback {
 
     private final java.util.Map<java.lang.Integer, java.util.concurrent.CompletableFuture<? extends $base_package.$dto_package.JVppReply<?>>> requests;
-    private final $base_package.$notification_package.GlobalNotificationCallback notificationCallback;
+    private final $plugin_package.$notification_package.Global${plugin_name}NotificationCallback notificationCallback;
 
-    public FutureJVppFacadeCallback(final java.util.Map<java.lang.Integer, java.util.concurrent.CompletableFuture<? extends $base_package.$dto_package.JVppReply<?>>> requestMap,
-                                    final $base_package.$notification_package.GlobalNotificationCallback notificationCallback) {
+    public FutureJVpp${plugin_name}FacadeCallback(
+        final java.util.Map<java.lang.Integer, java.util.concurrent.CompletableFuture<? extends $base_package.$dto_package.JVppReply<?>>> requestMap,
+        final $plugin_package.$notification_package.Global${plugin_name}NotificationCallback notificationCallback) {
         this.requests = requestMap;
         this.notificationCallback = notificationCallback;
     }
 
     @Override
     @SuppressWarnings("unchecked")
-    public void onError(org.openvpp.jvpp.VppCallbackException reply) {
+    public void onError($base_package.VppCallbackException reply) {
         final java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply<?>> completableFuture;
 
         synchronized(requests) {
@@ -56,6 +57,33 @@
         }
     }
 
+    @Override
+    @SuppressWarnings("unchecked")
+    public void onControlPingReply($base_package.$dto_package.ControlPingReply 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.context);
+        }
+
+        if(completableFuture != null) {
+            // Finish dump call
+            if (completableFuture instanceof $base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture) {
+                completableFuture.complete((($base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture) completableFuture).getReplyDump());
+                // Remove future mapped to dump call context id
+                synchronized(requests) {
+                    requests.remove((($base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture) completableFuture).getContextId());
+                }
+            } else {
+                completableFuture.complete(reply);
+            }
+
+            synchronized(requests) {
+                requests.remove(reply.context);
+            }
+        }
+    }
+
 $methods
 }
 """)
@@ -63,7 +91,7 @@
 jvpp_facade_callback_method_template = Template("""
     @Override
     @SuppressWarnings("unchecked")
-    public void on$callback_dto($base_package.$dto_package.$callback_dto reply) {
+    public void on$callback_dto($plugin_package.$dto_package.$callback_dto reply) {
         final java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply<?>> completableFuture;
 
         synchronized(requests) {
@@ -82,55 +110,25 @@
 
 jvpp_facade_callback_notification_method_template = Template("""
     @Override
-    public void on$callback_dto($base_package.$dto_package.$callback_dto notification) {
+    public void on$callback_dto($plugin_package.$dto_package.$callback_dto notification) {
         notificationCallback.on$callback_dto(notification);
     }
 """)
 
-# TODO reuse common parts with generic method callback
-jvpp_facade_control_ping_method_template = Template("""
-    @Override
-    @SuppressWarnings("unchecked")
-    public void on$callback_dto($base_package.$dto_package.$callback_dto 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.context);
-        }
-
-        if(completableFuture != null) {
-            // Finish dump call
-            if (completableFuture instanceof $base_package.$future_package.FutureJVppFacade.CompletableDumpFuture) {
-                completableFuture.complete((($base_package.$future_package.FutureJVppFacade.CompletableDumpFuture) completableFuture).getReplyDump());
-                // Remove future mapped to dump call context id
-                synchronized(requests) {
-                    requests.remove((($base_package.$future_package.FutureJVppFacade.CompletableDumpFuture) completableFuture).getContextId());
-                }
-            } else {
-                completableFuture.complete(reply);
-            }
-
-            synchronized(requests) {
-                requests.remove(reply.context);
-            }
-        }
-    }
-""")
-
 jvpp_facade_details_callback_method_template = Template("""
     @Override
     @SuppressWarnings("unchecked")
-    public void on$callback_dto($base_package.$dto_package.$callback_dto reply) {
-        final FutureJVppFacade.CompletableDumpFuture<$base_package.$dto_package.$callback_dto_reply_dump> completableFuture;
+    public void on$callback_dto($plugin_package.$dto_package.$callback_dto reply) {
+        final $base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture<$plugin_package.$dto_package.$callback_dto_reply_dump> completableFuture;
 
         synchronized(requests) {
-            completableFuture = ($base_package.$future_package.FutureJVppFacade.CompletableDumpFuture<$base_package.$dto_package.$callback_dto_reply_dump>) requests.get(reply.context);
+            completableFuture = ($base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture<$plugin_package.$dto_package.$callback_dto_reply_dump>) requests.get(reply.context);
         }
 
         if(completableFuture != null) {
-            $base_package.$dto_package.$callback_dto_reply_dump replyDump = completableFuture.getReplyDump();
+            $plugin_package.$dto_package.$callback_dto_reply_dump replyDump = completableFuture.getReplyDump();
             if(replyDump == null) {
-                replyDump = new $base_package.$dto_package.$callback_dto_reply_dump();
+                replyDump = new $plugin_package.$dto_package.$callback_dto_reply_dump();
                 completableFuture.setReplyDump(replyDump);
             }
 
@@ -140,7 +138,7 @@
 """)
 
 
-def generate_jvpp(func_list, base_package, dto_package, callback_package, notification_package, future_facade_package, inputfile):
+def generate_jvpp(func_list, base_package, plugin_package, plugin_name, dto_package, callback_package, notification_package, future_facade_package, inputfile):
     """ Generates JVpp interface and JNI implementation """
     print "Generating JVpp future facade"
 
@@ -151,11 +149,11 @@
     methods_impl = []
     callbacks = []
     for func in func_list:
+        camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name'])
 
-        if util.is_ignored(func['name']):
+        if util.is_ignored(func['name']) or util.is_control_ping(camel_case_name_with_suffix):
             continue
 
-        camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name'])
         if not util.is_reply(camel_case_name_with_suffix) and not util.is_notification(func['name']):
             continue
 
@@ -167,20 +165,21 @@
                 camel_case_reply_name = get_standard_dump_reply_name(util.underscore_to_camelcase_upper(func['name']),
                                                                      func['name'])
                 callbacks.append(jvpp_facade_details_callback_method_template.substitute(base_package=base_package,
+                                                                                         plugin_package=plugin_package,
                                                                                          dto_package=dto_package,
                                                                                          callback_dto=camel_case_name_with_suffix,
                                                                                          callback_dto_field=camel_case_method_name,
                                                                                          callback_dto_reply_dump=camel_case_reply_name + dto_gen.dump_dto_suffix,
                                                                                          future_package=future_facade_package))
 
-                methods.append(future_jvpp_method_template.substitute(base_package=base_package,
+                methods.append(future_jvpp_method_template.substitute(plugin_package=plugin_package,
                                                                       dto_package=dto_package,
                                                                       method_name=camel_case_request_method_name +
                                                                                   util.underscore_to_camelcase_upper(util.dump_suffix),
                                                                       reply_name=camel_case_reply_name + dto_gen.dump_dto_suffix,
                                                                       request_name=util.remove_reply_suffix(camel_case_reply_name) +
                                                                                    util.underscore_to_camelcase_upper(util.dump_suffix)))
-                methods_impl.append(future_jvpp_method_impl_template.substitute(base_package=base_package,
+                methods_impl.append(future_jvpp_method_impl_template.substitute(plugin_package=plugin_package,
                                                                                 dto_package=dto_package,
                                                                                 method_name=camel_case_request_method_name +
                                                                                             util.underscore_to_camelcase_upper(util.dump_suffix),
@@ -191,36 +190,32 @@
                 request_name = util.underscore_to_camelcase_upper(util.unconventional_naming_rep_req[func['name']]) \
                     if func['name'] in util.unconventional_naming_rep_req else util.remove_reply_suffix(camel_case_name_with_suffix)
 
-                methods.append(future_jvpp_method_template.substitute(base_package=base_package,
+                methods.append(future_jvpp_method_template.substitute(plugin_package=plugin_package,
                                                                       dto_package=dto_package,
                                                                       method_name=camel_case_request_method_name,
                                                                       reply_name=camel_case_name_with_suffix,
                                                                       request_name=request_name))
-                methods_impl.append(future_jvpp_method_impl_template.substitute(base_package=base_package,
+                methods_impl.append(future_jvpp_method_impl_template.substitute(plugin_package=plugin_package,
                                                                                 dto_package=dto_package,
                                                                                 method_name=camel_case_request_method_name,
                                                                                 reply_name=camel_case_name_with_suffix,
                                                                                 request_name=request_name))
 
-                # Callback handler is a bit special and a different template has to be used
-                if util.is_control_ping(camel_case_name_with_suffix):
-                    callbacks.append(jvpp_facade_control_ping_method_template.substitute(base_package=base_package,
-                                                                                         dto_package=dto_package,
-                                                                                         callback_dto=camel_case_name_with_suffix,
-                                                                                         future_package=future_facade_package))
-                else:
-                    callbacks.append(jvpp_facade_callback_method_template.substitute(base_package=base_package,
-                                                                                     dto_package=dto_package,
-                                                                                     callback_dto=camel_case_name_with_suffix))
+                callbacks.append(jvpp_facade_callback_method_template.substitute(base_package=base_package,
+                                                                                 plugin_package=plugin_package,
+                                                                                 dto_package=dto_package,
+                                                                                 callback_dto=camel_case_name_with_suffix))
 
         if util.is_notification(func["name"]):
-            callbacks.append(jvpp_facade_callback_notification_method_template.substitute(base_package=base_package,
+            callbacks.append(jvpp_facade_callback_notification_method_template.substitute(plugin_package=plugin_package,
                                                                                           dto_package=dto_package,
                                                                                           callback_dto=util.add_notification_suffix(camel_case_name_with_suffix)))
 
-    jvpp_file = open(os.path.join(future_facade_package, "FutureJVppFacadeCallback.java"), 'w')
+    jvpp_file = open(os.path.join(future_facade_package, "FutureJVpp%sFacadeCallback.java" % plugin_name), 'w')
     jvpp_file.write(jvpp_facade_callback_template.substitute(inputfile=inputfile,
                                                              base_package=base_package,
+                                                             plugin_package=plugin_package,
+                                                             plugin_name=plugin_name,
                                                              dto_package=dto_package,
                                                              notification_package=notification_package,
                                                              callback_package=callback_package,
@@ -229,18 +224,24 @@
     jvpp_file.flush()
     jvpp_file.close()
 
-    jvpp_file = open(os.path.join(future_facade_package, "FutureJVpp.java"), 'w')
+    jvpp_file = open(os.path.join(future_facade_package, "FutureJVpp%s.java" % plugin_name), 'w')
     jvpp_file.write(future_jvpp_template.substitute(inputfile=inputfile,
                                                     base_package=base_package,
+                                                    plugin_package=plugin_package,
+                                                    plugin_name=plugin_name,
+                                                    notification_package=notification_package,
                                                     methods="".join(methods),
                                                     future_package=future_facade_package))
     jvpp_file.flush()
     jvpp_file.close()
 
-    jvpp_file = open(os.path.join(future_facade_package, "FutureJVppFacade.java"), 'w')
+    jvpp_file = open(os.path.join(future_facade_package, "FutureJVpp%sFacade.java" % plugin_name), 'w')
     jvpp_file.write(future_jvpp_facade_template.substitute(inputfile=inputfile,
                                                            base_package=base_package,
+                                                           plugin_package=plugin_package,
+                                                           plugin_name=plugin_name,
                                                            dto_package=dto_package,
+                                                           notification_package=notification_package,
                                                            methods="".join(methods_impl),
                                                            future_package=future_facade_package))
     jvpp_file.flush()
@@ -248,35 +249,41 @@
 
 
 future_jvpp_template = Template('''
-package $base_package.$future_package;
+package $plugin_package.$future_package;
 
 /**
  * <p>Async facade extension adding specific methods for each request invocation
  * <br>It was generated by jvpp_future_facade_gen.py based on $inputfile
- * <br>(python representation of vpe.api generated by vppapigen).
+ * <br>(python representation of api file generated by vppapigen).
  */
-public interface FutureJVpp extends FutureJVppInvoker {
+public interface FutureJVpp${plugin_name} extends $base_package.$future_package.FutureJVppInvoker {
 $methods
+
+    @Override
+    public $plugin_package.$notification_package.${plugin_name}NotificationRegistry getNotificationRegistry();
+
 }
 ''')
 
 future_jvpp_method_template = Template('''
-    java.util.concurrent.CompletionStage<$base_package.$dto_package.$reply_name> $method_name($base_package.$dto_package.$request_name request);
+    java.util.concurrent.CompletionStage<$plugin_package.$dto_package.$reply_name> $method_name($plugin_package.$dto_package.$request_name request);
 ''')
 
 
 future_jvpp_facade_template = Template('''
-package $base_package.$future_package;
+package $plugin_package.$future_package;
 
 /**
- * <p>Implementation of FutureJVpp based on FutureJVppInvokerFacade
+ * <p>Implementation of FutureJVpp based on AbstractFutureJVppInvoker
  * <br>It was generated by jvpp_future_facade_gen.py based on $inputfile
- * <br>(python representation of vpe.api generated by vppapigen).
+ * <br>(python representation of api file generated by vppapigen).
  */
-public class FutureJVppFacade extends FutureJVppInvokerFacade implements FutureJVpp {
+public class FutureJVpp${plugin_name}Facade extends $base_package.$future_package.AbstractFutureJVppInvoker implements FutureJVpp${plugin_name} {
+
+    private final $plugin_package.$notification_package.${plugin_name}NotificationRegistryImpl notificationRegistry = new $plugin_package.$notification_package.${plugin_name}NotificationRegistryImpl();
 
     /**
-     * <p>Create FutureJVppFacade object for provided JVpp instance.
+     * <p>Create FutureJVpp${plugin_name}Facade object for provided JVpp instance.
      * Constructor internally creates FutureJVppFacadeCallback class for processing callbacks
      * and then connects to provided JVpp instance
      *
@@ -284,17 +291,24 @@
      *
      * @throws java.io.IOException in case instance cannot connect to JVPP
      */
-    public FutureJVppFacade(final $base_package.JVpp jvpp) throws java.io.IOException {
-        super(jvpp, new java.util.HashMap<>());
-        jvpp.connect(new FutureJVppFacadeCallback(getRequests(), getNotificationCallback()));
+    public FutureJVpp${plugin_name}Facade(final $base_package.JVppRegistry registry, final $base_package.JVpp jvpp) throws java.io.IOException {
+        super(jvpp, registry, new java.util.HashMap<>());
+        java.util.Objects.requireNonNull(registry, "JVppRegistry should not be null");
+        registry.register(jvpp, new FutureJVpp${plugin_name}FacadeCallback(getRequests(), notificationRegistry));
     }
+
+    @Override
+    public $plugin_package.$notification_package.${plugin_name}NotificationRegistry getNotificationRegistry() {
+        return notificationRegistry;
+    }
+
 $methods
 }
 ''')
 
 future_jvpp_method_impl_template = Template('''
     @Override
-    public java.util.concurrent.CompletionStage<$base_package.$dto_package.$reply_name> $method_name($base_package.$dto_package.$request_name request) {
+    public java.util.concurrent.CompletionStage<$plugin_package.$dto_package.$reply_name> $method_name($plugin_package.$dto_package.$request_name request) {
         return send(request);
     }
 ''')
diff --git a/vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py b/vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py
index 93ffd0f..41df4f2 100644
--- a/vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py
+++ b/vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py
@@ -17,25 +17,14 @@
 from string import Template
 
 jvpp_ifc_template = Template("""
-package $base_package;
-
+package $plugin_package;
 
 /**
- * <p>Java representation of vpe.api.
+ * <p>Java representation of plugin's api file.
  * <br>It was generated by jvpp_impl_gen.py based on $inputfile
- * <br>(python representation of vpe.api generated by vppapigen).
+ * <br>(python representation of api file generated by vppapigen).
  */
-public interface JVpp extends java.lang.AutoCloseable {
-
-    /**
-     * Generic connect with $base_package.callback.JVppCallback callback handler
-     * providing connecting to VPP
-     *
-     * @param callback JVppCallback instance providing callback handling
-     *
-     * @throws java.io.IOException if connection cannot be initiated
-     */
-    void connect($base_package.callback.JVppCallback callback) throws java.io.IOException;
+public interface JVpp${plugin_name} extends $base_package.JVpp {
 
     /**
      * Generic dispatch method for sending requests to VPP
@@ -44,52 +33,110 @@
      */
     int send($base_package.$dto_package.JVppRequest request) throws org.openvpp.jvpp.VppInvocationException;
 
-    @Override
-    void close();
-
 $methods
 }
 """)
 
 jvpp_impl_template = Template("""
-package $base_package;
+package $plugin_package;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.util.Set;
+import java.util.logging.Logger;
+import $base_package.callback.JVppCallback;
+import $base_package.VppConnection;
+import $base_package.JVppRegistry;
 
 /**
  * <p>Default implementation of JVpp interface.
  * <br>It was generated by jvpp_impl_gen.py based on $inputfile
- * <br>(python representation of vpe.api generated by vppapigen).
+ * <br>(python representation of api file generated by vppapigen).
  */
-public final class JVppImpl implements $base_package.JVpp {
+public final class JVpp${plugin_name}Impl implements $plugin_package.JVpp${plugin_name} {
 
-    private final $base_package.VppConnection connection;
+    private final static Logger LOG = Logger.getLogger(JVpp${plugin_name}Impl.class.getName());
+    private static final String LIBNAME = "libjvpp_${plugin_name_underscore}.so.0.0.0";
 
-    public JVppImpl(final $base_package.VppConnection connection) {
-        this.connection = java.util.Objects.requireNonNull(connection,"Connection is null");
+    // FIXME using NativeLibraryLoader makes load fail could not find (WantInterfaceEventsReply).
+    static {
+        try {
+            loadLibrary();
+        } catch (Exception e) {
+            LOG.severe("Can't find jvpp jni library: " + LIBNAME);
+            throw new ExceptionInInitializerError(e);
+        }
     }
 
+    private static void loadStream(final InputStream is) throws IOException {
+        final Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rwxr-x---");
+        final Path p = Files.createTempFile(LIBNAME, null, PosixFilePermissions.asFileAttribute(perms));
+        try {
+            Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING);
+
+            try {
+                Runtime.getRuntime().load(p.toString());
+            } catch (UnsatisfiedLinkError e) {
+                throw new IOException("Failed to load library " + p, e);
+            }
+        } finally {
+            try {
+                Files.deleteIfExists(p);
+            } catch (IOException e) {
+            }
+        }
+    }
+
+    private static void loadLibrary() throws IOException {
+        try (final InputStream is = JVpp${plugin_name}Impl.class.getResourceAsStream('/' + LIBNAME)) {
+            if (is == null) {
+                throw new IOException("Failed to open library resource " + LIBNAME);
+            }
+            loadStream(is);
+        }
+    }
+
+    private VppConnection connection;
+    private JVppRegistry registry;
+
+    private static native void init0(final JVppCallback callback, final long queueAddress, final int clientIndex);
     @Override
-    public void connect($base_package.callback.JVppCallback callback) throws java.io.IOException {
-        connection.connect(callback);
+    public void init(final JVppRegistry registry, final JVppCallback callback, final long queueAddress, final int clientIndex) {
+        this.registry = java.util.Objects.requireNonNull(registry, "registry should not be null");
+        this.connection = java.util.Objects.requireNonNull(registry.getConnection(), "connection should not be null");
+        connection.checkActive();
+        init0(callback, queueAddress, clientIndex);
     }
 
+    private static native void close0();
     @Override
     public void close() {
-        connection.close();
+        close0();
     }
 
     @Override
-    public int send($base_package.$dto_package.JVppRequest request)  throws org.openvpp.jvpp.VppInvocationException {
+    public int send($base_package.$dto_package.JVppRequest request) throws org.openvpp.jvpp.VppInvocationException {
         return request.send(this);
     }
 
+    @Override
+    public final int controlPing(final org.openvpp.jvpp.dto.ControlPing controlPing) throws org.openvpp.jvpp.VppInvocationException {
+        return registry.controlPing(JVpp${plugin_name}Impl.class);
+    }
+
 $methods
 }
 """)
 
-method_template = Template("""    int $name($base_package.$dto_package.$request request) throws org.openvpp.jvpp.VppInvocationException;""")
+method_template = Template("""    int $name($plugin_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) throws org.openvpp.jvpp.VppInvocationException {
+    """    private static native int ${name}0($plugin_package.$dto_package.$request request);""")
+method_impl_template = Template("""    public final int $name($plugin_package.$dto_package.$request request) throws org.openvpp.jvpp.VppInvocationException {
         java.util.Objects.requireNonNull(request,"Null request object");
         connection.checkActive();
         int result=${name}0(request);
@@ -113,9 +160,10 @@
 """)
 
 
-def generate_jvpp(func_list, base_package, dto_package, inputfile):
+def generate_jvpp(func_list, base_package, plugin_package, plugin_name_underscore, control_ping_class, dto_package, inputfile):
     """ Generates JVpp interface and JNI implementation """
     print "Generating JVpp"
+    plugin_name = util.underscore_to_camelcase_upper(plugin_name_underscore)
 
     methods = []
     methods_impl = []
@@ -131,43 +179,42 @@
             continue
 
         if len(func['args']) == 0:
-            methods.append(no_arg_method_template.substitute(name=camel_case_name,
-                                                             base_package=base_package,
-                                                             dto_package=dto_package))
-            methods_impl.append(
-                no_arg_method_native_template.substitute(name=camel_case_name,
-                                                         base_package=base_package,
-                                                         dto_package=dto_package))
-            methods_impl.append(no_arg_method_impl_template.substitute(name=camel_case_name,
-                                                                       base_package=base_package,
-                                                                       dto_package=dto_package))
+            methods.append(no_arg_method_template.substitute(name=camel_case_name))
+            methods_impl.append(no_arg_method_native_template.substitute(name=camel_case_name))
+            methods_impl.append(no_arg_method_impl_template.substitute(name=camel_case_name))
         else:
             methods.append(method_template.substitute(name=camel_case_name,
                                                       request=camel_case_name_upper,
-                                                      base_package=base_package,
+                                                      plugin_package=plugin_package,
                                                       dto_package=dto_package))
             methods_impl.append(method_native_template.substitute(name=camel_case_name,
                                                                   request=camel_case_name_upper,
-                                                                  base_package=base_package,
+                                                                  plugin_package=plugin_package,
                                                                   dto_package=dto_package))
             methods_impl.append(method_impl_template.substitute(name=camel_case_name,
                                                                 request=camel_case_name_upper,
-                                                                base_package=base_package,
+                                                                plugin_package=plugin_package,
                                                                 dto_package=dto_package))
 
-    jvpp_file = open("JVpp.java", 'w')
+    jvpp_file = open("JVpp%s.java" % plugin_name, 'w')
     jvpp_file.write(
         jvpp_ifc_template.substitute(inputfile=inputfile,
                                      methods="\n".join(methods),
                                      base_package=base_package,
+                                     plugin_package=plugin_package,
+                                     plugin_name=plugin_name,
                                      dto_package=dto_package))
     jvpp_file.flush()
     jvpp_file.close()
 
-    jvpp_file = open("JVppImpl.java", 'w')
+    jvpp_file = open("JVpp%sImpl.java" % plugin_name, 'w')
     jvpp_file.write(jvpp_impl_template.substitute(inputfile=inputfile,
                                                   methods="\n".join(methods_impl),
                                                   base_package=base_package,
-                                                  dto_package=dto_package))
+                                                  plugin_package=plugin_package,
+                                                  plugin_name=plugin_name,
+                                                  plugin_name_underscore=plugin_name_underscore,
+                                                  dto_package=dto_package,
+                                                  control_ping_class=control_ping_class))
     jvpp_file.flush()
     jvpp_file.close()
diff --git a/vpp-api/java/jvpp/gen/jvppgen/notification_gen.py b/vpp-api/java/jvpp/gen/jvppgen/notification_gen.py
index df6407f..eb380fc 100644
--- a/vpp-api/java/jvpp/gen/jvppgen/notification_gen.py
+++ b/vpp-api/java/jvpp/gen/jvppgen/notification_gen.py
@@ -19,17 +19,15 @@
 import util
 from string import Template
 
-from util import remove_suffix
-
 notification_registry_template = Template("""
-package $base_package.$notification_package;
+package $plugin_package.$notification_package;
 
 /**
- * <p>Registry for notification callbacks.
+ * <p>Registry for notification callbacks defined in ${plugin_name}.
  * <br>It was generated by notification_gen.py based on $inputfile
- * <br>(python representation of vpe.api generated by vppapigen).
+ * <br>(python representation of api file generated by vppapigen).
  */
-public interface NotificationRegistry extends java.lang.AutoCloseable {
+public interface ${plugin_name}NotificationRegistry extends $base_package.$notification_package.NotificationRegistry {
 
     $register_callback_methods
 
@@ -39,27 +37,27 @@
 """)
 
 global_notification_callback_template = Template("""
-package $base_package.$notification_package;
+package $plugin_package.$notification_package;
 
 /**
  * <p>Aggregated callback interface for notifications only.
  * <br>It was generated by notification_gen.py based on $inputfile
- * <br>(python representation of vpe.api generated by vppapigen).
+ * <br>(python representation of api file generated by vppapigen).
  */
-public interface GlobalNotificationCallback extends $callbacks {
+public interface Global${plugin_name}NotificationCallback$callbacks {
 
 }
 """)
 
 notification_registry_impl_template = Template("""
-package $base_package.$notification_package;
+package $plugin_package.$notification_package;
 
 /**
  * <p>Notification registry delegating notification processing to registered callbacks.
  * <br>It was generated by notification_gen.py based on $inputfile
- * <br>(python representation of vpe.api generated by vppapigen).
+ * <br>(python representation of api file generated by vppapigen).
  */
-public final class NotificationRegistryImpl implements NotificationRegistry, GlobalNotificationCallback {
+public final class ${plugin_name}NotificationRegistryImpl implements ${plugin_name}NotificationRegistry, Global${plugin_name}NotificationCallback {
 
     // TODO add a special NotificationCallback interface and only allow those to be registered
     private final java.util.concurrent.ConcurrentMap<Class<? extends $base_package.$dto_package.JVppNotification>, $base_package.$callback_package.JVppNotificationCallback> registeredCallbacks =
@@ -76,30 +74,45 @@
 """)
 
 register_callback_impl_template = Template("""
-    public java.lang.AutoCloseable register$callback(final $base_package.$callback_package.$callback callback){
-        if(null != registeredCallbacks.putIfAbsent($base_package.$dto_package.$notification.class, callback)){
-            throw new IllegalArgumentException("Callback for " + $base_package.$dto_package.$notification.class +
+    public java.lang.AutoCloseable register$callback(final $plugin_package.$callback_package.$callback callback){
+        if(null != registeredCallbacks.putIfAbsent($plugin_package.$dto_package.$notification.class, callback)){
+            throw new IllegalArgumentException("Callback for " + $plugin_package.$dto_package.$notification.class +
                 "notification already registered");
         }
-        return () -> registeredCallbacks.remove($base_package.$dto_package.$notification.class);
+        return () -> registeredCallbacks.remove($plugin_package.$dto_package.$notification.class);
     }
 """)
 
 handler_impl_template = Template("""
     @Override
     public void on$notification(
-        final $base_package.$dto_package.$notification notification) {
-        final $base_package.$callback_package.JVppNotificationCallback JVppNotificationCallback = registeredCallbacks.get($base_package.$dto_package.$notification.class);
-        if (null != JVppNotificationCallback) {
-            (($base_package.$callback_package.$callback) registeredCallbacks
-                .get($base_package.$dto_package.$notification.class))
+        final $plugin_package.$dto_package.$notification notification) {
+        final $base_package.$callback_package.JVppNotificationCallback jVppNotificationCallback = registeredCallbacks.get($plugin_package.$dto_package.$notification.class);
+        if (null != jVppNotificationCallback) {
+            (($plugin_package.$callback_package.$callback) registeredCallbacks
+                .get($plugin_package.$dto_package.$notification.class))
                 .on$notification(notification);
         }
     }
 """)
 
+notification_provider_template = Template("""
+package $plugin_package.$notification_package;
 
-def generate_notification_registry(func_list, base_package, notification_package, callback_package, dto_package, inputfile):
+ /**
+ * Provides ${plugin_name}NotificationRegistry.
+ * <br>The file was generated by notification_gen.py based on $inputfile
+ * <br>(python representation of api file generated by vppapigen).
+ */
+public interface ${plugin_name}NotificationRegistryProvider extends $base_package.$notification_package.NotificationRegistryProvider {
+
+    @Override
+    public ${plugin_name}NotificationRegistry getNotificationRegistry();
+}
+""")
+
+
+def generate_notification_registry(func_list, base_package, plugin_package, plugin_name, notification_package, callback_package, dto_package, inputfile):
     """ Generates notification registry interface and implementation """
     print "Generating Notification interfaces and implementation"
 
@@ -118,47 +131,69 @@
         camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name'])
         notification_dto = util.add_notification_suffix(camel_case_name_with_suffix)
         callback_ifc = notification_dto + callback_gen.callback_suffix
-        fully_qualified_callback_ifc = "{0}.{1}.{2}".format(base_package, callback_package, callback_ifc)
+        fully_qualified_callback_ifc = "{0}.{1}.{2}".format(plugin_package, callback_package, callback_ifc)
         callbacks.append(fully_qualified_callback_ifc)
 
         # TODO create NotificationListenerRegistration and return that instead of AutoCloseable to better indicate
         # that the registration should be closed
         register_callback_methods.append("java.lang.AutoCloseable register{0}({1} callback);"
                                          .format(callback_ifc, fully_qualified_callback_ifc))
-        register_callback_methods_impl.append(register_callback_impl_template.substitute(base_package=base_package,
+        register_callback_methods_impl.append(register_callback_impl_template.substitute(plugin_package=plugin_package,
                                                                                          callback_package=callback_package,
                                                                                          dto_package=dto_package,
                                                                                          notification=notification_dto,
                                                                                          callback=callback_ifc))
         handler_methods.append(handler_impl_template.substitute(base_package=base_package,
+                                                                plugin_package=plugin_package,
                                                                 callback_package=callback_package,
                                                                 dto_package=dto_package,
                                                                 notification=notification_dto,
                                                                 callback=callback_ifc))
-    if(callbacks):
-      callback_file = open(os.path.join(notification_package, "NotificationRegistry.java"), 'w')
-      callback_file.write(notification_registry_template.substitute(inputfile=inputfile,
-                                                                    register_callback_methods="\n    ".join(register_callback_methods),
-                                                                    base_package=base_package,
-                                                                    notification_package=notification_package))
-      callback_file.flush()
-      callback_file.close()
 
-      callback_file = open(os.path.join(notification_package, "GlobalNotificationCallback.java"), 'w')
-      callback_file.write(global_notification_callback_template.substitute(inputfile=inputfile,
-                                                                           callbacks=", ".join(callbacks),
-                                                                           base_package=base_package,
-                                                                           notification_package=notification_package))
-      callback_file.flush()
-      callback_file.close()
 
-      callback_file = open(os.path.join(notification_package, "NotificationRegistryImpl.java"), 'w')
-      callback_file.write(notification_registry_impl_template.substitute(inputfile=inputfile,
-                                                                         callback_package=callback_package,
-                                                                         dto_package=dto_package,
-                                                                         register_callback_methods="".join(register_callback_methods_impl),
-                                                                         handler_methods="".join(handler_methods),
-                                                                         base_package=base_package,
-                                                                         notification_package=notification_package))
-      callback_file.flush()
-      callback_file.close()
+    callback_file = open(os.path.join(notification_package, "%sNotificationRegistry.java" % plugin_name), 'w')
+    callback_file.write(notification_registry_template.substitute(inputfile=inputfile,
+                                                                register_callback_methods="\n    ".join(register_callback_methods),
+                                                                base_package=base_package,
+                                                                plugin_package=plugin_package,
+                                                                plugin_name=plugin_name,
+                                                                notification_package=notification_package))
+    callback_file.flush()
+    callback_file.close()
+
+    callback_file = open(os.path.join(notification_package, "Global%sNotificationCallback.java" % plugin_name), 'w')
+
+    global_notification_callback_callbacks = ""
+    if (callbacks):
+        global_notification_callback_callbacks = " extends " + ", ".join(callbacks)
+
+    callback_file.write(global_notification_callback_template.substitute(inputfile=inputfile,
+                                                                       callbacks=global_notification_callback_callbacks,
+                                                                       plugin_package=plugin_package,
+                                                                       plugin_name=plugin_name,
+                                                                       notification_package=notification_package))
+    callback_file.flush()
+    callback_file.close()
+
+    callback_file = open(os.path.join(notification_package, "%sNotificationRegistryImpl.java" % plugin_name), 'w')
+    callback_file.write(notification_registry_impl_template.substitute(inputfile=inputfile,
+                                                                     callback_package=callback_package,
+                                                                     dto_package=dto_package,
+                                                                     register_callback_methods="".join(register_callback_methods_impl),
+                                                                     handler_methods="".join(handler_methods),
+                                                                     base_package=base_package,
+                                                                     plugin_package=plugin_package,
+                                                                     plugin_name=plugin_name,
+                                                                     notification_package=notification_package))
+    callback_file.flush()
+    callback_file.close()
+
+    callback_file = open(os.path.join(notification_package, "%sNotificationRegistryProvider.java" % plugin_name), 'w')
+    callback_file.write(notification_provider_template.substitute(inputfile=inputfile,
+                                                                     base_package=base_package,
+                                                                     plugin_package=plugin_package,
+                                                                     plugin_name=plugin_name,
+                                                                     notification_package=notification_package))
+    callback_file.flush()
+    callback_file.close()
+
diff --git a/vpp-api/java/jvpp/gen/jvppgen/util.py b/vpp-api/java/jvpp/gen/jvppgen/util.py
index f22132d..0018e01 100644
--- a/vpp-api/java/jvpp/gen/jvppgen/util.py
+++ b/vpp-api/java/jvpp/gen/jvppgen/util.py
@@ -120,15 +120,18 @@
     'jfloatArray': 'ObjectField'
 }
 
-# TODO watch out for unsigned types
+# Mapping according to:
 # http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html
-vpp_2_jni_type_mapping = {'u8': 'jbyte',  # fixme
+#
+# Unsigned types are converted to signed java types that have the same size.
+# It is the API user responsibility to interpret them correctly.
+vpp_2_jni_type_mapping = {'u8': 'jbyte',
                           'i8': 'jbyte',
                           'u16': 'jshort',
                           'i16': 'jshort',
-                          'u32': 'jint',  # fixme
+                          'u32': 'jint',
                           'i32': 'jint',
-                          'u64': 'jlong',  # fixme
+                          'u64': 'jlong',
                           'i64': 'jlong',
                           'f64': 'jdouble'
                           }
@@ -179,7 +182,7 @@
 
 
 def is_control_ping(camel_case_name_with_suffix):
-    return "controlping" in camel_case_name_with_suffix.lower()
+    return camel_case_name_with_suffix.lower().startswith("controlping");
 
 def api_message_to_javadoc(api_message):
     """ Converts vpe.api message description to javadoc """
diff --git a/vpp-api/java/jvpp/jvpp.c b/vpp-api/java/jvpp/jvpp.c
deleted file mode 100644
index 37aef80..0000000
--- a/vpp-api/java/jvpp/jvpp.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * 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.
- */
-#define _GNU_SOURCE /* for strcasestr(3) */
-#include <vnet/vnet.h>
-
-#define vl_api_version(n,v) static u32 vpe_api_version = (v);
-#include <vpp-api/vpe.api.h>
-#undef vl_api_version
-
-#include <jni.h>
-#include <jvpp/jvpp.h>
-#include <jvpp/org_openvpp_jvpp_VppJNIConnection.h>
-#include <jvpp/org_openvpp_jvpp_JVppImpl.h>
-
-#include <vpp-api/vpe_msg_enum.h>
-#define vl_typedefs             /* define message structures */
-#include <vpp-api/vpe_all_api_h.h>
-#undef vl_typedefs
-
-#define vl_endianfun
-#include <vpp-api/vpe_all_api_h.h>
-#undef vl_endianfun
-
-/* instantiate all the print functions we know about */
-#define vl_print(handle, ...)
-#define vl_printfun
-#include <vpp-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__)
-#else
-  #define DEBUG_LOG(...)
-#endif
-
-#include "gen/target/jvpp_gen.h"
-
-static int connect_to_vpe(char *name);
-
-/*
- * The Java runtime isn't compile w/ -fstack-protector,
- * so we have to supply missing external references for the
- * regular vpp libraries. Weak reference in case folks get religion
- * at a later date...
- */
-void __stack_chk_guard (void) __attribute__((weak));
-void __stack_chk_guard (void) {  }
-
-void vl_client_add_api_signatures (vl_api_memclnt_create_t *mp)
-{
-    /*
-     * Send the main API signature in slot 0. This bit of code must
-     * match the checks in ../vpe/api/api.c: vl_msg_api_version_check().
-     */
-    mp->api_versions[0] = clib_host_to_net_u32 (vpe_api_version);
-}
-
-/* cleanup handler for RX thread */
-static void cleanup_rx_thread(void *arg)
-{
-    vppjni_main_t * jm = &vppjni_main;
-
-    vppjni_lock (jm, 99);
-
-    int getEnvStat = (*jm->jvm)->GetEnv(jm->jvm, (void **)&(jm->jenv), JNI_VERSION_1_8);
-    if (getEnvStat == JNI_EVERSION) {
-        clib_warning ("Unsupported JNI version\n");
-        jm->retval = VNET_API_ERROR_UNSUPPORTED_JNI_VERSION;
-        goto out;
-    } else if (getEnvStat != JNI_EDETACHED) {
-        (*jm->jvm)->DetachCurrentThread(jm->jvm);
-    }
-out:
-    vppjni_unlock (jm);
-}
-
-JNIEXPORT jint JNICALL Java_org_openvpp_jvpp_VppJNIConnection_clientConnect
-  (JNIEnv *env, jclass obj, jstring clientName, jobject callback)
-{
-    int rv;
-    const char *client_name;
-    void vl_msg_reply_handler_hookup(void);
-    vppjni_main_t * jm = &vppjni_main;
-
-    /*
-     * Bail out now if we're not running as root
-     */
-    if (geteuid() != 0)
-        return VNET_API_ERROR_NOT_RUNNING_AS_ROOT;
-
-    if (jm->is_connected)
-        return VNET_API_ERROR_ALREADY_CONNECTED;
-
-    client_name = (*env)->GetStringUTFChars(env, clientName, 0);
-    if (!client_name)
-        return VNET_API_ERROR_INVALID_VALUE;
-
-    rv = connect_to_vpe ((char *) client_name);
-
-    if (rv < 0)
-        clib_warning ("connection failed, rv %d", rv);
-
-    (*env)->ReleaseStringUTFChars (env, clientName, client_name);
-
-    if (rv == 0) {
-        f64 timeout;
-        clib_time_t clib_time;
-        clib_time_init (&clib_time);
-
-        /* vl_msg_reply_handler_hookup (); */
-        jm->is_connected = 1;
-
-        jm->callback = (*env)->NewGlobalRef(env, callback);
-        jm->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback));
-
-        {
-            // call control ping first to attach rx thread to java thread
-            vl_api_control_ping_t * mp;
-            M(CONTROL_PING, control_ping);
-            S;
-
-            // wait for results: Current time + 10 seconds is the timeout
-            timeout = clib_time_now (&clib_time) + 10.0;
-            rv = VNET_API_ERROR_RESPONSE_NOT_READY;
-            while (clib_time_now (&clib_time) < timeout) {
-              if (jm->result_ready == 1) {
-                rv = (jm->retval);
-                break;
-              }
-            }
-
-            if (rv != 0) {
-                clib_warning ("first control ping failed: %d", rv);
-            }
-        }
-    }
-    DEBUG_LOG ("clientConnect result: %d", rv);
-    return rv;
-}
-
-JNIEXPORT void JNICALL Java_org_openvpp_jvpp_VppJNIConnection_clientDisconnect
-  (JNIEnv *env, jclass clazz)
-{
-    vppjni_main_t * jm = &vppjni_main;
-    jm->is_connected = 0; // TODO make thread safe
-    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
-(vl_api_control_ping_reply_t * mp)
-{
-    vppjni_main_t * jm = &vppjni_main;
-
-    char was_thread_connected = 0;
-
-    // attach to java thread if not attached
-    int getEnvStat = (*jm->jvm)->GetEnv(jm->jvm, (void **)&(jm->jenv), JNI_VERSION_1_8);
-    if (getEnvStat == JNI_EDETACHED) {
-        if ((*jm->jvm)->AttachCurrentThread(jm->jvm, (void **)&(jm->jenv), NULL) != 0) {
-            clib_warning("Failed to attach thread\n");
-            jm->retval = VNET_API_ERROR_FAILED_TO_ATTACH_TO_JAVA_THREAD;
-            goto out;
-        }
-
-        // workaround as we can't use pthread_cleanup_push
-        pthread_key_create(&jm->cleanup_rx_thread_key, cleanup_rx_thread);
-        // destructor is only called if the value of key is non null
-        pthread_setspecific(jm->cleanup_rx_thread_key, (void *)1);
-        was_thread_connected = 1;
-    } else if (getEnvStat == JNI_EVERSION) {
-        clib_warning ("Unsupported JNI version\n");
-        jm->retval = VNET_API_ERROR_UNSUPPORTED_JNI_VERSION;
-        goto out;
-    }
-
-    if (was_thread_connected == 0) {
-        JNIEnv *env = jm->jenv;
-
-        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);
-
-            jfieldID contextFieldId = (*env)->GetFieldID(env, controlPingReplyClass, "context", "I");
-            (*env)->SetIntField(env, dto, contextFieldId, clib_net_to_host_u32(mp->context));
-
-            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));
-
-            (*env)->CallVoidMethod(env, jm->callback, callbackMethod, dto);
-        }
-    }
-
-    out:
-        jm->result_ready = 1;
-}
-
-jint JNI_OnLoad(JavaVM *vm, void *reserved) {
-    vppjni_main_t * jm = &vppjni_main;
-    JNIEnv* env;
-    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) {
-        return JNI_EVERSION;
-    }
-
-    if (cache_class_references(env) != 0) {
-        return JNI_ERR;
-    }
-
-    jm->jvm = vm;
-    return JNI_VERSION_1_8;
-}
-
-void JNI_OnUnload(JavaVM *vm, void *reserved) {
-    vppjni_main_t * jm = &vppjni_main;
-    JNIEnv* env;
-    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) {
-        return;
-    }
-
-    // cleanup:
-    (*env)->DeleteGlobalRef(env, jm->callbackClass);
-    (*env)->DeleteGlobalRef(env, jm->callback);
-
-    jm->callbackClass = NULL;
-    jm->callback = NULL;
-    jm->jenv = NULL;
-    jm->jvm = NULL;
-}
-
-static int connect_to_vpe(char *name)
-{
-    vppjni_main_t * jm = &vppjni_main;
-    api_main_t * am = &api_main;
-
-    if (vl_client_connect_to_vlib("/vpe-api", name, 32) < 0)
-        return -1;
-
-    jm->my_client_index = am->my_client_index;
-    jm->vl_input_queue = am->shmem_hdr->vl_input_queue;
-
-#define _(N,n)                                  \
-    vl_msg_api_set_handlers(VL_API_##N, #n,     \
-            vl_api_##n##_t_handler,	            \
-            vl_noop_handler,                    \
-            vl_api_##n##_t_endian,              \
-            vl_api_##n##_t_print,               \
-            sizeof(vl_api_##n##_t), 1);
-    foreach_vpe_api_msg;
-#undef _
-
-    return 0;
-}
diff --git a/vpp-api/java/jvpp/jvpp.h b/vpp-api/java/jvpp/jvpp.h
deleted file mode 100644
index 15f9057..0000000
--- a/vpp-api/java/jvpp/jvpp.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * 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.
- */
-#ifndef __included_vppjni_h__
-#define __included_vppjni_h__
-
-#include <vnet/vnet.h>
-#include <vnet/ip/ip.h>
-#include <vnet/api_errno.h>
-#include <vlibapi/api.h>
-#include <vlibmemory/api.h>
-#include <jni.h>
-
-typedef struct {
-    /* Unique identifier used for matching replays with requests  */
-    volatile u32 context_id;
-
-    /* Spinlock */
-    volatile u32 lock;
-    u32 tag;
-
-    /* Used for first control ping */
-    // TODO better names?
-    volatile u32 result_ready;
-    volatile i32 retval;
-
-    /* JNI Native Method Interface pointer for message handlers */
-    JNIEnv *jenv;
-
-    /* thread cleanup */
-    pthread_key_t cleanup_rx_thread_key;
-
-    /* JNI Invoke Interface pointer for attachment of rx thread to java thread */
-    JavaVM *jvm;
-
-    /* Callback object and class references enabling asynchronous Java calls */
-    jobject callback;
-    jclass callbackClass;
-
-    /* Connected indication */
-    volatile u8 is_connected;
-
-    /* Convenience */
-    unix_shared_memory_queue_t * vl_input_queue;
-    u32 my_client_index;
-
-} vppjni_main_t;
-
-vppjni_main_t vppjni_main __attribute__((aligned (64)));
-
-static inline u32 vppjni_get_context_id (vppjni_main_t * jm)
-{
-    return __sync_add_and_fetch (&jm->context_id, 1);
-}
-
-static inline void vppjni_lock (vppjni_main_t * jm, u32 tag)
-{
-    while (__sync_lock_test_and_set (&jm->lock, 1))
-        ;
-    jm->tag = tag;
-}
-
-static inline void vppjni_unlock (vppjni_main_t * jm)
-{
-    jm->tag = 0;
-    CLIB_MEMORY_BARRIER();
-    jm->lock = 0;
-}
-
-static inline int vppjni_sanity_check (vppjni_main_t * jm)
-{
-    if (!jm->is_connected)
-        return VNET_API_ERROR_NOT_CONNECTED;
-    return 0;
-}
-
-// TODO remove macros (code is now fully autogenerated)
-
-/* M: construct, but don't yet send a message */
-#define M(T,t)                                  \
-do {                                            \
-    jm->result_ready = 0;                         \
-    mp = vl_msg_api_alloc(sizeof(*mp));           \
-    memset (mp, 0, sizeof (*mp));                 \
-    mp->_vl_msg_id = ntohs (VL_API_##T);          \
-    mp->client_index = jm->my_client_index;       \
- } while(0);
-
-#define M2(T,t,n)                               \
-do {                                            \
-    jm->result_ready = 0;                         \
-    mp = vl_msg_api_alloc(sizeof(*mp)+(n));       \
-    memset (mp, 0, sizeof (*mp));                 \
-    mp->_vl_msg_id = ntohs (VL_API_##T);          \
-    mp->client_index = jm->my_client_index;       \
- } while(0);
-
-/* S: send a message */
-#define S (vl_msg_api_send_shmem (jm->vl_input_queue, (u8 *)&mp))
-
-#endif /* __included_vppjni_h__ */
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/VppJNIConnection.java b/vpp-api/java/jvpp/org/openvpp/jvpp/VppJNIConnection.java
deleted file mode 100644
index 7401bca..0000000
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/VppJNIConnection.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * 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;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
-import java.nio.file.attribute.PosixFilePermission;
-import java.nio.file.attribute.PosixFilePermissions;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.logging.Logger;
-import org.openvpp.jvpp.callback.JVppCallback;
-
-/**
- * JNI based representation of a management connection to VPP
- */
-public final class VppJNIConnection implements VppConnection {
-    private final static Logger LOG = Logger.getLogger(VppJNIConnection.class.getName());
-    private static final String LIBNAME = "libjvpp.so.0.0.0";
-
-    static {
-        try {
-            loadLibrary();
-        } catch (Exception e) {
-            LOG.severe("Can't find vpp jni library: " + LIBNAME);
-            throw new ExceptionInInitializerError(e);
-        }
-    }
-
-    private static void loadStream(final InputStream is) throws IOException {
-        final Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rwxr-x---");
-        final Path p = Files.createTempFile(LIBNAME, null, PosixFilePermissions.asFileAttribute(perms));
-        try {
-            Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING);
-
-            try {
-                Runtime.getRuntime().load(p.toString());
-            } catch (UnsatisfiedLinkError e) {
-                throw new IOException("Failed to load library " + p, e);
-            }
-        } finally {
-            try {
-                Files.deleteIfExists(p);
-            } catch (IOException e) {
-            }
-        }
-    }
-
-    private static void loadLibrary() throws IOException {
-        try (final InputStream is = VppJNIConnection.class.getResourceAsStream('/' + LIBNAME)) {
-            if (is == null) {
-                throw new IOException("Failed to open library resource " + LIBNAME);
-            }
-            loadStream(is);
-        }
-    }
-
-    private final String clientName;
-    private volatile boolean disconnected = false;
-
-    /**
-     * Create VPPJNIConnection instance for client connecting to VPP.
-     *
-     * @param clientName client name instance to be used for communication. Single connection per clientName is allowed.
-     */
-    public VppJNIConnection(final String clientName) {
-        this.clientName = Objects.requireNonNull(clientName,"Null clientName");
-    }
-
-    /**
-     * Guarded by VppJNIConnection.class
-     */
-    private static final Map<String, VppJNIConnection> connections = new HashMap<>();
-
-    /**
-     * Initiate VPP connection for current instance
-     *
-     * Multiple instances are allowed since this class is not a singleton
-     * (VPP allows multiple management connections).
-     *
-     * However only a single connection per clientName is allowed.
-     *
-     * @param callback global callback to receive response calls from vpp
-     *
-     * @throws IOException in case the connection could not be established
-     */
-    public void connect(final JVppCallback callback) throws IOException {
-        synchronized (VppJNIConnection.class) {
-            if(connections.containsKey(clientName)) {
-                throw new IOException("Client " + clientName + " already connected");
-            }
-
-            final int ret = clientConnect(clientName, callback);
-            if (ret != 0) {
-                throw new IOException("Connection returned error " + ret);
-            }
-            connections.put(clientName, this);
-        }
-    }
-
-    @Override
-    public final void checkActive() {
-        if (disconnected) {
-            throw new IllegalStateException("Disconnected client " + clientName);
-        }
-    }
-
-    @Override
-    public synchronized final void close() {
-        if (!disconnected) {
-            disconnected = true;
-            try {
-                clientDisconnect();
-            } finally {
-                synchronized (VppJNIConnection.class) {
-                    connections.remove(clientName);
-                }
-            }
-        }
-    }
-
-    private static native int clientConnect(String clientName, JVppCallback callback);
-    private static native void clientDisconnect();
-}
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/notification/NotificationRegistryProvider.java b/vpp-api/java/jvpp/org/openvpp/jvpp/notification/NotificationRegistryProvider.java
deleted file mode 100644
index 50b72be..0000000
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/notification/NotificationRegistryProvider.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package org.openvpp.jvpp.notification;
-
-/**
- * Provides notification registry
- */
-public interface NotificationRegistryProvider {
-
-    /**
-     * Get current notification registry instance
-     */
-    NotificationRegistry getNotificationRegistry();
-}
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/notification/NotificationRegistryProviderContext.java b/vpp-api/java/jvpp/org/openvpp/jvpp/notification/NotificationRegistryProviderContext.java
deleted file mode 100644
index 8e70381..0000000
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/notification/NotificationRegistryProviderContext.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.openvpp.jvpp.notification;
-
-/**
- * Base class for notification aware JVpp facades
- */
-public abstract class NotificationRegistryProviderContext implements NotificationRegistryProvider {
-
-    private final NotificationRegistryImpl notificationRegistry = new NotificationRegistryImpl();
-
-    public final NotificationRegistry getNotificationRegistry() {
-        return notificationRegistry;
-    }
-
-    /**
-     * Get instance of notification callback. Can be used to propagate notifications from JVpp facade
-     */
-    protected final GlobalNotificationCallback getNotificationCallback() {
-        return notificationRegistry;
-    }
-}
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackApiTest.java b/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackApiTest.java
deleted file mode 100644
index 8c976db..0000000
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackApiTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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.callback.SwInterfaceCallback;
-import org.openvpp.jvpp.dto.*;
-
-public class CallbackApiTest {
-
-    private static class TestCallback implements GetNodeIndexCallback, ShowVersionCallback, SwInterfaceCallback {
-
-        @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 onSwInterfaceDetails(final SwInterfaceDetails msg) {
-            System.out.printf("Received SwInterfaceDetails: interfaceName=%s, l2AddressLength=%d, adminUpDown=%d, " +
-                    "linkUpDown=%d, linkSpeed=%d, linkMtu=%d\n",
-                    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());
-        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 = "node0".getBytes();
-        jvpp.send(getNodeIndexRequest);
-
-        System.out.println("Sending SwInterfaceDump request...");
-        SwInterfaceDump swInterfaceDumpRequest = new SwInterfaceDump();
-        swInterfaceDumpRequest.nameFilterValid = 0;
-        swInterfaceDumpRequest.nameFilter = "".getBytes();
-        jvpp.send(swInterfaceDumpRequest);
-
-        Thread.sleep(5000);
-
-        System.out.println("Disconnecting...");
-        jvpp.close();
-        Thread.sleep(1000);
-    }
-
-    public static void main(String[] args) throws Exception {
-        testCallbackApi();
-    }
-}
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackJVppFacadeTest.java b/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackJVppFacadeTest.java
deleted file mode 100644
index bb06c76..0000000
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackJVppFacadeTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * 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.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.
- * This is more convenient than the approach shown in CallbackApiTest.
- */
-public class CallbackJVppFacadeTest {
-
-    private static ShowVersionCallback showVersionCallback1;
-    private static ShowVersionCallback showVersionCallback2;
-    private static GetNodeIndexCallback getNodeIndexCallback;
-
-    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");
-
-        JVpp jvpp = new JVppImpl(new VppJNIConnection("CallbackApiTest"));
-
-        CallbackJVppFacade jvppCallbackFacade = new CallbackJVppFacade(jvpp);
-        System.out.println("Successfully connected to VPP");
-
-        jvppCallbackFacade.showVersion(showVersionCallback1);
-        jvppCallbackFacade.showVersion(showVersionCallback2);
-
-        GetNodeIndex getNodeIndexRequest = new GetNodeIndex();
-        getNodeIndexRequest.nodeName = "dummyNode".getBytes();
-        jvppCallbackFacade.getNodeIndex(getNodeIndexRequest, getNodeIndexCallback);
-
-        Thread.sleep(2000);
-
-        System.out.println("Disconnecting...");
-        jvpp.close();
-        Thread.sleep(1000);
-    }
-
-    public static void main(String[] args) throws Exception {
-        testCallbackFacade();
-    }
-}
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/test/FutureApiTest.java b/vpp-api/java/jvpp/org/openvpp/jvpp/test/FutureApiTest.java
deleted file mode 100644
index 0000bcd..0000000
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/FutureApiTest.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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.VppJNIConnection;
-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) {
-        System.out.println("Sending ShowVersion request...");
-        try {
-            Objects.requireNonNull(jvpp,"jvpp is null");
-            final Future<ShowVersionReply> replyFuture = jvpp.showVersion(new ShowVersion()).toCompletableFuture();
-            Objects.requireNonNull(replyFuture,"replyFuture is null");
-            final ShowVersionReply reply = replyFuture.get();
-            Objects.requireNonNull(reply,"reply is null");
-            System.out.printf("Received ShowVersionReply: context=%d, program=%s, " +
-                            "version=%s, buildDate=%s, buildDirectory=%s\n",
-                    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:"+e.getCause());
-            e.printStackTrace();
-        }
-    }
-
-    /**
-     * This test will fail with some error code if node 'node0' is not defined.
-     * TODO: consider adding error messages specific for given api calls
-     */
-    private static void testGetNodeIndex(final FutureJVppFacade jvpp) {
-        System.out.println("Sending GetNodeIndex request...");
-        try {
-            Objects.requireNonNull(jvpp,"jvpp is null");
-            final GetNodeIndex request = new GetNodeIndex();
-            request.nodeName = "node0".getBytes();
-            final Future<GetNodeIndexReply> replyFuture = jvpp.getNodeIndex(request).toCompletableFuture();
-            Objects.requireNonNull(replyFuture,"replyFuture is null");
-            final GetNodeIndexReply reply = replyFuture.get();
-            Objects.requireNonNull(reply,"reply is null");
-            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:"+e.getCause());
-            e.printStackTrace();
-        }
-    }
-
-    private static void testSwInterfaceDump(final FutureJVppFacade jvpp) {
-        System.out.println("Sending SwInterfaceDump request...");
-        try {
-            Objects.requireNonNull(jvpp,"SwInterfaceDetailsReplyDump is null!");
-            final SwInterfaceDump request = new SwInterfaceDump();
-            request.nameFilterValid = 0;
-            request.nameFilter = "".getBytes();
-            final Future<SwInterfaceDetailsReplyDump> replyFuture = jvpp.swInterfaceDump(request).toCompletableFuture();
-            Objects.requireNonNull(replyFuture,"replyFuture is null");
-            final SwInterfaceDetailsReplyDump reply = replyFuture.get();
-            Objects.requireNonNull(reply.swInterfaceDetails, "SwInterfaceDetailsReplyDump.swInterfaceDetails is null!");
-            for (SwInterfaceDetails details : reply.swInterfaceDetails) {
-                Objects.requireNonNull(details, "reply.swInterfaceDetails contains null element!");
-                System.out.printf("Received SwInterfaceDetails: interfaceName=%s, l2AddressLength=%d, adminUpDown=%d, " +
-                                "linkUpDown=%d, linkSpeed=%d, linkMtu=%d\n",
-                        new String(details.interfaceName), details.l2AddressLength, details.adminUpDown,
-                        details.linkUpDown, details.linkSpeed, (int) details.linkMtu);
-            }
-        } catch(NullPointerException e) {
-            throw new IllegalStateException(e.getMessage());
-        } catch (Exception e) {
-            System.err.printf("SwInterfaceDump request failed:"+e.getCause());
-            e.printStackTrace();
-        }
-    }
-
-    private static void testFutureApi() throws Exception {
-        System.out.println("Testing Java future API");
-
-        final org.openvpp.jvpp.JVppImpl impl =
-                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);
-
-        System.out.println("Disconnecting...");
-        // TODO we should consider adding jvpp.close(); to the facade
-        impl.close();
-    }
-
-    public static void main(String[] args) throws Exception {
-        testFutureApi();
-    }
-}
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/test/OnErrorCallbackTest.java b/vpp-api/java/jvpp/org/openvpp/jvpp/test/OnErrorCallbackTest.java
deleted file mode 100644
index 46d8558..0000000
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/OnErrorCallbackTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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();
-    }
-}