From 66ea26b1bc7bbc8d54a3498dbd3d0919c4712fa8 Mon Sep 17 00:00:00 2001 From: Marek Gradzki Date: Tue, 26 Jul 2016 15:28:22 +0200 Subject: 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 --- vpp-api/java/Makefile.am | 132 +++++--- vpp-api/java/Readme.txt | 206 ++++++++++++ vpp-api/java/jvpp-common/jvpp_common.c | 65 ++++ vpp-api/java/jvpp-common/jvpp_common.h | 67 ++++ vpp-api/java/jvpp-core/jvpp_core.c | 117 +++++++ .../openvpp/jvpp/core/test/CallbackApiTest.java | 99 ++++++ .../test/CallbackJVppFacadeNotificationTest.java | 89 ++++++ .../jvpp/core/test/CallbackJVppFacadeTest.java | 108 +++++++ .../core/test/CallbackNotificationApiTest.java | 96 ++++++ .../openvpp/jvpp/core/test/ControlPingTest.java | 70 +++++ .../jvpp/core/test/CreateSubInterfaceTest.java | 123 ++++++++ .../jvpp/core/test/FutureApiNotificationTest.java | 64 ++++ .../org/openvpp/jvpp/core/test/FutureApiTest.java | 103 ++++++ .../org/openvpp/jvpp/core/test/L2AclTest.java | 221 +++++++++++++ .../openvpp/jvpp/core/test/NotificationUtils.java | 54 ++++ .../org/openvpp/jvpp/core/test/Readme.txt | 16 + vpp-api/java/jvpp-registry/jvpp_registry.c | 349 +++++++++++++++++++++ .../java/jvpp-registry/org/openvpp/jvpp/JVpp.java | 56 ++++ .../org/openvpp/jvpp/JVppRegistry.java | 69 ++++ .../org/openvpp/jvpp/JVppRegistryImpl.java | 133 ++++++++ .../org/openvpp/jvpp/NativeLibraryLoader.java | 73 +++++ .../org/openvpp/jvpp/VppBaseCallException.java | 60 ++++ .../org/openvpp/jvpp/VppCallbackException.java | 47 +++ .../org/openvpp/jvpp/VppConnection.java | 45 +++ .../org/openvpp/jvpp/VppInvocationException.java | 33 ++ .../org/openvpp/jvpp/VppJNIConnection.java | 137 ++++++++ .../openvpp/jvpp/callback/ControlPingCallback.java | 29 ++ .../org/openvpp/jvpp/callback/JVppCallback.java | 29 ++ .../jvpp/callback/JVppNotificationCallback.java | 24 ++ .../org/openvpp/jvpp/dto/ControlPing.java | 34 ++ .../org/openvpp/jvpp/dto/ControlPingReply.java | 30 ++ .../org/openvpp/jvpp/dto/JVppDump.java | 24 ++ .../org/openvpp/jvpp/dto/JVppNotification.java | 23 ++ .../org/openvpp/jvpp/dto/JVppReply.java | 24 ++ .../org/openvpp/jvpp/dto/JVppReplyDump.java | 25 ++ .../org/openvpp/jvpp/dto/JVppRequest.java | 34 ++ .../jvpp/future/AbstractFutureJVppInvoker.java | 120 +++++++ .../org/openvpp/jvpp/future/FutureJVppInvoker.java | 39 +++ .../jvpp/notification/NotificationRegistry.java | 25 ++ .../notification/NotificationRegistryProvider.java | 28 ++ .../org/openvpp/jvpp/test/ConnectionTest.java | 43 +++ vpp-api/java/jvpp/Readme.txt | 201 ------------ vpp-api/java/jvpp/gen/jvpp_gen.py | 27 +- vpp-api/java/jvpp/gen/jvppgen/callback_gen.py | 27 +- vpp-api/java/jvpp/gen/jvppgen/dto_gen.py | 41 +-- vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py | 103 +++--- .../jvpp/gen/jvppgen/jvpp_callback_facade_gen.py | 119 ++++--- .../jvpp/gen/jvppgen/jvpp_future_facade_gen.py | 158 +++++----- vpp-api/java/jvpp/gen/jvppgen/jvpp_impl_gen.py | 143 ++++++--- vpp-api/java/jvpp/gen/jvppgen/notification_gen.py | 137 +++++--- vpp-api/java/jvpp/gen/jvppgen/util.py | 13 +- vpp-api/java/jvpp/jvpp.c | 314 ------------------ vpp-api/java/jvpp/jvpp.h | 112 ------- .../org/openvpp/jvpp/VppBaseCallException.java | 60 ---- .../org/openvpp/jvpp/VppCallbackException.java | 47 --- .../java/jvpp/org/openvpp/jvpp/VppConnection.java | 48 --- .../org/openvpp/jvpp/VppInvocationException.java | 33 -- .../jvpp/org/openvpp/jvpp/VppJNIConnection.java | 143 --------- .../org/openvpp/jvpp/callback/JVppCallback.java | 29 -- .../jvpp/callback/JVppNotificationCallback.java | 24 -- .../java/jvpp/org/openvpp/jvpp/dto/JVppDump.java | 24 -- .../org/openvpp/jvpp/dto/JVppNotification.java | 23 -- .../java/jvpp/org/openvpp/jvpp/dto/JVppReply.java | 24 -- .../jvpp/org/openvpp/jvpp/dto/JVppReplyDump.java | 25 -- .../jvpp/org/openvpp/jvpp/dto/JVppRequest.java | 34 -- .../org/openvpp/jvpp/future/FutureJVppInvoker.java | 39 --- .../jvpp/future/FutureJVppInvokerFacade.java | 112 ------- .../notification/NotificationRegistryProvider.java | 12 - .../NotificationRegistryProviderContext.java | 20 -- .../org/openvpp/jvpp/test/CallbackApiTest.java | 89 ------ .../test/CallbackJVppFacadeNotificationTest.java | 87 ----- .../openvpp/jvpp/test/CallbackJVppFacadeTest.java | 107 ------- .../jvpp/test/CallbackNotificationApiTest.java | 93 ------ .../org/openvpp/jvpp/test/ControlPingTest.java | 61 ---- .../openvpp/jvpp/test/CreateSubInterfaceTest.java | 123 -------- .../jvpp/test/FutureApiNotificationTest.java | 60 ---- .../jvpp/org/openvpp/jvpp/test/FutureApiTest.java | 116 ------- .../java/jvpp/org/openvpp/jvpp/test/L2AclTest.java | 218 ------------- .../org/openvpp/jvpp/test/NotificationUtils.java | 38 --- .../org/openvpp/jvpp/test/OnErrorCallbackTest.java | 74 ----- vpp-api/java/jvpp/org/openvpp/jvpp/test/Readme.txt | 17 - 81 files changed, 3589 insertions(+), 2749 deletions(-) create mode 100644 vpp-api/java/Readme.txt create mode 100644 vpp-api/java/jvpp-common/jvpp_common.c create mode 100644 vpp-api/java/jvpp-common/jvpp_common.h create mode 100644 vpp-api/java/jvpp-core/jvpp_core.c create mode 100644 vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackApiTest.java create mode 100644 vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackJVppFacadeNotificationTest.java create mode 100644 vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackJVppFacadeTest.java create mode 100644 vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackNotificationApiTest.java create mode 100644 vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/ControlPingTest.java create mode 100644 vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CreateSubInterfaceTest.java create mode 100644 vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/FutureApiNotificationTest.java create mode 100644 vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/FutureApiTest.java create mode 100644 vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/L2AclTest.java create mode 100644 vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/NotificationUtils.java create mode 100644 vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/Readme.txt create mode 100644 vpp-api/java/jvpp-registry/jvpp_registry.c create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/JVpp.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/JVppRegistry.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/JVppRegistryImpl.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/NativeLibraryLoader.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppBaseCallException.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppCallbackException.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppConnection.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppInvocationException.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppJNIConnection.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/callback/ControlPingCallback.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/callback/JVppCallback.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/callback/JVppNotificationCallback.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/ControlPing.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/ControlPingReply.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppDump.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppNotification.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppReply.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppReplyDump.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppRequest.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/future/AbstractFutureJVppInvoker.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/future/FutureJVppInvoker.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/notification/NotificationRegistry.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/notification/NotificationRegistryProvider.java create mode 100644 vpp-api/java/jvpp-registry/org/openvpp/jvpp/test/ConnectionTest.java delete mode 100644 vpp-api/java/jvpp/Readme.txt delete mode 100644 vpp-api/java/jvpp/jvpp.c delete mode 100644 vpp-api/java/jvpp/jvpp.h delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/VppBaseCallException.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/VppCallbackException.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/VppConnection.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/VppInvocationException.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/VppJNIConnection.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/callback/JVppCallback.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/callback/JVppNotificationCallback.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppDump.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppNotification.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppReply.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppReplyDump.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvoker.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvokerFacade.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/notification/NotificationRegistryProvider.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/notification/NotificationRegistryProviderContext.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackApiTest.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackJVppFacadeNotificationTest.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackJVppFacadeTest.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackNotificationApiTest.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/test/ControlPingTest.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/test/CreateSubInterfaceTest.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/test/FutureApiNotificationTest.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/test/FutureApiTest.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/test/L2AclTest.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/test/NotificationUtils.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/test/OnErrorCallbackTest.java delete mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/test/Readme.txt (limited to 'vpp-api') 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/Readme.txt b/vpp-api/java/Readme.txt new file mode 100644 index 00000000000..be540b0c7b4 --- /dev/null +++ b/vpp-api/java/Readme.txt @@ -0,0 +1,206 @@ += JVpp + +JVpp is JNI based Java API for VPP. + +== Features +It is: + +* Asynchronous +* Fully generated +* 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 + + + JVpp Java + + /----------\ /--------\ /------------\ /------\ + | VppConn* | | JVpp | | Callbacks | | DTOs | + \----+-----/ \----+---/ \------+-----/ \------/ + ^ ^ ^ + | implements | implements | implements + /----+---------\ /----+-------\ /------+-----------\ + | VppConnImpl* +<--------+ JVppImpl | | GlobalCallback | + \--------------/ uses \---+--------/ \-------+----------/ + | ^ + | uses | calls back + | | +-------------------------------|-----------------------|--------------------- + | | + | +---------------+ + C JNI | | + v | /------------\ + /---+-------+--\ +---->+ jvpp.h* | + | +-----+ \------------/ + | jvpp.c* | + | +-----+ /------------\ + \--------------/ +---->+ jvpp_gen.h | + \------------/ + +* Components marked with an asterisk contain manually crafted Java code, which in addition +to generated classes form jvpp. Exception applies to Callbacks and DTOs, since there are +manually crafted marker interfaces in callback and dto package (dto/JVppRequest, dto/JVppReply, +dto/JVppDump, dto/JVppReplyDump, callback/JVppCallback) + +Note: jvpp.c calls back the GlobalCallback instance with every response. An instance of the +GlobalCallback is provided to jvpp.c by VppConnImpl while connecting to VPP. + +Part of the JVpp is also Future facade. It is asynchronous API returning Future objects +on top of low level JVpp. + + +Future facade + + /-------------\ /--------------------\ + | FutureJVpp* | +-->+ FutureJVppRegistry | + \-----+-------/ | \----------+---------/ + ^ | ^ + | implements | uses | uses + | | | + /--------+----------\ | /----------+---------\ + | FutureJVppFacade* +----+ | FutureJVppCallback | + \---------+---------/ \----------+---------/ + | | +---------------|-----------------------------|------------------------------- + | uses | implements +JVpp Java | | + | | + /---------\ | | + | JVpp +<--+ | + \----+----/ | + ^ | + | implements v + /----+-------\ /----------+-------\ + | JVppImpl | | GlobalCallback | + \------------/ \------------------/ + + + +Another useful utility of the JVpp is Callback facade. It is asynchronous API +capable of calling specific callback instance (provided when performing a call) +per call. + + +Callback facade + + /--------------\ /----------------------\ + | CallbackJVpp | +-->+ CallbackJVppRegistry | + \-----+--------/ | \----------+-----------/ + ^ | ^ + | implements | uses | uses + | | | + /--------+-----------\ | /----------+-----------\ + | CallbackJVppFacade +-----+ | CallbackJVppCallback | + \---------+----------/ \----------+-----------/ + | | +---------------|-----------------------------|------------------------------- + | uses | implements +JVpp Java | | + | | + /---------\ | | + | JVpp +<--+ | + \----+----/ | + ^ | + | implements v + /----+-------\ /----------+-------\ + | JVppImpl | | GlobalCallback | + \------------/ \------------------/ + + + +== Package structure + +* *org.openvpp.jvpp* - top level package for generated JVpp interface+ implementation and hand-crafted +VppConnection interface + implementation + +** *dto* - package for DTOs generated from VPP API structures + base/marker hand-crafted interfaces +** *callback* - package for low-level JVpp callbacks and a global callback interface implementing each of the low-level JVppcallbacks +** *future* - package for future based facade on top of JVpp and callbacks +** *callfacade* - package for callback based facade on top of JVpp and callbacks. Allowing +users to provide callback per request +** *test* - package for JVpp standalone tests. Can also serve as samples for JVpp. + +C code is structured into 3 files: + +* *jvpp.c* - includes jvpp.h and jvpp_gen.h + contains hand crafted code for: + +** VPP connection open/close +** Rx thread to java thread attach +** Callback instance store +* *jvpp.h* - contains hand-crafted macros and structures used by jvpp.c +* *jvpp_gen.h* - contains JNI compatible handlers for each VPP request and reply + +== Code generators +All of the required code except the base/marker interfaces is generated using +simple python2 code generators. The generators use __defs_vpp_papi.py__ input +file produced by __vppapigen__ from vpe.api file. + +=== JNI compatible C code +Produces __jvpp_gen.h__ file containing JNI compatible handlers for each VPP +request and reply. + +[NOTE] +==== +Source: jvpp_c_gen.py +==== + +=== Request/Reply DTOs +For all the structures in __defs_vpp_papi.py__ a POJO DTO is produced. Logically, +there are 4 types of DTOs: + +* Request - requests that can be sent to VPP and only a single response is expected +* DumpRequest - requests that can be sent to VPP and a stream of responses is expected +* Reply - reply to a simple request or a single response from dump triggered response stream +* ReplyDump - collection of replies from a single dump request +* Notifications/Events - Not implemented yet + +[NOTE] +==== +Source: dto_gen.py +==== + +=== JVpp +Produces __JVpp.java__ and __JVppImpl.java__. This is the layer right above JNI compatible C +code. + +[NOTE] +==== +Source: jvpp_impl_gen.py +==== + +=== Callbacks +Produces callback interface for each VPP reply + a global callback interface called +__JVppGlobalCallback.java__ aggregating all of the callback interfaces. The JNI +compatible C code expects only a single instance of this global callback and calls +it with every reply. + +[NOTE] +==== +Source: callback_gen.py +==== + +=== Future facade +Produces an asynchronous facade on top of JVpp and callbacks, which returns a Future that provides +matching reply once VPP invocation finishes. Sources produced: +__FutureJVpp.java, FutureJVppFacade.java and FutureJVppCallback.java__ + +[NOTE] +==== +Source: jvpp_future_facade_gen.py +==== + +=== Callback facade +Similar to future facade, only this facade takes callback objects as part of the invocation +and the callback is called with result once VPP invocation finishes. Sources produced: +__CallbackJVpp.java, CallbackJVppFacade.java and CallbackJVppCallback.java__ + +[NOTE] +==== +Source: jvpp_callback_facade_gen.py +==== 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, + "", "(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 +#include +#include +#include + +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 + +#include +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +#define vl_endianfun +#include +#undef vl_endianfun + +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +#include +#include +#include +#include + +#include + +// TODO: generate jvpp_plugin_name.c files (or at least reuse plugin's main structure) +typedef struct { + /* Base message index for the nsh plugin */ + u16 msg_id_base; + + /* Pointer to shared memory queue */ + unix_shared_memory_queue_t * vl_input_queue; + + /* VPP api client index */ + u32 my_client_index; + + /* Callback object and class references enabling asynchronous Java calls */ + jobject callbackObject; + jclass callbackClass; + +} core_main_t; + +core_main_t core_main __attribute__((aligned (64))); + +#include "org_openvpp_jvpp_core_JVppCoreImpl.h" +#include "jvpp_core_gen.h" + +JNIEXPORT void JNICALL Java_org_openvpp_jvpp_core_JVppCoreImpl_init0 +(JNIEnv * env, jclass clazz, jobject callback, jlong queue_address, jint my_client_index) { + core_main_t * plugin_main = &core_main; + plugin_main->my_client_index = my_client_index; + plugin_main->vl_input_queue = (unix_shared_memory_queue_t *)queue_address; + + plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback); + plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback)); + + #define _(N,n) \ + vl_msg_api_set_handlers(VL_API_##N, #n, \ + vl_api_##n##_t_handler, \ + vl_noop_handler, \ + vl_api_##n##_t_endian, \ + vl_api_##n##_t_print, \ + sizeof(vl_api_##n##_t), 1); + foreach_api_reply_handler; + #undef _ +} + +JNIEXPORT void JNICALL Java_org_openvpp_jvpp_core_JVppCoreImpl_close0 +(JNIEnv *env, jclass clazz) { + core_main_t * plugin_main = &core_main; + + // cleanup: + (*env)->DeleteGlobalRef(env, plugin_main->callbackClass); + (*env)->DeleteGlobalRef(env, plugin_main->callbackObject); + + plugin_main->callbackClass = NULL; + plugin_main->callbackObject = NULL; +} + +jint JNI_OnLoad(JavaVM *vm, void *reserved) { + JNIEnv* env; + + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { + return JNI_EVERSION; + } + + if (cache_class_references(env) != 0) { + clib_warning ("Failed to cache class references\n"); + return JNI_ERR; + } + + return JNI_VERSION_1_8; +} + +void JNI_OnUnload(JavaVM *vm, void *reserved) { + JNIEnv* env; + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { + return; + } + delete_class_references(env); +} + + + diff --git a/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackApiTest.java b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackApiTest.java new file mode 100644 index 00000000000..cfa24560336 --- /dev/null +++ b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackApiTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openvpp.jvpp.core.test; + +import org.openvpp.jvpp.JVpp; +import org.openvpp.jvpp.JVppRegistry; +import org.openvpp.jvpp.JVppRegistryImpl; +import org.openvpp.jvpp.VppCallbackException; +import org.openvpp.jvpp.core.JVppCoreImpl; +import org.openvpp.jvpp.core.callback.GetNodeIndexCallback; +import org.openvpp.jvpp.core.callback.ShowVersionCallback; +import org.openvpp.jvpp.core.callback.SwInterfaceCallback; +import org.openvpp.jvpp.core.dto.GetNodeIndex; +import org.openvpp.jvpp.core.dto.GetNodeIndexReply; +import org.openvpp.jvpp.core.dto.ShowVersion; +import org.openvpp.jvpp.core.dto.ShowVersionReply; +import org.openvpp.jvpp.core.dto.SwInterfaceDetails; +import org.openvpp.jvpp.core.dto.SwInterfaceDump; + +public class CallbackApiTest { + + static class TestCallback implements GetNodeIndexCallback, ShowVersionCallback, SwInterfaceCallback { + + @Override + public void onGetNodeIndexReply(final GetNodeIndexReply msg) { + System.out.printf("Received GetNodeIndexReply: context=%d, nodeIndex=%d\n", + msg.context, msg.nodeIndex); + } + + @Override + public void onShowVersionReply(final ShowVersionReply msg) { + System.out.printf("Received ShowVersionReply: context=%d, program=%s, version=%s, " + + "buildDate=%s, buildDirectory=%s\n", + msg.context, new String(msg.program), new String(msg.version), + new String(msg.buildDate), new String(msg.buildDirectory)); + } + + @Override + public void onSwInterfaceDetails(final SwInterfaceDetails msg) { + System.out.printf("Received SwInterfaceDetails: interfaceName=%s, l2AddressLength=%d, adminUpDown=%d, " + + "linkUpDown=%d, linkSpeed=%d, linkMtu=%d\n", + new String(msg.interfaceName), msg.l2AddressLength, msg.adminUpDown, + msg.linkUpDown, msg.linkSpeed, (int) msg.linkMtu); + } + + @Override + public void onError(VppCallbackException ex) { + System.out.printf("Received onError exception: call=%s, context=%d, retval=%d\n", ex.getMethodName(), + ex.getCtxId(), ex.getErrorCode()); + } + } + + public static void main(String[] args) throws Exception { + testCallbackApi(); + } + + private static void testCallbackApi() throws Exception { + System.out.println("Testing Java callback API with JVppRegistry"); + JVppRegistry registry = new JVppRegistryImpl("CallbackApiTest"); + JVpp jvpp = new JVppCoreImpl(); + + registry.register(jvpp, new TestCallback()); + + System.out.println("Sending ShowVersion request..."); + final int result = jvpp.send(new ShowVersion()); + System.out.printf("ShowVersion send result = %d\n", result); + + System.out.println("Sending GetNodeIndex request..."); + GetNodeIndex getNodeIndexRequest = new GetNodeIndex(); + getNodeIndexRequest.nodeName = "non-existing-node".getBytes(); + jvpp.send(getNodeIndexRequest); + + System.out.println("Sending SwInterfaceDump request..."); + SwInterfaceDump swInterfaceDumpRequest = new SwInterfaceDump(); + swInterfaceDumpRequest.nameFilterValid = 0; + swInterfaceDumpRequest.nameFilter = "".getBytes(); + jvpp.send(swInterfaceDumpRequest); + + Thread.sleep(1000); + + System.out.println("Disconnecting..."); + registry.close(); + Thread.sleep(1000); + } +} diff --git a/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackJVppFacadeNotificationTest.java b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackJVppFacadeNotificationTest.java new file mode 100644 index 00000000000..542a561a412 --- /dev/null +++ b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackJVppFacadeNotificationTest.java @@ -0,0 +1,89 @@ +/* + * 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.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"); + + final JVppRegistry registry = new JVppRegistryImpl("CallbackFacadeTest"); + final JVppCore jvpp = new JVppCoreImpl(); + + CallbackJVppCoreFacade jvppCallbackFacade = new CallbackJVppCoreFacade(registry, jvpp); + System.out.println("Successfully connected to VPP"); + + final AutoCloseable notificationListenerReg = + jvppCallbackFacade.getNotificationRegistry().registerSwInterfaceSetFlagsNotificationCallback( + NotificationUtils::printNotification + ); + + jvppCallbackFacade.wantInterfaceEvents(NotificationUtils.getEnableInterfaceNotificationsReq(), + new WantInterfaceEventsCallback() { + @Override + public void onWantInterfaceEventsReply(final WantInterfaceEventsReply reply) { + System.out.println("Interface events started"); + } + + @Override + public void onError(final VppCallbackException ex) { + System.out.printf("Received onError exception: call=%s, context=%d, retval=%d\n", + ex.getMethodName(), ex.getCtxId(), ex.getErrorCode()); + } + }); + + System.out.println("Changing interface configuration"); + NotificationUtils.getChangeInterfaceState().send(jvpp); + + Thread.sleep(1000); + + jvppCallbackFacade.wantInterfaceEvents(NotificationUtils.getDisableInterfaceNotificationsReq(), + new WantInterfaceEventsCallback() { + @Override + public void onWantInterfaceEventsReply(final WantInterfaceEventsReply reply) { + System.out.println("Interface events stopped"); + } + + @Override + public void onError(final VppCallbackException ex) { + System.out.printf("Received onError exception: call=%s, context=%d, retval=%d\n", + ex.getMethodName(), ex.getCtxId(), ex.getErrorCode()); + } + }); + + notificationListenerReg.close(); + + 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-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-core/org/openvpp/jvpp/core/test/CallbackNotificationApiTest.java b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackNotificationApiTest.java new file mode 100644 index 00000000000..a11cce60e1d --- /dev/null +++ b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CallbackNotificationApiTest.java @@ -0,0 +1,96 @@ +/* + * 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 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.JVppRegistry; +import org.openvpp.jvpp.JVppRegistryImpl; +import org.openvpp.jvpp.VppCallbackException; +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 { + + private static class TestCallback implements SwInterfaceSetFlagsNotificationCallback, + WantInterfaceEventsCallback, SwInterfaceSetFlagsCallback { + + @Override + public void onSwInterfaceSetFlagsNotification( + final SwInterfaceSetFlagsNotification msg) { + printNotification(msg); + } + + @Override + public void onWantInterfaceEventsReply(final WantInterfaceEventsReply wantInterfaceEventsReply) { + System.out.println("Interface notification stream updated"); + } + + @Override + public void onSwInterfaceSetFlagsReply(final SwInterfaceSetFlagsReply swInterfaceSetFlagsReply) { + System.out.println("Interface flags set successfully"); + } + + @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 testCallbackApi() throws Exception { + System.out.println("Testing Java callback API for notifications"); + JVppRegistry registry = new JVppRegistryImpl("CallbackNotificationTest"); + JVpp jvpp = new JVppCoreImpl(); + + registry.register(jvpp, new TestCallback()); + System.out.println("Successfully connected to VPP"); + + getEnableInterfaceNotificationsReq().send(jvpp); + System.out.println("Interface notifications started"); + // TODO test ifc dump which also triggers interface flags send + + System.out.println("Changing interface configuration"); + getChangeInterfaceState().send(jvpp); + + // Notifications are received + Thread.sleep(500); + + getDisableInterfaceNotificationsReq().send(jvpp); + System.out.println("Interface events stopped"); + + Thread.sleep(2000); + + System.out.println("Disconnecting..."); + registry.close(); + Thread.sleep(1000); + } + + public static void main(String[] args) throws Exception { + testCallbackApi(); + } +} diff --git a/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/ControlPingTest.java b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/ControlPingTest.java new file mode 100644 index 00000000000..12ded2e019b --- /dev/null +++ b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/ControlPingTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openvpp.jvpp.core.test; + +import org.openvpp.jvpp.JVpp; +import org.openvpp.jvpp.JVppRegistry; +import org.openvpp.jvpp.JVppRegistryImpl; +import org.openvpp.jvpp.VppCallbackException; +import org.openvpp.jvpp.core.JVppCoreImpl; +import org.openvpp.jvpp.callback.ControlPingCallback; +import org.openvpp.jvpp.dto.ControlPing; +import org.openvpp.jvpp.dto.ControlPingReply; + +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(); + + 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); + } + + @Override + public void onError(VppCallbackException ex) { + System.out.printf("Received onError exception: call=%s, reply=%d, context=%d ", ex.getMethodName(), + ex.getErrorCode(), ex.getCtxId()); + } + + }); + System.out.println("Successfully connected to VPP"); + Thread.sleep(1000); + + 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..."); + registry.close(); + Thread.sleep(1000); + } + + public static void main(String[] args) throws Exception { + testControlPing(); + } +} diff --git a/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CreateSubInterfaceTest.java b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CreateSubInterfaceTest.java new file mode 100644 index 00000000000..9719a8cc8be --- /dev/null +++ b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/CreateSubInterfaceTest.java @@ -0,0 +1,123 @@ +/* + * 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 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; + +/** + *

Tests sub-interface creation.
Equivalent to:
+ * + *

{@code
+ * vppctl create sub GigabitEthernet0/9/0 1 dot1q 100 inner-dot1q any
+ * }
+ * 
+ * + * To verify invoke:
+ *
{@code
+ * vpp_api_test json
+ * vat# sw_interface_dump
+ * }
+ */
+public class CreateSubInterfaceTest {
+
+    private static SwInterfaceDump createSwInterfaceDumpRequest(final String ifaceName) {
+        SwInterfaceDump request = new SwInterfaceDump();
+        request.nameFilter = ifaceName.getBytes();
+        request.nameFilterValid = 1;
+        return request;
+    }
+
+    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()));
+        }
+    }
+
+    private static CreateSubif createSubifRequest(final int swIfIndex, final int subId) {
+        CreateSubif request = new CreateSubif();
+        request.swIfIndex = swIfIndex; // super interface id
+        request.subId = subId;
+        request.noTags = 0;
+        request.oneTag = 0;
+        request.twoTags = 1;
+        request.dot1Ad = 0;
+        request.exactMatch = 1;
+        request.defaultSub = 0;
+        request.outerVlanIdAny = 0;
+        request.innerVlanIdAny = 1;
+        request.outerVlanId = 100;
+        request.innerVlanId = 0;
+        return request;
+    }
+
+    private static void print(CreateSubifReply reply) {
+        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 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/8/0";
+
+        final SwInterfaceDetailsReplyDump swInterfaceDetails =
+            jvppFacade.swInterfaceDump(createSwInterfaceDumpRequest(ifaceName)).toCompletableFuture().get();
+
+        requireNonNull(swInterfaceDetails, "swInterfaceDump returned null");
+        requireNonNull(swInterfaceDetails.swInterfaceDetails, "swInterfaceDetails is null");
+        requireSingleIface(swInterfaceDetails, ifaceName);
+
+        final int swIfIndex = swInterfaceDetails.swInterfaceDetails.get(0).swIfIndex;
+        final int subId = 1;
+
+        final CreateSubifReply createSubifReply =
+            jvppFacade.createSubif(createSubifRequest(swIfIndex, subId)).toCompletableFuture().get();
+        print(createSubifReply);
+
+        final String subIfaceName = "GigabitEthernet0/8/0." + subId;
+        final SwInterfaceDetailsReplyDump subIface =
+            jvppFacade.swInterfaceDump(createSwInterfaceDumpRequest(subIfaceName)).toCompletableFuture().get();
+        requireNonNull(swInterfaceDetails, "swInterfaceDump returned null");
+        requireNonNull(subIface.swInterfaceDetails, "swInterfaceDump returned null");
+        requireSingleIface(swInterfaceDetails, ifaceName);
+
+        System.out.println("Disconnecting...");
+        registry.close();
+        Thread.sleep(1000);
+    }
+
+    public static void main(String[] args) throws Exception {
+        testCreateSubInterface();
+    }
+}
diff --git a/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/FutureApiNotificationTest.java b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/FutureApiNotificationTest.java
new file mode 100644
index 00000000000..2decf6eb08f
--- /dev/null
+++ b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/FutureApiNotificationTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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 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.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 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.wantInterfaceEvents(getEnableInterfaceNotificationsReq()).toCompletableFuture().get();
+        System.out.println("Interface events started");
+
+        System.out.println("Changing interface configuration");
+        jvppFacade.swInterfaceSetFlags(getChangeInterfaceState()).toCompletableFuture().get();
+
+        Thread.sleep(1000);
+
+        jvppFacade.wantInterfaceEvents(getDisableInterfaceNotificationsReq()).toCompletableFuture().get();
+        System.out.println("Interface events stopped");
+
+        notificationListenerReg.close();
+
+        System.out.println("Disconnecting...");
+        registry.close();
+    }
+
+    public static void main(String[] args) throws Exception {
+        testFutureApi();
+    }
+}
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 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 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 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-core/org/openvpp/jvpp/core/test/L2AclTest.java b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/L2AclTest.java
new file mode 100644
index 00000000000..fc353f1dad4
--- /dev/null
+++ b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/L2AclTest.java
@@ -0,0 +1,221 @@
+/*
+ * 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.Arrays;
+import javax.xml.bind.DatatypeConverter;
+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;
+
+/**
+ * 

Tests L2 ACL creation and read.
Equivalent to the following vppctl commands:
+ * + *

{@code
+ * vppctl classify table mask l2 src
+ * vppctl classify session acl-hit-next deny opaque-index 0 table-index 0 match l2 src 01:02:03:04:05:06
+ * vppctl set int input acl intfc local0 l2-table 0
+ * vppctl sh class table verbose
+ * }
+ * 
+ */ +public class L2AclTest { + + private static final int LOCAL0_IFACE_ID = 0; + + private static ClassifyAddDelTable createClassifyTable() { + ClassifyAddDelTable request = new ClassifyAddDelTable(); + request.isAdd = 1; + request.tableIndex = ~0; // default + request.nbuckets = 2; + request.memorySize = 2 << 20; + request.nextTableIndex = ~0; // default + request.missNextIndex = ~0; // default + request.skipNVectors = 0; + request.matchNVectors = 1; + request.mask = + new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, 0x00, 0x00, 0x00, 0x00}; + return request; + } + + private static ClassifyTableInfo createClassifyTableInfoRequest(final int tableId) { + ClassifyTableInfo request = new ClassifyTableInfo(); + request.tableId = tableId; + return request; + } + + private static ClassifyAddDelSession createClassifySession(final int tableIndex) { + ClassifyAddDelSession request = new ClassifyAddDelSession(); + request.isAdd = 1; + request.tableIndex = tableIndex; + request.hitNextIndex = 0; // deny + request.opaqueIndex = 0; + request.advance = 0; // default + // match 01:02:03:04:05:06 mac address + request.match = + new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, + (byte) 0x05, (byte) 0x06, 0x00, 0x00, 0x00, 0x00}; + return request; + } + + private static ClassifySessionDump createClassifySessionDumpRequest(final int newTableIndex) { + ClassifySessionDump request = new ClassifySessionDump(); + request.tableId = newTableIndex; + return request; + } + + private static InputAclSetInterface aclSetInterface() { + InputAclSetInterface request = new InputAclSetInterface(); + request.isAdd = 1; + request.swIfIndex = LOCAL0_IFACE_ID; + request.ip4TableIndex = ~0; // skip + request.ip6TableIndex = ~0; // skip + request.l2TableIndex = 0; + return request; + } + + private static ClassifyTableByInterface createClassifyTableByInterfaceRequest() { + ClassifyTableByInterface request = new ClassifyTableByInterface(); + request.swIfIndex = LOCAL0_IFACE_ID; + return request; + } + + private static void print(ClassifyAddDelTableReply reply) { + System.out.printf("ClassifyAddDelTableReply: context=%d, " + + "newTableIndex=%d, skipNVectors=%d, matchNVectors=%d\n", + reply.context, reply.newTableIndex, reply.skipNVectors, reply.matchNVectors); + } + + private static void print(ClassifyTableIdsReply reply) { + System.out.printf("ClassifyTableIdsReply: context=%d, count=%d, ids.length=%d\n", + reply.context, reply.count, reply.ids.length); + Arrays.stream(reply.ids).forEach(System.out::println); + } + + private static void print(final ClassifyTableInfoReply reply) { + final StringBuilder builder = new StringBuilder("ClassifyTableInfoReply:\n"); + builder.append("context: ").append(reply.context).append('\n'); + builder.append("tableId: ").append(reply.tableId).append('\n'); + builder.append("nbuckets: ").append(reply.nbuckets).append('\n'); + builder.append("matchNVectors: ").append(reply.matchNVectors).append('\n'); + builder.append("skipNVectors: ").append(reply.skipNVectors).append('\n'); + builder.append("activeSessions: ").append(reply.activeSessions).append('\n'); + builder.append("nextTableIndex: ").append(reply.nextTableIndex).append('\n'); + builder.append("missNextIndex: ").append(reply.missNextIndex).append('\n'); + builder.append("maskLength: ").append(reply.maskLength).append('\n'); + builder.append("mask: ").append(DatatypeConverter.printHexBinary(reply.mask)).append('\n'); + System.out.println(builder.toString()); + } + + private static void print(ClassifyAddDelSessionReply reply) { + System.out.printf("ClassifyAddDelSessionReply: context=%d\n", + reply.context); + } + + private static void print(final ClassifySessionDetailsReplyDump reply) { + if (reply.classifySessionDetails == null) { + System.out.println("ClassifySessionDetailsReplyDump: classifySessionDetails == NULL"); + } + for (final ClassifySessionDetails details : reply.classifySessionDetails) { + final StringBuilder builder = new StringBuilder("ClassifySessionDetails:\n"); + builder.append("context: ").append(details.context).append('\n'); + builder.append("tableId: ").append(details.tableId).append('\n'); + builder.append("hitNextIndex: ").append(details.hitNextIndex).append('\n'); + builder.append("advance: ").append(details.advance).append('\n'); + builder.append("opaqueIndex: ").append(details.opaqueIndex).append('\n'); + builder.append("matchLength: ").append(details.matchLength).append('\n'); + builder.append("match: ").append(DatatypeConverter.printHexBinary(details.match)).append('\n'); + System.out.println(builder.toString()); + } + } + + private static void print(final InputAclSetInterfaceReply reply) { + System.out.printf("InputAclSetInterfaceReply: context=%d\n", reply.context); + } + + 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); + } + + private static void testL2Acl() throws Exception { + System.out.println("Testing L2 ACLs using Java callback API"); + 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); + + final ClassifyAddDelTableReply classifyAddDelTableReply = + jvppFacade.classifyAddDelTable(createClassifyTable()).toCompletableFuture().get(); + print(classifyAddDelTableReply); + + final ClassifyTableIdsReply classifyTableIdsReply = + jvppFacade.classifyTableIds(new ClassifyTableIds()).toCompletableFuture().get(); + print(classifyTableIdsReply); + + final ClassifyTableInfoReply classifyTableInfoReply = + jvppFacade.classifyTableInfo(createClassifyTableInfoRequest(classifyAddDelTableReply.newTableIndex)) + .toCompletableFuture().get(); + print(classifyTableInfoReply); + + final ClassifyAddDelSessionReply classifyAddDelSessionReply = + jvppFacade.classifyAddDelSession(createClassifySession(classifyAddDelTableReply.newTableIndex)) + .toCompletableFuture().get(); + print(classifyAddDelSessionReply); + + final ClassifySessionDetailsReplyDump classifySessionDetailsReplyDump = + jvppFacade.classifySessionDump(createClassifySessionDumpRequest(classifyAddDelTableReply.newTableIndex)) + .toCompletableFuture().get(); + print(classifySessionDetailsReplyDump); + + final InputAclSetInterfaceReply inputAclSetInterfaceReply = + jvppFacade.inputAclSetInterface(aclSetInterface()).toCompletableFuture().get(); + print(inputAclSetInterfaceReply); + + final ClassifyTableByInterfaceReply classifyTableByInterfaceReply = + jvppFacade.classifyTableByInterface(createClassifyTableByInterfaceRequest()).toCompletableFuture().get(); + print(classifyTableByInterfaceReply); + + System.out.println("Disconnecting..."); + registry.close(); + Thread.sleep(1000); + } + + public static void main(String[] args) throws Exception { + testL2Acl(); + } +} diff --git a/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/NotificationUtils.java b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/NotificationUtils.java new file mode 100644 index 00000000000..2e4d810c46d --- /dev/null +++ b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/NotificationUtils.java @@ -0,0 +1,54 @@ +/* + * 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.core.dto.SwInterfaceSetFlags; +import org.openvpp.jvpp.core.dto.SwInterfaceSetFlagsNotification; +import org.openvpp.jvpp.core.dto.WantInterfaceEvents; + +final class NotificationUtils { + + private NotificationUtils() {} + + static PrintStream printNotification(final SwInterfaceSetFlagsNotification msg) { + return System.out.printf("Received interface notification: ifc: %d, admin: %d, link: %d, deleted: %d\n", + msg.swIfIndex, msg.adminUpDown, msg.linkUpDown, msg.deleted); + } + + static SwInterfaceSetFlags getChangeInterfaceState() { + final SwInterfaceSetFlags swInterfaceSetFlags = new SwInterfaceSetFlags(); + swInterfaceSetFlags.swIfIndex = 0; + swInterfaceSetFlags.adminUpDown = 1; + swInterfaceSetFlags.deleted = 0; + return swInterfaceSetFlags; + } + + static WantInterfaceEvents getEnableInterfaceNotificationsReq() { + WantInterfaceEvents wantInterfaceEvents = new WantInterfaceEvents(); + wantInterfaceEvents.pid = 1; + wantInterfaceEvents.enableDisable = 1; + return wantInterfaceEvents; + } + + static WantInterfaceEvents getDisableInterfaceNotificationsReq() { + WantInterfaceEvents wantInterfaceEvents = new WantInterfaceEvents(); + wantInterfaceEvents.pid = 1; + wantInterfaceEvents.enableDisable = 0; + return wantInterfaceEvents; + } +} diff --git a/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/Readme.txt b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/Readme.txt new file mode 100644 index 00000000000..016bde1cd92 --- /dev/null +++ b/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/test/Readme.txt @@ -0,0 +1,16 @@ +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_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: +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 +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 +FutureApiTest - Execution of more complex calls using Future based JVpp facade +L2AclTest - Tests L2 ACL creation diff --git a/vpp-api/java/jvpp-registry/jvpp_registry.c b/vpp-api/java/jvpp-registry/jvpp_registry.c new file mode 100644 index 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 + +#define vl_api_version(n,v) static u32 vpe_api_version = (v); +#include +#undef vl_api_version + +#include +#include +#include "org_openvpp_jvpp_VppJNIConnection.h" +#include "org_openvpp_jvpp_JVppRegistryImpl.h" + +#include +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +#define vl_endianfun +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) +#define vl_printfun +#include +#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, "", "()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, "", "(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 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 pluginRegistry; + private final ConcurrentMap 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 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 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-registry/org/openvpp/jvpp/VppBaseCallException.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppBaseCallException.java new file mode 100644 index 00000000000..792af2c69ec --- /dev/null +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppBaseCallException.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openvpp.jvpp; + +/** + * Base exception representing failed operation of JVpp request call + */ +public abstract class VppBaseCallException extends Exception { + private final String methodName; + private final int errorCode; + + /** + * Constructs an VppCallbackException with the specified api method name and error code. + * + * @param methodName name of a method, which invocation or execution failed + * @param errorCode negative error code value associated with this failure + * @throws NullPointerException if apiMethodName is null + */ + public VppBaseCallException(final String methodName, final int errorCode) { + super(String.format("vppApi.%s failed with error code: %d", methodName, errorCode)); + this.methodName = java.util.Objects.requireNonNull(methodName, "apiMethodName is null!"); + this.errorCode = errorCode; + if(errorCode >= 0) { + throw new IllegalArgumentException("Error code must be < 0. Was " + errorCode + + " for " + methodName ); + } + } + + /** + * Returns name of a method, which invocation failed. + * + * @return method name + */ + public String getMethodName() { + return methodName; + } + + /** + * Returns the error code associated with this failure. + * + * @return a negative integer error code + */ + public int getErrorCode() { + return errorCode; + } +} diff --git a/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppCallbackException.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppCallbackException.java new file mode 100644 index 00000000000..3d2a1cb2013 --- /dev/null +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppCallbackException.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openvpp.jvpp; + +/** + * Callback Exception representing failed operation of JVpp request call + */ +public class VppCallbackException extends VppBaseCallException { + private final int ctxId; + + /** + * Constructs an VppCallbackException with the specified api method name and error code. + * + * @param methodName name of a method, which invocation failed. + * @param ctxId api request context identifier + * @param errorCode negative error code value associated with this failure + * @throws NullPointerException if apiMethodName is null + */ + public VppCallbackException(final String methodName, final int ctxId, final int errorCode ){ + super(methodName, errorCode); + this.ctxId = ctxId; + } + + /** + * Returns api request context identifier. + * + * @return value of context identifier + */ + public int getCtxId() { + return ctxId; + } + +} diff --git a/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppConnection.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppConnection.java new file mode 100644 index 00000000000..e7055f9042f --- /dev/null +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppConnection.java @@ -0,0 +1,45 @@ +/* + * 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; + +/** + * Representation of a management connection to VPP. + */ +public interface VppConnection extends AutoCloseable { + + /** + * Opens VppConnection for communication with VPP. + * + * @throws IOException if connection is not established + */ + void connect() throws IOException; + + /** + * Checks if this instance connection is active. + * + * @throws IllegalStateException if this instance was disconnected. + */ + void checkActive(); + + /** + * Closes Vpp connection. + */ + @Override + void close(); +} diff --git a/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppInvocationException.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppInvocationException.java new file mode 100644 index 00000000000..298bcd0ae55 --- /dev/null +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppInvocationException.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openvpp.jvpp; + +/** + * Exception thrown when Vpp jAPI method invocation failed. + */ +public class VppInvocationException extends VppBaseCallException { + /** + * Constructs an VppApiInvocationFailedException with the specified api method name and error code. + * + * @param methodName name of a method, which invocation failed. + * @param errorCode negative error code value associated with this failure + * @throws NullPointerException if apiMethodName is null + */ + public VppInvocationException(final String methodName, final int errorCode) { + super(methodName, errorCode); + } +} diff --git a/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppJNIConnection.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppJNIConnection.java new file mode 100644 index 00000000000..f35298741b6 --- /dev/null +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/VppJNIConnection.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openvpp.jvpp; + +import static org.openvpp.jvpp.NativeLibraryLoader.loadLibrary; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * JNI based representation of a management connection to VPP. + */ +public final class VppJNIConnection implements VppConnection { + private static final Logger LOG = Logger.getLogger(VppJNIConnection.class.getName()); + + static { + final String libName = "libjvpp_registry.so.0.0.0"; + try { + loadLibrary(libName, VppJNIConnection.class); + } catch (IOException e) { + LOG.log(Level.SEVERE, String.format("Can't find vpp jni library: %s", libName), e); + throw new ExceptionInInitializerError(e); + } + } + + private ConnectionInfo connectionInfo; + + private final String clientName; + private volatile boolean disconnected = false; + + /** + * Create VPPJNIConnection instance for client connecting to VPP. + * + * @param clientName client name instance to be used for communication. Single connection per clientName is + * allowed. + */ + public VppJNIConnection(final String clientName) { + this.clientName = Objects.requireNonNull(clientName, "Null clientName"); + } + + /** + * Guarded by VppJNIConnection.class + */ + private static final Map connections = new HashMap<>(); + + /** + * Initiate VPP connection for current instance + * + * Multiple instances are allowed since this class is not a singleton (VPP allows multiple management connections). + * + * However only a single connection per clientName is allowed. + * + * @throws IOException in case the connection could not be established + */ + + @Override + public void connect() throws IOException { + _connect(); + } + + private void _connect() throws IOException { + synchronized (VppJNIConnection.class) { + if (connections.containsKey(clientName)) { + throw new IOException("Client " + clientName + " already connected"); + } + + connectionInfo = clientConnect(clientName); + if (connectionInfo.status != 0) { + throw new IOException("Connection returned error " + connectionInfo.status); + } + connections.put(clientName, this); + } + } + + @Override + public final void checkActive() { + if (disconnected) { + throw new IllegalStateException("Disconnected client " + clientName); + } + } + + @Override + public final synchronized void close() { + if (!disconnected) { + disconnected = true; + try { + clientDisconnect(); + } finally { + synchronized (VppJNIConnection.class) { + connections.remove(clientName); + } + } + } + } + + public ConnectionInfo getConnectionInfo() { + return connectionInfo; + } + + /** + * VPP connection information used by plugins to reuse the connection. + */ + public static final class ConnectionInfo { + public final long queueAddress; + public final int clientIndex; + public final int status; // FIXME throw exception instead + + public ConnectionInfo(long queueAddress, int clientIndex, int status) { + this.queueAddress = queueAddress; + this.clientIndex = clientIndex; + this.status = status; + } + } + + private static native ConnectionInfo clientConnect(String clientName); + + private static native void clientDisconnect(); + +} diff --git a/vpp-api/java/jvpp-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-registry/org/openvpp/jvpp/callback/JVppCallback.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/callback/JVppCallback.java new file mode 100644 index 00000000000..f681e379bfd --- /dev/null +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/callback/JVppCallback.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.VppCallbackException; + +/** + * Base JVppCallback interface + */ +public interface JVppCallback { + /** + * onError callback handler used to report failing operation + * @param ex VppCallbackException object containing details about failing operation + */ + void onError(VppCallbackException ex); +} diff --git a/vpp-api/java/jvpp-registry/org/openvpp/jvpp/callback/JVppNotificationCallback.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/callback/JVppNotificationCallback.java new file mode 100644 index 00000000000..72a75c83942 --- /dev/null +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/callback/JVppNotificationCallback.java @@ -0,0 +1,24 @@ +/* + * 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; + +/** +* Notification callback +*/ +public interface JVppNotificationCallback { + +} 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 { + + public int context; + public int clientIndex; + public int vpePid; + + +} + diff --git a/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppDump.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppDump.java new file mode 100644 index 00000000000..295bbba8525 --- /dev/null +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppDump.java @@ -0,0 +1,24 @@ +/* + * 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; + +/** +* Base interface for all dump requests +*/ +public interface JVppDump extends JVppRequest { + +} diff --git a/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppNotification.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppNotification.java new file mode 100644 index 00000000000..7d0fecb7d78 --- /dev/null +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppNotification.java @@ -0,0 +1,23 @@ +/* + * 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; + +/** +* Base interface for all notification DTOs +*/ +public interface JVppNotification { +} diff --git a/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppReply.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppReply.java new file mode 100644 index 00000000000..2f4964c4de0 --- /dev/null +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppReply.java @@ -0,0 +1,24 @@ +/* + * 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; + +/** +* Base interface for all reply DTOs +*/ +public interface JVppReply { + +} diff --git a/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppReplyDump.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppReplyDump.java new file mode 100644 index 00000000000..4aecedc19d4 --- /dev/null +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppReplyDump.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.dto; + +/** +* Base interface for all dump replies +*/ +public interface JVppReplyDump> + extends JVppReply { + +} diff --git a/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppRequest.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppRequest.java new file mode 100644 index 00000000000..1216edf8e31 --- /dev/null +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/dto/JVppRequest.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; + +/** +* Base interface for all request DTOs +*/ +public interface JVppRequest { + + /** + * Invoke current operation asynchronously on VPP + * + * @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-registry/org/openvpp/jvpp/future/AbstractFutureJVppInvoker.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/future/AbstractFutureJVppInvoker.java new file mode 100644 index 00000000000..d8b105f359e --- /dev/null +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/future/AbstractFutureJVppInvoker.java @@ -0,0 +1,120 @@ +/* + * 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.future; + + +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import org.openvpp.jvpp.JVpp; +import org.openvpp.jvpp.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 abstract class AbstractFutureJVppInvoker implements FutureJVppInvoker { + + private final JVpp jvpp; + private final JVppRegistry registry; + + /** + * Guarded by self + */ + private final Map>> requests; + + protected AbstractFutureJVppInvoker(final JVpp jvpp, final JVppRegistry registry, + final Map>> 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 + this.requests = Objects.requireNonNull(requestMap, "Null requestMap"); + } + + protected final Map>> getRequests() { + return this.requests; + } + + // TODO use Optional in Future, java8 + + @Override + @SuppressWarnings("unchecked") + public > CompletionStage send(REQ req) { + synchronized(requests) { + try { + final CompletableFuture replyCompletableFuture; + final int contextId = jvpp.send(req); + + if(req instanceof JVppDump) { + replyCompletableFuture = (CompletableFuture) new CompletableDumpFuture<>(contextId); + } else { + replyCompletableFuture = new CompletableFuture<>(); + } + + requests.put(contextId, replyCompletableFuture); + if(req instanceof JVppDump) { + 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 replyCompletableFuture = new CompletableFuture<>(); + replyCompletableFuture.completeExceptionally(ex); + return replyCompletableFuture; + } + } + } + + public static final class CompletableDumpFuture> extends CompletableFuture { + // 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; + + public CompletableDumpFuture(final long contextId) { + this.contextId = contextId; + } + + public long getContextId() { + return contextId; + } + + public T getReplyDump() { + return replyDump; + } + + public void setReplyDump(final T replyDump) { + this.replyDump = replyDump; + } + } + + @Override + public void close() throws Exception { + jvpp.close(); + } +} diff --git a/vpp-api/java/jvpp-registry/org/openvpp/jvpp/future/FutureJVppInvoker.java b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/future/FutureJVppInvoker.java new file mode 100644 index 00000000000..1683bd75139 --- /dev/null +++ b/vpp-api/java/jvpp-registry/org/openvpp/jvpp/future/FutureJVppInvoker.java @@ -0,0 +1,39 @@ +/* + * 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.future; + + +import org.openvpp.jvpp.dto.JVppReply; +import org.openvpp.jvpp.dto.JVppRequest; + +import java.util.concurrent.CompletionStage; +import org.openvpp.jvpp.notification.NotificationRegistryProvider; + +/** +* Future facade on top of JVpp +*/ +public interface FutureJVppInvoker extends NotificationRegistryProvider, AutoCloseable { + + /** + * Invoke asynchronous operation on VPP + * + * @return CompletionStage with future result of an async VPP call + * @throws org.openvpp.jvpp.VppInvocationException when send request failed with details + */ + > CompletionStage send(REQ req); + +} 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/Readme.txt b/vpp-api/java/jvpp/Readme.txt deleted file mode 100644 index 9b759e09a44..00000000000 --- a/vpp-api/java/jvpp/Readme.txt +++ /dev/null @@ -1,201 +0,0 @@ -= JVpp - -JVpp is JNI based Java API for VPP. - -== Features -It is: - -* Asynchronous -* Fully generated -* Lightweight - -== Architecture -JVpp and JNI - - - JVpp Java - - /----------\ /--------\ /------------\ /------\ - | VppConn* | | JVpp | | Callbacks | | DTOs | - \----+-----/ \----+---/ \------+-----/ \------/ - ^ ^ ^ - | implements | implements | implements - /----+---------\ /----+-------\ /------+-----------\ - | VppConnImpl* +<--------+ JVppImpl | | GlobalCallback | - \--------------/ uses \---+--------/ \-------+----------/ - | ^ - | uses | calls back - | | --------------------------------|-----------------------|--------------------- - | | - | +---------------+ - C JNI | | - v | /------------\ - /---+-------+--\ +---->+ jvpp.h* | - | +-----+ \------------/ - | jvpp.c* | - | +-----+ /------------\ - \--------------/ +---->+ jvpp_gen.h | - \------------/ - -* Components marked with an asterisk contain manually crafted Java code, which in addition -to generated classes form jvpp. Exception applies to Callbacks and DTOs, since there are -manually crafted marker interfaces in callback and dto package (dto/JVppRequest, dto/JVppReply, -dto/JVppDump, dto/JVppReplyDump, callback/JVppCallback) - -Note: jvpp.c calls back the GlobalCallback instance with every response. An instance of the -GlobalCallback is provided to jvpp.c by VppConnImpl while connecting to VPP. - -Part of the JVpp is also Future facade. It is asynchronous API returning Future objects -on top of low level JVpp. - - -Future facade - - /-------------\ /--------------------\ - | FutureJVpp* | +-->+ FutureJVppRegistry | - \-----+-------/ | \----------+---------/ - ^ | ^ - | implements | uses | uses - | | | - /--------+----------\ | /----------+---------\ - | FutureJVppFacade* +----+ | FutureJVppCallback | - \---------+---------/ \----------+---------/ - | | ----------------|-----------------------------|------------------------------- - | uses | implements -JVpp Java | | - | | - /---------\ | | - | JVpp +<--+ | - \----+----/ | - ^ | - | implements v - /----+-------\ /----------+-------\ - | JVppImpl | | GlobalCallback | - \------------/ \------------------/ - - - -Another useful utility of the JVpp is Callback facade. It is asynchronous API -capable of calling specific callback instance (provided when performing a call) -per call. - - -Callback facade - - /--------------\ /----------------------\ - | CallbackJVpp | +-->+ CallbackJVppRegistry | - \-----+--------/ | \----------+-----------/ - ^ | ^ - | implements | uses | uses - | | | - /--------+-----------\ | /----------+-----------\ - | CallbackJVppFacade +-----+ | CallbackJVppCallback | - \---------+----------/ \----------+-----------/ - | | ----------------|-----------------------------|------------------------------- - | uses | implements -JVpp Java | | - | | - /---------\ | | - | JVpp +<--+ | - \----+----/ | - ^ | - | implements v - /----+-------\ /----------+-------\ - | JVppImpl | | GlobalCallback | - \------------/ \------------------/ - - - -== Package structure - -* *org.openvpp.jvpp* - top level package for generated JVpp interface+ implementation and hand-crafted -VppConnection interface + implementation - -** *dto* - package for DTOs generated from VPP API structures + base/marker hand-crafted interfaces -** *callback* - package for low-level JVpp callbacks and a global callback interface implementing each of the low-level JVppcallbacks -** *future* - package for future based facade on top of JVpp and callbacks -** *callfacade* - package for callback based facade on top of JVpp and callbacks. Allowing -users to provide callback per request -** *test* - package for JVpp standalone tests. Can also serve as samples for JVpp. - -C code is structured into 3 files: - -* *jvpp.c* - includes jvpp.h and jvpp_gen.h + contains hand crafted code for: - -** VPP connection open/close -** Rx thread to java thread attach -** Callback instance store -* *jvpp.h* - contains hand-crafted macros and structures used by jvpp.c -* *jvpp_gen.h* - contains JNI compatible handlers for each VPP request and reply - -== Code generators -All of the required code except the base/marker interfaces is generated using -simple python2 code generators. The generators use __defs_vpp_papi.py__ input -file produced by __vppapigen__ from vpe.api file. - -=== JNI compatible C code -Produces __jvpp_gen.h__ file containing JNI compatible handlers for each VPP -request and reply. - -[NOTE] -==== -Source: jvpp_c_gen.py -==== - -=== Request/Reply DTOs -For all the structures in __defs_vpp_papi.py__ a POJO DTO is produced. Logically, -there are 4 types of DTOs: - -* Request - requests that can be sent to VPP and only a single response is expected -* DumpRequest - requests that can be sent to VPP and a stream of responses is expected -* Reply - reply to a simple request or a single response from dump triggered response stream -* ReplyDump - collection of replies from a single dump request -* Notifications/Events - Not implemented yet - -[NOTE] -==== -Source: dto_gen.py -==== - -=== JVpp -Produces __JVpp.java__ and __JVppImpl.java__. This is the layer right above JNI compatible C -code. - -[NOTE] -==== -Source: jvpp_impl_gen.py -==== - -=== Callbacks -Produces callback interface for each VPP reply + a global callback interface called -__JVppGlobalCallback.java__ aggregating all of the callback interfaces. The JNI -compatible C code expects only a single instance of this global callback and calls -it with every reply. - -[NOTE] -==== -Source: callback_gen.py -==== - -=== Future facade -Produces an asynchronous facade on top of JVpp and callbacks, which returns a Future that provides -matching reply once VPP invocation finishes. Sources produced: -__FutureJVpp.java, FutureJVppFacade.java and FutureJVppCallback.java__ - -[NOTE] -==== -Source: jvpp_future_facade_gen.py -==== - -=== Callback facade -Similar to future facade, only this facade takes callback objects as part of the invocation -and the callback is called with result once VPP invocation finishes. Sources produced: -__CallbackJVpp.java, CallbackJVppFacade.java and CallbackJVppCallback.java__ - -[NOTE] -==== -Source: jvpp_callback_facade_gen.py -==== 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; /** - *

Represents callback for vpe.api message. + *

Represents callback for plugin's api file message. *
It was generated by callback_gen.py based on $inputfile preparsed data: *

 $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;
 
 /**
  * 

Global aggregated callback interface. *
It was generated by callback_gen.py based on $inputfile - *
(python representation of vpe.api generated by vppapigen). + *
(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; /** *

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, "", "()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; /** - *

Callback Java API representation of vpe.api. + *

Callback Java API representation of $plugin_package plugin. *
It was generated by jvpp_callback_facade_gen.py based on $inputfile - *
(python representation of vpe.api generated by vppapigen). + *
(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; /** - *

Default implementation of CallbackJVpp interface. + *

Default implementation of Callback${plugin_name}JVpp interface. *
It was generated by jvpp_callback_facade_gen.py based on $inputfile - *
(python representation of vpe.api generated by vppapigen). + *
(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 callbacks; - + private final $plugin_package.$notification_package.${plugin_name}NotificationRegistryImpl notificationRegistry = new $plugin_package.$notification_package.${plugin_name}NotificationRegistryImpl(); /** - *

Create CallbackJVppFacade object for provided JVpp instance. + *

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; /** *

Implementation of JVppGlobalCallback interface for Java Callback API. *
It was generated by jvpp_callback_facade_gen.py based on $inputfile - *
(python representation of vpe.api generated by vppapigen). + *
(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 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 requestMap, - final $base_package.$notification_package.GlobalNotificationCallback notificationCallback) { + public CallbackJVpp${plugin_name}FacadeCallback(final java.util.Map 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; /** *

Async facade callback setting values to future objects *
It was generated by jvpp_future_facade_gen.py based on $inputfile - *
(python representation of vpe.api generated by vppapigen). + *
(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>> 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>> requestMap, - final $base_package.$notification_package.GlobalNotificationCallback notificationCallback) { + public FutureJVpp${plugin_name}FacadeCallback( + final java.util.Map>> 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; /** *

Async facade extension adding specific methods for each request invocation *
It was generated by jvpp_future_facade_gen.py based on $inputfile - *
(python representation of vpe.api generated by vppapigen). + *
(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; /** - *

Implementation of FutureJVpp based on FutureJVppInvokerFacade + *

Implementation of FutureJVpp based on AbstractFutureJVppInvoker *
It was generated by jvpp_future_facade_gen.py based on $inputfile - *
(python representation of vpe.api generated by vppapigen). + *
(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(); /** - *

Create FutureJVppFacade object for provided JVpp instance. + *

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; /** - *

Java representation of vpe.api. + *

Java representation of plugin's api file. *
It was generated by jvpp_impl_gen.py based on $inputfile - *
(python representation of vpe.api generated by vppapigen). + *
(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; /** *

Default implementation of JVpp interface. *
It was generated by jvpp_impl_gen.py based on $inputfile - *
(python representation of vpe.api generated by vppapigen). + *
(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 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; /** - *

Registry for notification callbacks. + *

Registry for notification callbacks defined in ${plugin_name}. *
It was generated by notification_gen.py based on $inputfile - *
(python representation of vpe.api generated by vppapigen). + *
(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; /** *

Aggregated callback interface for notifications only. *
It was generated by notification_gen.py based on $inputfile - *
(python representation of vpe.api generated by vppapigen). + *
(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; /** *

Notification registry delegating notification processing to registered callbacks. *
It was generated by notification_gen.py based on $inputfile - *
(python representation of vpe.api generated by vppapigen). + *
(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, $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. + *
The file was generated by notification_gen.py based on $inputfile + *
(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 - -#define vl_api_version(n,v) static u32 vpe_api_version = (v); -#include -#undef vl_api_version - -#include -#include -#include -#include - -#include -#define vl_typedefs /* define message structures */ -#include -#undef vl_typedefs - -#define vl_endianfun -#include -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) -#define vl_printfun -#include -#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, "", "(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, "", "()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 -#include -#include -#include -#include -#include - -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/VppBaseCallException.java b/vpp-api/java/jvpp/org/openvpp/jvpp/VppBaseCallException.java deleted file mode 100644 index 792af2c69ec..00000000000 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/VppBaseCallException.java +++ /dev/null @@ -1,60 +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; - -/** - * Base exception representing failed operation of JVpp request call - */ -public abstract class VppBaseCallException extends Exception { - private final String methodName; - private final int errorCode; - - /** - * Constructs an VppCallbackException with the specified api method name and error code. - * - * @param methodName name of a method, which invocation or execution failed - * @param errorCode negative error code value associated with this failure - * @throws NullPointerException if apiMethodName is null - */ - public VppBaseCallException(final String methodName, final int errorCode) { - super(String.format("vppApi.%s failed with error code: %d", methodName, errorCode)); - this.methodName = java.util.Objects.requireNonNull(methodName, "apiMethodName is null!"); - this.errorCode = errorCode; - if(errorCode >= 0) { - throw new IllegalArgumentException("Error code must be < 0. Was " + errorCode + - " for " + methodName ); - } - } - - /** - * Returns name of a method, which invocation failed. - * - * @return method name - */ - public String getMethodName() { - return methodName; - } - - /** - * Returns the error code associated with this failure. - * - * @return a negative integer error code - */ - public int getErrorCode() { - return errorCode; - } -} diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/VppCallbackException.java b/vpp-api/java/jvpp/org/openvpp/jvpp/VppCallbackException.java deleted file mode 100644 index 3d2a1cb2013..00000000000 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/VppCallbackException.java +++ /dev/null @@ -1,47 +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; - -/** - * Callback Exception representing failed operation of JVpp request call - */ -public class VppCallbackException extends VppBaseCallException { - private final int ctxId; - - /** - * Constructs an VppCallbackException with the specified api method name and error code. - * - * @param methodName name of a method, which invocation failed. - * @param ctxId api request context identifier - * @param errorCode negative error code value associated with this failure - * @throws NullPointerException if apiMethodName is null - */ - public VppCallbackException(final String methodName, final int ctxId, final int errorCode ){ - super(methodName, errorCode); - this.ctxId = ctxId; - } - - /** - * Returns api request context identifier. - * - * @return value of context identifier - */ - public int getCtxId() { - return ctxId; - } - -} diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/VppConnection.java b/vpp-api/java/jvpp/org/openvpp/jvpp/VppConnection.java deleted file mode 100644 index 19733985452..00000000000 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/VppConnection.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.openvpp.jvpp; - -import java.io.IOException; - -/** - * 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 - * - * @throws IOException if connection is not established - */ - void connect(final org.openvpp.jvpp.callback.JVppCallback callback) throws IOException; - - /** - * Check if this instance connection is active. - * - * @throws IllegalStateException if this instance was disconnected. - */ - void checkActive(); - - /** - * Closes Vpp connection. - */ - @Override - void close(); -} diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/VppInvocationException.java b/vpp-api/java/jvpp/org/openvpp/jvpp/VppInvocationException.java deleted file mode 100644 index 298bcd0ae55..00000000000 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/VppInvocationException.java +++ /dev/null @@ -1,33 +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; - -/** - * Exception thrown when Vpp jAPI method invocation failed. - */ -public class VppInvocationException extends VppBaseCallException { - /** - * Constructs an VppApiInvocationFailedException with the specified api method name and error code. - * - * @param methodName name of a method, which invocation failed. - * @param errorCode negative error code value associated with this failure - * @throws NullPointerException if apiMethodName is null - */ - public VppInvocationException(final String methodName, final int errorCode) { - super(methodName, errorCode); - } -} diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/VppJNIConnection.java b/vpp-api/java/jvpp/org/openvpp/jvpp/VppJNIConnection.java deleted file mode 100644 index 7401bcadc47..00000000000 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/VppJNIConnection.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.openvpp.jvpp; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.nio.file.attribute.PosixFilePermission; -import java.nio.file.attribute.PosixFilePermissions; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.logging.Logger; -import org.openvpp.jvpp.callback.JVppCallback; - -/** - * JNI based representation of a management connection to VPP - */ -public final class VppJNIConnection implements VppConnection { - private final static Logger LOG = Logger.getLogger(VppJNIConnection.class.getName()); - private static final String LIBNAME = "libjvpp.so.0.0.0"; - - static { - try { - loadLibrary(); - } catch (Exception e) { - LOG.severe("Can't find vpp jni library: " + LIBNAME); - throw new ExceptionInInitializerError(e); - } - } - - private static void loadStream(final InputStream is) throws IOException { - final Set perms = PosixFilePermissions.fromString("rwxr-x---"); - final Path p = Files.createTempFile(LIBNAME, null, PosixFilePermissions.asFileAttribute(perms)); - try { - Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING); - - try { - Runtime.getRuntime().load(p.toString()); - } catch (UnsatisfiedLinkError e) { - throw new IOException("Failed to load library " + p, e); - } - } finally { - try { - Files.deleteIfExists(p); - } catch (IOException e) { - } - } - } - - private static void loadLibrary() throws IOException { - try (final InputStream is = VppJNIConnection.class.getResourceAsStream('/' + LIBNAME)) { - if (is == null) { - throw new IOException("Failed to open library resource " + LIBNAME); - } - loadStream(is); - } - } - - private final String clientName; - private volatile boolean disconnected = false; - - /** - * Create VPPJNIConnection instance for client connecting to VPP. - * - * @param clientName client name instance to be used for communication. Single connection per clientName is allowed. - */ - public VppJNIConnection(final String clientName) { - this.clientName = Objects.requireNonNull(clientName,"Null clientName"); - } - - /** - * Guarded by VppJNIConnection.class - */ - private static final Map connections = new HashMap<>(); - - /** - * Initiate VPP connection for current instance - * - * Multiple instances are allowed since this class is not a singleton - * (VPP allows multiple management connections). - * - * However only a single connection per clientName is allowed. - * - * @param callback global callback to receive response calls from vpp - * - * @throws IOException in case the connection could not be established - */ - public void connect(final JVppCallback callback) throws IOException { - synchronized (VppJNIConnection.class) { - if(connections.containsKey(clientName)) { - throw new IOException("Client " + clientName + " already connected"); - } - - final int ret = clientConnect(clientName, callback); - if (ret != 0) { - throw new IOException("Connection returned error " + ret); - } - connections.put(clientName, this); - } - } - - @Override - public final void checkActive() { - if (disconnected) { - throw new IllegalStateException("Disconnected client " + clientName); - } - } - - @Override - public synchronized final void close() { - if (!disconnected) { - disconnected = true; - try { - clientDisconnect(); - } finally { - synchronized (VppJNIConnection.class) { - connections.remove(clientName); - } - } - } - } - - private static native int clientConnect(String clientName, JVppCallback callback); - private static native void clientDisconnect(); -} diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/callback/JVppCallback.java b/vpp-api/java/jvpp/org/openvpp/jvpp/callback/JVppCallback.java deleted file mode 100644 index f681e379bfd..00000000000 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/callback/JVppCallback.java +++ /dev/null @@ -1,29 +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.callback; -import org.openvpp.jvpp.VppCallbackException; - -/** - * Base JVppCallback interface - */ -public interface JVppCallback { - /** - * onError callback handler used to report failing operation - * @param ex VppCallbackException object containing details about failing operation - */ - void onError(VppCallbackException ex); -} diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/callback/JVppNotificationCallback.java b/vpp-api/java/jvpp/org/openvpp/jvpp/callback/JVppNotificationCallback.java deleted file mode 100644 index 72a75c83942..00000000000 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/callback/JVppNotificationCallback.java +++ /dev/null @@ -1,24 +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.callback; - -/** -* Notification callback -*/ -public interface JVppNotificationCallback { - -} diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppDump.java b/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppDump.java deleted file mode 100644 index 295bbba8525..00000000000 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppDump.java +++ /dev/null @@ -1,24 +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.dto; - -/** -* Base interface for all dump requests -*/ -public interface JVppDump extends JVppRequest { - -} diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppNotification.java b/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppNotification.java deleted file mode 100644 index 7d0fecb7d78..00000000000 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppNotification.java +++ /dev/null @@ -1,23 +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.dto; - -/** -* Base interface for all notification DTOs -*/ -public interface JVppNotification { -} diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppReply.java b/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppReply.java deleted file mode 100644 index 2f4964c4de0..00000000000 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppReply.java +++ /dev/null @@ -1,24 +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.dto; - -/** -* Base interface for all reply DTOs -*/ -public interface JVppReply { - -} diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppReplyDump.java b/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppReplyDump.java deleted file mode 100644 index 4aecedc19d4..00000000000 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppReplyDump.java +++ /dev/null @@ -1,25 +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.dto; - -/** -* Base interface for all dump replies -*/ -public interface JVppReplyDump> - extends JVppReply { - -} diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java b/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java deleted file mode 100644 index 273e444f601..00000000000 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppRequest.java +++ /dev/null @@ -1,34 +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.dto; - -import org.openvpp.jvpp.JVpp; -import org.openvpp.jvpp.VppInvocationException; - -/** -* Base interface for all request DTOs -*/ -public interface JVppRequest { - - /** - * Invoke current operation asynchronously on VPP - * - * @return context id of this request. Can be used to track incomming response - */ - int send(JVpp jvpp) throws VppInvocationException; - -} diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvoker.java b/vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvoker.java deleted file mode 100644 index 1683bd75139..00000000000 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvoker.java +++ /dev/null @@ -1,39 +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.future; - - -import org.openvpp.jvpp.dto.JVppReply; -import org.openvpp.jvpp.dto.JVppRequest; - -import java.util.concurrent.CompletionStage; -import org.openvpp.jvpp.notification.NotificationRegistryProvider; - -/** -* Future facade on top of JVpp -*/ -public interface FutureJVppInvoker extends NotificationRegistryProvider, AutoCloseable { - - /** - * Invoke asynchronous operation on VPP - * - * @return CompletionStage with future result of an async VPP call - * @throws org.openvpp.jvpp.VppInvocationException when send request failed with details - */ - > CompletionStage send(REQ req); - -} diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvokerFacade.java b/vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvokerFacade.java deleted file mode 100644 index a60e1b285dd..00000000000 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvokerFacade.java +++ /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. - */ - -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; - -/** -* Future facade on top of JVpp -*/ -public class FutureJVppInvokerFacade extends NotificationRegistryProviderContext implements FutureJVppInvoker { - - private final JVpp jvpp; - - /** - * Guarded by self - */ - private final Map>> requests; - - public FutureJVppInvokerFacade(final JVpp jvpp, - final Map>> requestMap) { - this.jvpp = Objects.requireNonNull(jvpp, "Null jvpp"); - // 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"); - } - - protected final Map>> getRequests() { - return this.requests; - } - - // TODO use Optional in Future, java8 - - @Override - @SuppressWarnings("unchecked") - public > CompletionStage send(REQ req) { - synchronized(requests) { - try { - final CompletableFuture replyCompletableFuture; - final int contextId = jvpp.send(req); - - if(req instanceof JVppDump) { - replyCompletableFuture = (CompletableFuture) new CompletableDumpFuture<>(contextId); - } else { - replyCompletableFuture = new CompletableFuture<>(); - } - - requests.put(contextId, replyCompletableFuture); - if(req instanceof JVppDump) { - requests.put(jvpp.send(new ControlPing()), replyCompletableFuture); - } - return replyCompletableFuture; - } catch (VppInvocationException ex) { - final CompletableFuture replyCompletableFuture = new CompletableFuture<>(); - replyCompletableFuture.completeExceptionally(ex); - return replyCompletableFuture; - } - } - } - - static final class CompletableDumpFuture> extends CompletableFuture { - // 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) { - this.contextId = contextId; - } - - long getContextId() { - return contextId; - } - - T getReplyDump() { - return replyDump; - } - - void setReplyDump(final T replyDump) { - this.replyDump = replyDump; - } - } - - @Override - public void close() throws Exception { - // NOOP - } -} 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/CallbackApiTest.java b/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackApiTest.java deleted file mode 100644 index 8c976db2397..00000000000 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackApiTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.openvpp.jvpp.test; - -import org.openvpp.jvpp.JVpp; -import org.openvpp.jvpp.JVppImpl; -import org.openvpp.jvpp.VppCallbackException; -import org.openvpp.jvpp.VppJNIConnection; -import org.openvpp.jvpp.callback.GetNodeIndexCallback; -import org.openvpp.jvpp.callback.ShowVersionCallback; -import org.openvpp.jvpp.callback.SwInterfaceCallback; -import org.openvpp.jvpp.dto.*; - -public class CallbackApiTest { - - private static class TestCallback implements GetNodeIndexCallback, ShowVersionCallback, SwInterfaceCallback { - - @Override - public void onGetNodeIndexReply(final GetNodeIndexReply msg) { - System.out.printf("Received GetNodeIndexReply: context=%d, nodeIndex=%d\n", - msg.context, msg.nodeIndex); - } - @Override - public void onShowVersionReply(final ShowVersionReply msg) { - System.out.printf("Received ShowVersionReply: context=%d, program=%s, version=%s, " + - "buildDate=%s, buildDirectory=%s\n", - msg.context, new String(msg.program), new String(msg.version), - new String(msg.buildDate), new String(msg.buildDirectory)); - } - - @Override - public void onSwInterfaceDetails(final SwInterfaceDetails msg) { - System.out.printf("Received SwInterfaceDetails: interfaceName=%s, l2AddressLength=%d, adminUpDown=%d, " + - "linkUpDown=%d, linkSpeed=%d, linkMtu=%d\n", - new String(msg.interfaceName), msg.l2AddressLength, msg.adminUpDown, - msg.linkUpDown, msg.linkSpeed, (int)msg.linkMtu); - } - - @Override - public void onError(VppCallbackException ex) { - System.out.printf("Received onError exception: call=%s, context=%d, retval=%d\n", ex.getMethodName(), ex.getCtxId(), ex.getErrorCode()); - } - } - - private static void testCallbackApi() throws Exception { - System.out.println("Testing Java callback API"); - JVpp jvpp = new JVppImpl(new VppJNIConnection("CallbackApiTest")); - jvpp.connect(new TestCallback()); - System.out.println("Successfully connected to VPP"); - - System.out.println("Sending ShowVersion request..."); - jvpp.send(new ShowVersion()); - - System.out.println("Sending GetNodeIndex request..."); - GetNodeIndex getNodeIndexRequest = new GetNodeIndex(); - getNodeIndexRequest.nodeName = "node0".getBytes(); - jvpp.send(getNodeIndexRequest); - - System.out.println("Sending SwInterfaceDump request..."); - SwInterfaceDump swInterfaceDumpRequest = new SwInterfaceDump(); - swInterfaceDumpRequest.nameFilterValid = 0; - swInterfaceDumpRequest.nameFilter = "".getBytes(); - jvpp.send(swInterfaceDumpRequest); - - Thread.sleep(5000); - - System.out.println("Disconnecting..."); - jvpp.close(); - Thread.sleep(1000); - } - - public static void main(String[] args) throws Exception { - testCallbackApi(); - } -} diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackJVppFacadeNotificationTest.java b/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackJVppFacadeNotificationTest.java deleted file mode 100644 index 430ce8812c2..00000000000 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackJVppFacadeNotificationTest.java +++ /dev/null @@ -1,87 +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.WantInterfaceEventsCallback; -import org.openvpp.jvpp.callfacade.CallbackJVppFacade; -import org.openvpp.jvpp.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")); - - CallbackJVppFacade jvppCallbackFacade = new CallbackJVppFacade(jvpp); - System.out.println("Successfully connected to VPP"); - - final AutoCloseable notificationListenerReg = - jvppCallbackFacade.getNotificationRegistry().registerSwInterfaceSetFlagsNotificationCallback( - NotificationUtils::printNotification - ); - - jvppCallbackFacade.wantInterfaceEvents(NotificationUtils.getEnableInterfaceNotificationsReq(), - new WantInterfaceEventsCallback() { - @Override - public void onWantInterfaceEventsReply(final WantInterfaceEventsReply reply) { - System.out.println("Interface events started"); - } - - @Override - public void onError(final VppCallbackException ex) { - System.out.printf("Received onError exception: call=%s, context=%d, retval=%d\n", - ex.getMethodName(), ex.getCtxId(), ex.getErrorCode()); - } - }); - - System.out.println("Changing interface configuration"); - NotificationUtils.getChangeInterfaceState().send(jvpp); - - Thread.sleep(1000); - - jvppCallbackFacade.wantInterfaceEvents(NotificationUtils.getDisableInterfaceNotificationsReq(), - new WantInterfaceEventsCallback() { - @Override - public void onWantInterfaceEventsReply(final WantInterfaceEventsReply reply) { - System.out.println("Interface events stopped"); - } - - @Override - public void onError(final VppCallbackException ex) { - System.out.printf("Received onError exception: call=%s, context=%d, retval=%d\n", - ex.getMethodName(), ex.getCtxId(), ex.getErrorCode()); - } - }); - - notificationListenerReg.close(); - - 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/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/CallbackNotificationApiTest.java b/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackNotificationApiTest.java deleted file mode 100644 index 5bf2b212f73..00000000000 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackNotificationApiTest.java +++ /dev/null @@ -1,93 +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 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 org.openvpp.jvpp.JVpp; -import org.openvpp.jvpp.JVppImpl; -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; - -public class CallbackNotificationApiTest { - - private static class TestCallback implements SwInterfaceSetFlagsNotificationCallback, - WantInterfaceEventsCallback, SwInterfaceSetFlagsCallback { - - @Override - public void onSwInterfaceSetFlagsNotification( - final SwInterfaceSetFlagsNotification msg) { - printNotification(msg); - } - - @Override - public void onWantInterfaceEventsReply(final WantInterfaceEventsReply wantInterfaceEventsReply) { - System.out.println("Interface notification stream updated"); - } - - @Override - public void onSwInterfaceSetFlagsReply(final SwInterfaceSetFlagsReply swInterfaceSetFlagsReply) { - System.out.println("Interface flags set successfully"); - } - - @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 testCallbackApi() throws Exception { - System.out.println("Testing Java callback API for notifications"); - JVpp jvpp = new JVppImpl( new VppJNIConnection("CallbackApiTest")); - jvpp.connect( new TestCallback()); - System.out.println("Successfully connected to VPP"); - - getEnableInterfaceNotificationsReq().send(jvpp); - System.out.println("Interface notifications started"); - // TODO test ifc dump which also triggers interface flags send - - System.out.println("Changing interface configuration"); - getChangeInterfaceState().send(jvpp); - - // Notification is received - Thread.sleep(500); - - getDisableInterfaceNotificationsReq().send(jvpp); - System.out.println("Interface events stopped"); - - Thread.sleep(2000); - - System.out.println("Disconnecting..."); - jvpp.close(); - Thread.sleep(1000); - } - - public static void main(String[] args) throws Exception { - testCallbackApi(); - } -} diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/test/ControlPingTest.java b/vpp-api/java/jvpp/org/openvpp/jvpp/test/ControlPingTest.java deleted file mode 100644 index 514bb3ef887..00000000000 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/ControlPingTest.java +++ /dev/null @@ -1,61 +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.ControlPingCallback; -import org.openvpp.jvpp.dto.ControlPing; -import org.openvpp.jvpp.dto.ControlPingReply; - -public class ControlPingTest { - - private static void testControlPing() throws Exception { - System.out.println("Testing ControlPing using Java callback API"); - - JVpp jvpp = new JVppImpl( new VppJNIConnection("ControlPingTest")); - jvpp.connect( 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); - } - - @Override - public void onError(VppCallbackException ex) { - System.out.printf("Received onError exception: call=%s, reply=%d, context=%d ", ex.getMethodName(), ex.getErrorCode(), ex.getCtxId()); - } - - }); - System.out.println("Successfully connected to VPP"); - Thread.sleep(1000); - - jvpp.send(new ControlPing()); - - Thread.sleep(2000); - - System.out.println("Disconnecting..."); - jvpp.close(); - Thread.sleep(1000); - } - - public static void main(String[] args) throws Exception { - testControlPing(); - } -} diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/test/CreateSubInterfaceTest.java b/vpp-api/java/jvpp/org/openvpp/jvpp/test/CreateSubInterfaceTest.java deleted file mode 100644 index b3dc1f49491..00000000000 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/CreateSubInterfaceTest.java +++ /dev/null @@ -1,123 +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.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; - -import static java.util.Objects.requireNonNull; - -/** - *

Tests sub-interface creation.
Equivalent to:
- * - *

{@code
- * vppctl create sub GigabitEthernet0/9/0 1 dot1q 100 inner-dot1q any
- * }
- * 
- * - * To verify invoke:
- *
{@code
- * vpp_api_test json
- * vat# sw_interface_dump
- * }
- */
-public class CreateSubInterfaceTest {
-
-
-    private static SwInterfaceDump createSwInterfaceDumpRequest(final String ifaceName) {
-        SwInterfaceDump request = new SwInterfaceDump();
-        request.nameFilter = ifaceName.getBytes();
-        request.nameFilterValid = 1;
-        return request;
-    }
-
-    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()));
-        }
-    }
-
-    private static CreateSubif createSubifRequest(final int swIfIndex, final int subId) {
-        CreateSubif request = new CreateSubif();
-        request.swIfIndex = swIfIndex; // super interface id
-        request.subId = subId;
-        request.noTags = 0;
-        request.oneTag = 0;
-        request.twoTags = 1;
-        request.dot1Ad = 0;
-        request.exactMatch = 1;
-        request.defaultSub = 0;
-        request.outerVlanIdAny = 0;
-        request.innerVlanIdAny = 1;
-        request.outerVlanId = 100;
-        request.innerVlanId = 0;
-        return request;
-    }
-
-    private static void print(CreateSubifReply reply) {
-        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);
-
-        System.out.println("Successfully connected to VPP");
-        Thread.sleep(1000);
-
-        final String ifaceName = "GigabitEthernet0/9/0";
-
-        final SwInterfaceDetailsReplyDump swInterfaceDetails =
-                jvppFacade.swInterfaceDump(createSwInterfaceDumpRequest(ifaceName)).toCompletableFuture().get();
-
-        requireNonNull(swInterfaceDetails, "swInterfaceDump returned null");
-        requireNonNull(swInterfaceDetails.swInterfaceDetails, "swInterfaceDetails is null");
-        requireSingleIface(swInterfaceDetails, ifaceName);
-
-        final int swIfIndex = swInterfaceDetails.swInterfaceDetails.get(0).swIfIndex;
-        final int subId = 1;
-
-        final CreateSubifReply createSubifReply =
-                jvppFacade.createSubif(createSubifRequest(swIfIndex, subId)).toCompletableFuture().get();
-        print(createSubifReply);
-
-        final String subIfaceName = "GigabitEthernet0/9/0." + subId;
-        final SwInterfaceDetailsReplyDump subIface =
-                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();
-        Thread.sleep(1000);
-    }
-
-    public static void main(String[] args) throws Exception {
-        testCreateSubInterface();
-    }
-}
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/test/FutureApiNotificationTest.java b/vpp-api/java/jvpp/org/openvpp/jvpp/test/FutureApiNotificationTest.java
deleted file mode 100644
index c48f86d4f00..00000000000
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/FutureApiNotificationTest.java
+++ /dev/null
@@ -1,60 +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 static org.openvpp.jvpp.test.NotificationUtils.getChangeInterfaceState;
-import static org.openvpp.jvpp.test.NotificationUtils.getDisableInterfaceNotificationsReq;
-import static org.openvpp.jvpp.test.NotificationUtils.getEnableInterfaceNotificationsReq;
-
-import org.openvpp.jvpp.VppJNIConnection;
-import org.openvpp.jvpp.future.FutureJVppFacade;
-
-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);
-        System.out.println("Successfully connected to VPP");
-
-        final AutoCloseable notificationListenerReg =
-            jvppFacade.getNotificationRegistry().registerSwInterfaceSetFlagsNotificationCallback(NotificationUtils::printNotification);
-
-        jvppFacade.wantInterfaceEvents(getEnableInterfaceNotificationsReq()).toCompletableFuture().get();
-        System.out.println("Interface events started");
-
-        System.out.println("Changing interface configuration");
-        jvppFacade.swInterfaceSetFlags(getChangeInterfaceState()).toCompletableFuture().get();
-
-        Thread.sleep(1000);
-
-        jvppFacade.wantInterfaceEvents(getDisableInterfaceNotificationsReq()).toCompletableFuture().get();
-        System.out.println("Interface events stopped");
-
-        notificationListenerReg.close();
-
-        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/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 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 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 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/L2AclTest.java b/vpp-api/java/jvpp/org/openvpp/jvpp/test/L2AclTest.java
deleted file mode 100644
index 802df631162..00000000000
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/L2AclTest.java
+++ /dev/null
@@ -1,218 +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 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;
-
-/**
- * 

Tests L2 ACL creation and read.
Equivalent to the following vppctl commands:
- * - *

{@code
- * vppctl classify table mask l2 src
- * vppctl classify session acl-hit-next deny opaque-index 0 table-index 0 match l2 src 01:02:03:04:05:06
- * vppctl set int input acl intfc local0 l2-table 0
- * vppctl sh class table verbose
- * }
- * 
- */ -public class L2AclTest { - - private static final int LOCAL0_IFACE_ID = 0; - - private static ClassifyAddDelTable createClassifyTable() { - ClassifyAddDelTable request = new ClassifyAddDelTable(); - request.isAdd = 1; - request.tableIndex = ~0; // default - request.nbuckets = 2; - request.memorySize = 2 << 20; - request.nextTableIndex = ~0; // default - request.missNextIndex = ~0; // default - request.skipNVectors = 0; - request.matchNVectors = 1; - request.mask = - new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, 0x00, 0x00, 0x00, 0x00}; - return request; - } - - private static ClassifyTableInfo createClassifyTableInfoRequest(final int tableId) { - ClassifyTableInfo request = new ClassifyTableInfo(); - request.tableId = tableId; - return request; - } - - private static ClassifyAddDelSession createClassifySession(final int tableIndex) { - ClassifyAddDelSession request = new ClassifyAddDelSession(); - request.isAdd = 1; - request.tableIndex = tableIndex; - request.hitNextIndex = 0; // deny - request.opaqueIndex = 0; - request.advance = 0; // default - // match 01:02:03:04:05:06 mac address - request.match = - new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, - (byte) 0x05, (byte) 0x06, 0x00, 0x00, 0x00, 0x00}; - return request; - } - - private static ClassifySessionDump createClassifySessionDumpRequest(final int newTableIndex) { - ClassifySessionDump request = new ClassifySessionDump(); - request.tableId = newTableIndex; - return request; - } - - private static InputAclSetInterface aclSetInterface() { - InputAclSetInterface request = new InputAclSetInterface(); - request.isAdd = 1; - request.swIfIndex = LOCAL0_IFACE_ID; - request.ip4TableIndex = ~0; // skip - request.ip6TableIndex = ~0; // skip - request.l2TableIndex = 0; - return request; - } - - private static ClassifyTableByInterface createClassifyTableByInterfaceRequest() { - ClassifyTableByInterface request = new ClassifyTableByInterface(); - request.swIfIndex = LOCAL0_IFACE_ID; - return request; - } - - private static void print(ClassifyAddDelTableReply reply) { - System.out.printf("ClassifyAddDelTableReply: context=%d, " + - "newTableIndex=%d, skipNVectors=%d, matchNVectors=%d\n", - reply.context, reply.newTableIndex, reply.skipNVectors, reply.matchNVectors); - } - - private static void print(ClassifyTableIdsReply reply) { - System.out.printf("ClassifyTableIdsReply: context=%d, count=%d, ids.length=%d\n", - reply.context, reply.count, reply.ids.length); - Arrays.stream(reply.ids).forEach(System.out::println); - } - - private static void print(final ClassifyTableInfoReply reply) { - final StringBuilder builder = new StringBuilder("ClassifyTableInfoReply:\n"); - builder.append("context: ").append(reply.context).append('\n'); - builder.append("tableId: ").append(reply.tableId).append('\n'); - builder.append("nbuckets: ").append(reply.nbuckets).append('\n'); - builder.append("matchNVectors: ").append(reply.matchNVectors).append('\n'); - builder.append("skipNVectors: ").append(reply.skipNVectors).append('\n'); - builder.append("activeSessions: ").append(reply.activeSessions).append('\n'); - builder.append("nextTableIndex: ").append(reply.nextTableIndex).append('\n'); - builder.append("missNextIndex: ").append(reply.missNextIndex).append('\n'); - builder.append("maskLength: ").append(reply.maskLength).append('\n'); - builder.append("mask: ").append(DatatypeConverter.printHexBinary(reply.mask)).append('\n'); - System.out.println(builder.toString()); - } - - private static void print(ClassifyAddDelSessionReply reply) { - System.out.printf("ClassifyAddDelSessionReply: context=%d\n", - reply.context); - } - - private static void print(final ClassifySessionDetailsReplyDump reply) { - if (reply.classifySessionDetails == null) { - System.out.println("ClassifySessionDetailsReplyDump: classifySessionDetails == NULL"); - } - for (final ClassifySessionDetails details : reply.classifySessionDetails) { - final StringBuilder builder = new StringBuilder("ClassifySessionDetails:\n"); - builder.append("context: ").append(details.context).append('\n'); - builder.append("tableId: ").append(details.tableId).append('\n'); - builder.append("hitNextIndex: ").append(details.hitNextIndex).append('\n'); - builder.append("advance: ").append(details.advance).append('\n'); - builder.append("opaqueIndex: ").append(details.opaqueIndex).append('\n'); - builder.append("matchLength: ").append(details.matchLength).append('\n'); - builder.append("match: ").append(DatatypeConverter.printHexBinary(details.match)).append('\n'); - System.out.println(builder.toString()); - } - } - - private static void print(final InputAclSetInterfaceReply reply) { - System.out.printf("InputAclSetInterfaceReply: context=%d\n", reply.context); - } - - 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); - } - - 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); - - System.out.println("Successfully connected to VPP"); - Thread.sleep(1000); - - final ClassifyAddDelTableReply classifyAddDelTableReply = - jvppFacade.classifyAddDelTable(createClassifyTable()).toCompletableFuture().get(); - print(classifyAddDelTableReply); - - final ClassifyTableIdsReply classifyTableIdsReply = - jvppFacade.classifyTableIds(new ClassifyTableIds()).toCompletableFuture().get(); - print(classifyTableIdsReply); - - final ClassifyTableInfoReply classifyTableInfoReply = - jvppFacade.classifyTableInfo(createClassifyTableInfoRequest(classifyAddDelTableReply.newTableIndex)) - .toCompletableFuture().get(); - print(classifyTableInfoReply); - - final ClassifyAddDelSessionReply classifyAddDelSessionReply = - jvppFacade.classifyAddDelSession(createClassifySession(classifyAddDelTableReply.newTableIndex)) - .toCompletableFuture().get(); - print(classifyAddDelSessionReply); - - final ClassifySessionDetailsReplyDump classifySessionDetailsReplyDump = - jvppFacade.classifySessionDump(createClassifySessionDumpRequest(classifyAddDelTableReply.newTableIndex)) - .toCompletableFuture().get(); - print(classifySessionDetailsReplyDump); - - final InputAclSetInterfaceReply inputAclSetInterfaceReply = - jvppFacade.inputAclSetInterface(aclSetInterface()).toCompletableFuture().get(); - print(inputAclSetInterfaceReply); - - final ClassifyTableByInterfaceReply classifyTableByInterfaceReply = - jvppFacade.classifyTableByInterface(createClassifyTableByInterfaceRequest()).toCompletableFuture().get(); - print(classifyTableByInterfaceReply); - - System.out.println("Disconnecting..."); - jvpp.close(); - Thread.sleep(1000); - } - - public static void main(String[] args) throws Exception { - testL2Acl(); - } -} diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/test/NotificationUtils.java b/vpp-api/java/jvpp/org/openvpp/jvpp/test/NotificationUtils.java deleted file mode 100644 index 9c24d572cbc..00000000000 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/NotificationUtils.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.openvpp.jvpp.test; - -import java.io.PrintStream; -import org.openvpp.jvpp.dto.SwInterfaceSetFlags; -import org.openvpp.jvpp.dto.SwInterfaceSetFlagsNotification; -import org.openvpp.jvpp.dto.WantInterfaceEvents; - -final class NotificationUtils { - - private NotificationUtils() {} - - static PrintStream printNotification(final SwInterfaceSetFlagsNotification msg) { - return System.out.printf("Received interface notification: ifc: %d, admin: %d, link: %d, deleted: %d\n", - msg.swIfIndex, msg.adminUpDown, msg.linkUpDown, msg.deleted); - } - - static SwInterfaceSetFlags getChangeInterfaceState() { - final SwInterfaceSetFlags swInterfaceSetFlags = new SwInterfaceSetFlags(); - swInterfaceSetFlags.swIfIndex = 0; - swInterfaceSetFlags.adminUpDown = 1; - swInterfaceSetFlags.deleted = 0; - return swInterfaceSetFlags; - } - - static WantInterfaceEvents getEnableInterfaceNotificationsReq() { - WantInterfaceEvents wantInterfaceEvents = new WantInterfaceEvents(); - wantInterfaceEvents.pid = 1; - wantInterfaceEvents.enableDisable = 1; - return wantInterfaceEvents; - } - - static WantInterfaceEvents getDisableInterfaceNotificationsReq() { - WantInterfaceEvents wantInterfaceEvents = new WantInterfaceEvents(); - wantInterfaceEvents.pid = 1; - wantInterfaceEvents.enableDisable = 0; - return wantInterfaceEvents; - } -} 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(); - } -} diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/test/Readme.txt b/vpp-api/java/jvpp/org/openvpp/jvpp/test/Readme.txt deleted file mode 100644 index e0aa4f4d085..00000000000 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/Readme.txt +++ /dev/null @@ -1,17 +0,0 @@ -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] - -Available tests: -ControlPingTest - Simple test executing a single control ping using low level JVpp APIs -CallbackApiTest - Similar to ControlPingTest, invokes more complex calls (e.g. interface dump) using low level JVpp APIs -CallbackNotificationApiTest - Tests interface notifications using low level JVpp APIs -FutureApiTest - Execution of more complex calls using Future based JVpp facade -FutureApiNotificationTest - Tests interface notifications using Future based JVpp facade -CallbackJVppFacadeTest - Execution of more complex calls using Callback based JVpp facade -CallbackJVppFacadeNotificationTest - Tests interface notifications using Callback based JVpp facade -L2AclTest - Tests L2 ACL creation -CreateSubInterfaceTest - Tests sub-interface creation -OnErrorCallbackTest - simple test failing with onError -- cgit 1.2.3-korg