diff options
author | Marek Gradzki <mgradzki@cisco.com> | 2016-07-26 15:28:22 +0200 |
---|---|---|
committer | Dave Wallace <dwallacelf@gmail.com> | 2016-08-16 21:26:19 +0000 |
commit | 66ea26b1bc7bbc8d54a3498dbd3d0919c4712fa8 (patch) | |
tree | 16c46e75723099ad859128af6069055e68897300 /vpp-api | |
parent | f4691cd7befd4cf31a63adffc204d71b1f1548e1 (diff) |
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>
Diffstat (limited to 'vpp-api')
57 files changed, 2153 insertions, 1313 deletions
diff --git a/vpp-api/java/Makefile.am b/vpp-api/java/Makefile.am index d3f3c4f4249..aea5c0abfa9 100644 --- a/vpp-api/java/Makefile.am +++ b/vpp-api/java/Makefile.am @@ -22,51 +22,99 @@ CLEANFILES = 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 - -# 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/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 ; - -$(jarfile_jvpp): libjvpp.la - cd .libs ; $(JAR) cf $(JARFLAGS) ../$@ libjvpp.so.0.0.0 ../$(packagedir_jvpp)/* ; cd ..; - -all-local: $(jarfile_jvpp) +libjvpp_common_la_LDFLAGS = -module +libjvpp_common_la_CPPFLAGS = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux + + +# +# jvpp-registry (connection management + plugin registry) +# +lib_LTLIBRARIES += libjvpp_registry.la + +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_registry = jvpp-registry-$(PACKAGE_VERSION).jar +packagedir_jvpp_registry = org/openvpp/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 index 9b759e09a44..be540b0c7b4 100644 --- a/vpp-api/java/jvpp/Readme.txt +++ b/vpp-api/java/Readme.txt @@ -10,6 +10,11 @@ It is: * 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 00000000000..ebec9e94fd1 --- /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 00000000000..bbb203edcb4 --- /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 00000000000..cc1f9b55a95 --- /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/org/openvpp/jvpp/test/CallbackApiTest.java b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackApiTest.java index 8c976db2397..cfa24560336 100644 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackApiTest.java +++ b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackApiTest.java @@ -14,60 +14,74 @@ * 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.GetNodeIndexCallback; -import org.openvpp.jvpp.callback.ShowVersionCallback; -import org.openvpp.jvpp.callback.SwInterfaceCallback; -import org.openvpp.jvpp.dto.*; +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 { - private static class TestCallback implements GetNodeIndexCallback, ShowVersionCallback, SwInterfaceCallback { + 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); + 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)); + 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); + 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()); + 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"); - JVpp jvpp = new JVppImpl(new VppJNIConnection("CallbackApiTest")); - jvpp.connect(new TestCallback()); - System.out.println("Successfully connected to VPP"); + 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..."); - jvpp.send(new ShowVersion()); + 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 = "node0".getBytes(); + getNodeIndexRequest.nodeName = "non-existing-node".getBytes(); jvpp.send(getNodeIndexRequest); System.out.println("Sending SwInterfaceDump request..."); @@ -76,14 +90,10 @@ public class CallbackApiTest { swInterfaceDumpRequest.nameFilter = "".getBytes(); jvpp.send(swInterfaceDumpRequest); - Thread.sleep(5000); + Thread.sleep(1000); System.out.println("Disconnecting..."); - jvpp.close(); + registry.close(); Thread.sleep(1000); } - - public static void main(String[] args) throws Exception { - testCallbackApi(); - } } 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 index 430ce8812c2..542a561a412 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 @@ public class CallbackJVppFacadeNotificationTest { 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 00000000000..7499502b78d --- /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 index 5bf2b212f73..a11cce60e1d 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 @@ public class CallbackNotificationApiTest { 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 @@ public class CallbackNotificationApiTest { 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 @@ public class CallbackNotificationApiTest { 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 index 514bb3ef887..12ded2e019b 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 @@ public class ControlPingTest { 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 index b3dc1f49491..9719a8cc8be 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 @@ import static java.util.Objects.requireNonNull; */ public class CreateSubInterfaceTest { - private static SwInterfaceDump createSwInterfaceDumpRequest(final String ifaceName) { SwInterfaceDump request = new SwInterfaceDump(); request.nameFilter = ifaceName.getBytes(); @@ -53,8 +54,8 @@ public class CreateSubInterfaceTest { 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 @@ public class CreateSubInterfaceTest { } 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 @@ public class CreateSubInterfaceTest { 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 index c48f86d4f00..2decf6eb08f 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 @@ public class FutureApiNotificationTest { 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 00000000000..7a671731fdd --- /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 index 802df631162..fc353f1dad4 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 @@ public class L2AclTest { } 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 @@ public class L2AclTest { } 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 @@ public class L2AclTest { 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 index 9c24d572cbc..2e4d810c46d 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 index e0aa4f4d085..016bde1cd92 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 @@ This package contains basic tests for jvpp. To run the tests: - 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 +CallbackJVppFacadeNotificationTest - Tests interface notifications using Callback based JVpp facade +CallbackJVppFacadeTest - Execution of more complex calls using Callback based JVpp facade CallbackNotificationApiTest - Tests interface notifications using low level JVpp APIs -FutureApiTest - Execution of more complex calls using Future based JVpp facade +ControlPingTest - Simple test executing a single control ping using low level JVpp APIs +CreateSubInterfaceTest - Tests sub-interface creation 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 +FutureApiTest - Execution of more complex calls using Future based JVpp facade L2AclTest - Tests L2 ACL creation -CreateSubInterfaceTest - Tests sub-interface creation -OnErrorCallbackTest - simple test failing with onError 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 00000000000..1c9871bb8db --- /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 00000000000..53bae04c859 --- /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 00000000000..c25b6536bb1 --- /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 00000000000..bb6730f4cae --- /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 00000000000..d00c41d59b4 --- /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 index 792af2c69ec..792af2c69ec 100644 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/VppBaseCallException.java +++ b/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 index 3d2a1cb2013..3d2a1cb2013 100644 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/VppCallbackException.java +++ b/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 index 19733985452..e7055f9042f 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 @@ import java.io.IOException; /** * 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 index 298bcd0ae55..298bcd0ae55 100644 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/VppInvocationException.java +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppInvocationException.java diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/VppJNIConnection.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppJNIConnection.java index 7401bcadc47..f35298741b6 100644 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/VppJNIConnection.java +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppJNIConnection.java @@ -16,63 +16,32 @@ package org.openvpp.jvpp; +import static org.openvpp.jvpp.NativeLibraryLoader.loadLibrary; + 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.Level; import java.util.logging.Logger; -import org.openvpp.jvpp.callback.JVppCallback; /** - * JNI based representation of a management connection to VPP + * 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"; + private static final Logger LOG = Logger.getLogger(VppJNIConnection.class.getName()); static { + final String libName = "libjvpp_registry.so.0.0.0"; try { - loadLibrary(); - } catch (Exception e) { - LOG.severe("Can't find vpp jni library: " + LIBNAME); + 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 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 ConnectionInfo connectionInfo; private final String clientName; private volatile boolean disconnected = false; @@ -80,10 +49,11 @@ public final class VppJNIConnection implements VppConnection { /** * Create VPPJNIConnection instance for client connecting to VPP. * - * @param clientName client name instance to be used for communication. Single connection per clientName is allowed. + * @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"); + this.clientName = Objects.requireNonNull(clientName, "Null clientName"); } /** @@ -94,24 +64,27 @@ public final class VppJNIConnection implements VppConnection { /** * Initiate VPP connection for current instance * - * Multiple instances are allowed since this class is not a singleton - * (VPP allows multiple management connections). + * 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 { + + @Override + public void connect() throws IOException { + _connect(); + } + + private void _connect() throws IOException { synchronized (VppJNIConnection.class) { - if(connections.containsKey(clientName)) { + 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); + connectionInfo = clientConnect(clientName); + if (connectionInfo.status != 0) { + throw new IOException("Connection returned error " + connectionInfo.status); } connections.put(clientName, this); } @@ -125,7 +98,7 @@ public final class VppJNIConnection implements VppConnection { } @Override - public synchronized final void close() { + public final synchronized void close() { if (!disconnected) { disconnected = true; try { @@ -138,6 +111,27 @@ public final class VppJNIConnection implements VppConnection { } } - private static native int clientConnect(String clientName, JVppCallback callback); + 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-registry/org/openvpp/jvpp/callback/ControlPingCallback.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/callback/ControlPingCallback.java new file mode 100644 index 00000000000..529ea220b0a --- /dev/null +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/callback/ControlPingCallback.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openvpp.jvpp.callback; + +import org.openvpp.jvpp.dto.ControlPingReply; + +/** + * Represents callback for control_ping message. + */ +public interface ControlPingCallback extends JVppCallback { + + 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 index f681e379bfd..f681e379bfd 100644 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/callback/JVppCallback.java +++ b/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 index 72a75c83942..72a75c83942 100644 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/callback/JVppNotificationCallback.java +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/callback/JVppNotificationCallback.java diff --git a/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/ControlPing.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/ControlPing.java new file mode 100644 index 00000000000..cc59836dfa9 --- /dev/null +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/ControlPing.java @@ -0,0 +1,34 @@ +/* + * 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.dto; + +import org.openvpp.jvpp.JVpp; +import org.openvpp.jvpp.VppInvocationException; + +/** + * Represents request DTO for control_ping message. + */ +public final class ControlPing implements JVppRequest { + + @Override + public int send(final JVpp jvpp) throws VppInvocationException { + return jvpp.controlPing(this); + } + +} + + diff --git a/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/ControlPingReply.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/ControlPingReply.java new file mode 100644 index 00000000000..e7efd8595d6 --- /dev/null +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/ControlPingReply.java @@ -0,0 +1,30 @@ +/* + * 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.dto; + +/** + * Represents reply DTO for control_ping message. + */ +public final class ControlPingReply implements JVppReply<ControlPing> { + + 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 index 295bbba8525..295bbba8525 100644 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppDump.java +++ b/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 index 7d0fecb7d78..7d0fecb7d78 100644 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppNotification.java +++ b/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 index 2f4964c4de0..2f4964c4de0 100644 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppReply.java +++ b/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 index 4aecedc19d4..4aecedc19d4 100644 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppReplyDump.java +++ b/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 index 273e444f601..1216edf8e31 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 @@ public interface JVppRequest { /** * 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 index a60e1b285dd..d8b105f359e 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 @@ public class FutureJVppInvokerFacade extends NotificationRegistryProviderContext 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 @@ public class FutureJVppInvokerFacade extends NotificationRegistryProviderContext } } - 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 index 1683bd75139..1683bd75139 100644 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvoker.java +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/future/FutureJVppInvoker.java diff --git a/vpp-api/java/jvpp-registry/org/openvpp/jvpp/notification/NotificationRegistry.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/notification/NotificationRegistry.java new file mode 100644 index 00000000000..27349f2850a --- /dev/null +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/notification/NotificationRegistry.java @@ -0,0 +1,25 @@ +/* + * 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.notification; + +/** + * Base registry for notification callbacks. + */ +public interface NotificationRegistry extends AutoCloseable { + + void close(); +} diff --git a/vpp-api/java/jvpp-registry/org/openvpp/jvpp/notification/NotificationRegistryProvider.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/notification/NotificationRegistryProvider.java new file mode 100644 index 00000000000..46c534a0b31 --- /dev/null +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/notification/NotificationRegistryProvider.java @@ -0,0 +1,28 @@ +/* + * 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.notification; + +/** + * Provides notification registry + */ +public interface NotificationRegistryProvider { + + /** + * Get current notification registry instance + */ + 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 00000000000..d134a1c132a --- /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 6f531defc9a..551ce7d264c 100755 --- a/vpp-api/java/jvpp/gen/jvpp_gen.py +++ b/vpp-api/java/jvpp/gen/jvpp_gen.py @@ -41,7 +41,8 @@ from jvppgen.util import vpp_2_jni_type_mapping 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 @@ print "importdir %s" % importdir 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 @@ def get_definitions(): 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' - -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) +control_ping_class_fqn = "%s.%s.%s" % (plugin_package, dto_package, control_ping_class) + +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 eadf3b5c50d..68f70126a04 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 @@ from util import remove_suffix 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 @@ public interface $cls_name extends $base_package.$callback_package.$callback_typ """) 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 @@ def generate_callbacks(func_list, base_package, callback_package, dto_package, i 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 @@ def generate_callbacks(func_list, base_package, callback_package, dto_package, i 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 @@ def generate_callbacks(func_list, base_package, callback_package, dto_package, i 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 426cd96b2ac..785e47e9ef7 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 @@ from string import Template import util dto_template = Template(""" -package $base_package.$dto_package; +package $plugin_package.$dto_package; /** * <p>This class represents $description. @@ -39,11 +39,11 @@ field_template = Template(""" public $type $name;\n""") 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 @@ def generate_dtos(func_list, base_package, dto_package, inputfile): 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 @@ def generate_dtos(func_list, base_package, dto_package, inputfile): # 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 @@ def write_dto_file(base_package, base_type, camel_case_dto_name, description, dt 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 @@ def flush_dump_reply_dtos(inputfile): 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 @@ def flush_dump_reply_dtos(inputfile): 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 @@ def generate_dump_reply_dto(request_dto_name, base_package, dto_package, camel_c '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 1796ac1719b..cd3a3566f42 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 @@ class_reference_template = Template("""jclass ${ref_name}Class; """) 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 @@ find_class_template = Template(""" 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 @@ struct_setter_templates = {'u8': u8_struct_setter_template, 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 @@ def generate_jni_impl(func_list, inputfile): 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 @@ def generate_jni_impl(func_list, inputfile): 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 @@ dto_field_setter_templates = {'u8': default_dto_field_setter_template, 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 @@ callback_err_handler_template = Template(""" 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 @@ def generate_msg_handlers(func_list, inputfile): 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 @@ handler_registration_template = Template("""_(${upercase_name}, ${name}) \\ 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 @@ def generate_handler_registration(func_list): 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 @@ $msg_handlers $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 7df17486a60..ac096a7163d 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 callback_gen 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 @@ $methods """) 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 @@ public final class CallbackJVppFacade extends $base_package.$notification_packag * * @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 $plugin_package.$notification_package.${plugin_name}NotificationRegistry getNotificationRegistry() { + return notificationRegistry; } @Override - public void close() { + public void close() throws Exception { + jvpp.close(); } // TODO add send() @@ -77,17 +81,17 @@ $methods """) 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 @@ no_arg_method_impl_template = Template(""" public final void $name($base_pack """) -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 @@ def generate_jvpp(func_list, base_package, dto_package, callback_package, notifi 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 @@ def generate_jvpp(func_list, base_package, dto_package, callback_package, notifi 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 @@ def generate_jvpp(func_list, base_package, dto_package, callback_package, notifi 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 @@ def generate_jvpp(func_list, base_package, dto_package, callback_package, notifi 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 @@ public final class CallbackJVppFacadeCallback implements $base_package.$callback } } + @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 @@ $methods 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_method_template = Template(""" 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 @@ def generate_callback(func_list, base_package, dto_package, callback_package, no 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 e1ca4d022e0..06c1073b756 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 dto_gen 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,14 +57,9 @@ public final class FutureJVppFacadeCallback implements $base_package.$callback_p } } -$methods -} -""") - -jvpp_facade_callback_method_template = Template(""" @Override @SuppressWarnings("unchecked") - public void on$callback_dto($base_package.$dto_package.$callback_dto reply) { + public void onControlPingReply($base_package.$dto_package.ControlPingReply reply) { final java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply<?>> completableFuture; synchronized(requests) { @@ -71,27 +67,31 @@ jvpp_facade_callback_method_template = Template(""" } if(completableFuture != null) { - completableFuture.complete(reply); + // 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); } } } -""") -jvpp_facade_callback_notification_method_template = Template(""" - @Override - public void on$callback_dto($base_package.$dto_package.$callback_dto notification) { - notificationCallback.on$callback_dto(notification); - } +$methods +} """) -# TODO reuse common parts with generic method callback -jvpp_facade_control_ping_method_template = Template(""" +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) { @@ -99,16 +99,7 @@ jvpp_facade_control_ping_method_template = Template(""" } 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); - } + completableFuture.complete(reply); synchronized(requests) { requests.remove(reply.context); @@ -117,20 +108,27 @@ jvpp_facade_control_ping_method_template = Template(""" } """) +jvpp_facade_callback_notification_method_template = Template(""" + @Override + public void on$callback_dto($plugin_package.$dto_package.$callback_dto notification) { + notificationCallback.on$callback_dto(notification); + } +""") + 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 @@ jvpp_facade_details_callback_method_template = Template(""" """) -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 @@ def generate_jvpp(func_list, base_package, dto_package, callback_package, notifi 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 @@ def generate_jvpp(func_list, base_package, dto_package, callback_package, notifi 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 @@ def generate_jvpp(func_list, base_package, dto_package, callback_package, notifi 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 @@ def generate_jvpp(func_list, base_package, dto_package, callback_package, notifi 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 @@ def generate_jvpp(func_list, base_package, dto_package, callback_package, notifi 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 @@ public class FutureJVppFacade extends FutureJVppInvokerFacade implements FutureJ * * @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 93ffd0fb359..41df4f2ae18 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 @@ import os, util 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 @@ public interface JVpp extends java.lang.AutoCloseable { */ 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 static Logger LOG = Logger.getLogger(JVpp${plugin_name}Impl.class.getName()); + private static final String LIBNAME = "libjvpp_${plugin_name_underscore}.so.0.0.0"; + + // 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 final $base_package.VppConnection connection; + 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) { + } + } + } - public JVppImpl(final $base_package.VppConnection connection) { - this.connection = java.util.Objects.requireNonNull(connection,"Connection is null"); + 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 @@ no_arg_method_impl_template = Template(""" public final int $name() throws or """) -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 @@ def generate_jvpp(func_list, base_package, dto_package, inputfile): 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 df6407f845d..eb380fc8ea3 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 callback_gen 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 @@ public interface NotificationRegistry extends java.lang.AutoCloseable { """) 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 @@ public final class NotificationRegistryImpl implements NotificationRegistry, Glo """) 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; + + /** + * 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 { -def generate_notification_registry(func_list, base_package, notification_package, callback_package, dto_package, inputfile): + @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 @@ def generate_notification_registry(func_list, base_package, notification_package 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 f22132dfbc1..0018e014dc4 100644 --- a/vpp-api/java/jvpp/gen/jvppgen/util.py +++ b/vpp-api/java/jvpp/gen/jvppgen/util.py @@ -120,15 +120,18 @@ jni_field_accessors = { '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 remove_suffix(camel_case_name_with_suffix, suffix): 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 37aef8032cd..00000000000 --- 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 15f9057fa8e..00000000000 --- 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/notification/NotificationRegistryProvider.java b/vpp-api/java/jvpp/org/openvpp/jvpp/notification/NotificationRegistryProvider.java deleted file mode 100644 index 50b72be5805..00000000000 --- 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 8e703812eee..00000000000 --- 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/CallbackJVppFacadeTest.java b/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackJVppFacadeTest.java deleted file mode 100644 index bb06c761108..00000000000 --- 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 0000bcd907c..00000000000 --- 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 46d8558338f..00000000000 --- 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(); - } -} |