>> requestMap,
+ final $base_package.$notification_package.GlobalNotificationCallback notificationCallback) {
this.requests = requestMap;
+ this.notificationCallback = notificationCallback;
}
@Override
+ @SuppressWarnings("unchecked")
public void onError(org.openvpp.jvpp.VppCallbackException reply) {
final java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply>> completableFuture;
@@ -76,6 +80,13 @@ jvpp_facade_callback_method_template = Template("""
}
""")
+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);
+ }
+""")
+
# TODO reuse common parts with generic method callback
jvpp_facade_control_ping_method_template = Template("""
@Override
@@ -129,7 +140,7 @@ jvpp_facade_details_callback_method_template = Template("""
""")
-def generate_jvpp(func_list, base_package, dto_package, callback_package, future_facade_package, inputfile):
+def generate_jvpp(func_list, base_package, dto_package, callback_package, notification_package, future_facade_package, inputfile):
""" Generates JVpp interface and JNI implementation """
print "Generating JVpp future facade"
@@ -141,70 +152,77 @@ def generate_jvpp(func_list, base_package, dto_package, callback_package, future
callbacks = []
for func in func_list:
- if util.is_notification(func['name']) or util.is_ignored(func['name']):
- # TODO handle notifications
+ if util.is_ignored(func['name']):
continue
camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name'])
- if not util.is_reply(camel_case_name_with_suffix):
+ if not util.is_reply(camel_case_name_with_suffix) and not util.is_notification(func['name']):
continue
camel_case_method_name = util.underscore_to_camelcase(func['name'])
- camel_case_request_method_name = util.remove_reply_suffix(util.underscore_to_camelcase(func['name']))
- if util.is_details(camel_case_name_with_suffix):
- 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,
- 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,
- 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,
- 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)))
- else:
- 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)
+ if not util.is_notification(func["name"]):
+ camel_case_request_method_name = util.remove_reply_suffix(util.underscore_to_camelcase(func['name']))
+ if util.is_details(camel_case_name_with_suffix):
+ 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,
+ 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,
- 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,
- 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))
+ methods.append(future_jvpp_method_template.substitute(base_package=base_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,
+ 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)))
else:
- callbacks.append(jvpp_facade_callback_method_template.substitute(base_package=base_package,
- dto_package=dto_package,
- callback_dto=camel_case_name_with_suffix))
+ 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,
+ 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,
+ 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))
+
+ if util.is_notification(func["name"]):
+ callbacks.append(jvpp_facade_callback_notification_method_template.substitute(base_package=base_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.write(jvpp_facade_callback_template.substitute(inputfile=inputfile,
base_package=base_package,
dto_package=dto_package,
+ notification_package=notification_package,
callback_package=callback_package,
methods="".join(callbacks),
future_package=future_facade_package))
@@ -268,7 +286,7 @@ public class FutureJVppFacade extends FutureJVppInvokerFacade implements FutureJ
*/
public FutureJVppFacade(final $base_package.JVpp jvpp) throws java.io.IOException {
super(jvpp, new java.util.HashMap<>());
- jvpp.connect(new FutureJVppFacadeCallback(getRequests()));
+ jvpp.connect(new FutureJVppFacadeCallback(getRequests(), getNotificationCallback()));
}
$methods
}
diff --git a/vpp-api/java/jvpp/gen/jvpp_gen.py b/vpp-api/java/jvpp/gen/jvpp_gen.py
index e2ff2adcf14..c08593e180f 100755
--- a/vpp-api/java/jvpp/gen/jvpp_gen.py
+++ b/vpp-api/java/jvpp/gen/jvpp_gen.py
@@ -19,6 +19,7 @@ import importlib
import sys
import callback_gen
+import notification_gen
import dto_gen
import jvpp_callback_facade_gen
import jvpp_future_facade_gen
@@ -32,7 +33,7 @@ import util
#
# Compilation:
# ~/Projects/vpp/vpp-api/jvpp/gen/java/org/openvpp/jvpp$ javac *.java dto/*.java callback/*.java
-#
+#
# where
# defs_api_vpp_papi.py - vpe.api in python format (generated by vppapigen)
from util import vpp_2_jni_type_mapping
@@ -122,6 +123,7 @@ func_list, func_name = get_definitions()
base_package = 'org.openvpp.jvpp'
dto_package = 'dto'
callback_package = 'callback'
+notification_package = 'notification'
future_package = 'future'
# TODO find better package name
callback_facade_package = 'callfacade'
@@ -129,6 +131,7 @@ 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, future_package, args.inputfile)
-jvpp_callback_facade_gen.generate_jvpp(func_list, base_package, dto_package, callback_package, callback_facade_package, 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)
diff --git a/vpp-api/java/jvpp/gen/jvpp_impl_gen.py b/vpp-api/java/jvpp/gen/jvpp_impl_gen.py
index dfec6a743de..93ffd0fb359 100644
--- a/vpp-api/java/jvpp/gen/jvpp_impl_gen.py
+++ b/vpp-api/java/jvpp/gen/jvpp_impl_gen.py
@@ -121,8 +121,8 @@ def generate_jvpp(func_list, base_package, dto_package, inputfile):
methods_impl = []
for func in func_list:
- if util.is_notification(func['name']) or util.is_ignored(func['name']):
- # TODO handle notifications
+ # Skip structures that are used only as notifications
+ if util.is_just_notification(func['name']) or util.is_ignored(func['name']):
continue
camel_case_name = util.underscore_to_camelcase(func['name'])
diff --git a/vpp-api/java/jvpp/gen/notification_gen.py b/vpp-api/java/jvpp/gen/notification_gen.py
new file mode 100644
index 00000000000..4ca3c070431
--- /dev/null
+++ b/vpp-api/java/jvpp/gen/notification_gen.py
@@ -0,0 +1,164 @@
+#!/usr/bin/env python
+#
+# 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.
+
+import os
+
+import callback_gen
+import util
+from string import Template
+
+from util import remove_suffix
+
+notification_registry_template = Template("""
+package $base_package.$notification_package;
+
+/**
+ * Registry for notification callbacks.
+ *
It was generated by notification_gen.py based on $inputfile
+ *
(python representation of vpe.api generated by vppapigen).
+ */
+public interface NotificationRegistry extends java.lang.AutoCloseable {
+
+ $register_callback_methods
+
+ @Override
+ void close();
+}
+""")
+
+global_notification_callback_template = Template("""
+package $base_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).
+ */
+public interface GlobalNotificationCallback extends $callbacks {
+
+}
+""")
+
+notification_registry_impl_template = Template("""
+package $base_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).
+ */
+public final class NotificationRegistryImpl implements NotificationRegistry, GlobalNotificationCallback {
+
+ // 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 =
+ new java.util.concurrent.ConcurrentHashMap<>();
+
+ $register_callback_methods
+ $handler_methods
+
+ @Override
+ public void close() {
+ registeredCallbacks.clear();
+ }
+}
+""")
+
+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 +
+ "notification already registered");
+ }
+ return () -> registeredCallbacks.remove($base_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))
+ .on$notification(notification);
+ }
+ }
+""")
+
+
+def generate_notification_registry(func_list, base_package, notification_package, callback_package, dto_package, inputfile):
+ """ Generates notification registry interface and implementation """
+ print "Generating Notification interfaces and implementation"
+
+ if not os.path.exists(notification_package):
+ raise Exception("%s folder is missing" % notification_package)
+
+ callbacks = []
+ register_callback_methods = []
+ register_callback_methods_impl = []
+ handler_methods = []
+ for func in func_list:
+
+ if not util.is_notification(func['name']):
+ continue
+
+ 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)
+ 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,
+ 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,
+ callback_package=callback_package,
+ dto_package=dto_package,
+ notification=notification_dto,
+ callback=callback_ifc))
+
+ 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()
diff --git a/vpp-api/java/jvpp/gen/util.py b/vpp-api/java/jvpp/gen/util.py
index 072c9d592f2..12c8bc3170f 100644
--- a/vpp-api/java/jvpp/gen/util.py
+++ b/vpp-api/java/jvpp/gen/util.py
@@ -148,15 +148,21 @@ unconventional_naming_rep_req = {
#
# FIXME no convention in the naming of events (notifications) in vpe.api
notifications_message_suffixes = ("event", "counters")
-notification_messages = ["from_netconf_client", "from_netconf_server", "to_netconf_client", "to_netconf_server"]
+notification_messages_reused = ["sw_interface_set_flags"]
# messages that must be ignored. These messages are INSUFFICIENTLY marked as disabled in vpe.api
# FIXME
ignored_messages = ["is_address_reachable"]
-def is_notification(param):
- return param.lower().endswith(notifications_message_suffixes) or param.lower() in notification_messages
+def is_notification(name):
+ """ Returns true if the structure is a notification regardless of its no other use """
+ return is_just_notification(name) or name.lower() in notification_messages_reused
+
+
+def is_just_notification(name):
+ """ Returns true if the structure is just a notification and has no other use """
+ return name.lower().endswith(notifications_message_suffixes)
def is_ignored(param):
@@ -178,4 +184,12 @@ def is_control_ping(camel_case_name_with_suffix):
def api_message_to_javadoc(api_message):
""" Converts vpe.api message description to javadoc """
str = pprint.pformat(api_message, indent=4, width=120, depth=None)
- return " * " + str.replace("\n", "\n * ")
\ No newline at end of file
+ return " * " + str.replace("\n", "\n * ")
+
+
+notification_dto_suffix = "Notification"
+
+
+def add_notification_suffix(camel_case_dto_name):
+ camel_case_dto_name += notification_dto_suffix
+ return camel_case_dto_name
\ No newline at end of file
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/callback/JVppNotificationCallback.java b/vpp-api/java/jvpp/org/openvpp/jvpp/callback/JVppNotificationCallback.java
new file mode 100644
index 00000000000..72a75c83942
--- /dev/null
+++ b/vpp-api/java/jvpp/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/org/openvpp/jvpp/dto/JVppNotification.java b/vpp-api/java/jvpp/org/openvpp/jvpp/dto/JVppNotification.java
new file mode 100644
index 00000000000..7d0fecb7d78
--- /dev/null
+++ b/vpp-api/java/jvpp/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/org/openvpp/jvpp/future/FutureJVppInvoker.java b/vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvoker.java
index 9219e353cdb..1683bd75139 100644
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvoker.java
+++ b/vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvoker.java
@@ -21,11 +21,12 @@ 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 AutoCloseable {
+public interface FutureJVppInvoker extends NotificationRegistryProvider, AutoCloseable {
/**
* Invoke asynchronous operation on VPP
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvokerFacade.java b/vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvokerFacade.java
index 69967a1dbc1..a60e1b285dd 100644
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvokerFacade.java
+++ b/vpp-api/java/jvpp/org/openvpp/jvpp/future/FutureJVppInvokerFacade.java
@@ -25,11 +25,12 @@ 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 implements FutureJVppInvoker {
+public class FutureJVppInvokerFacade extends NotificationRegistryProviderContext implements FutureJVppInvoker {
private final JVpp jvpp;
@@ -39,7 +40,7 @@ public class FutureJVppInvokerFacade implements FutureJVppInvoker {
private final Map>> requests;
public FutureJVppInvokerFacade(final JVpp jvpp,
- final Map>> requestMap) {
+ 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
diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/notification/NotificationRegistryProvider.java b/vpp-api/java/jvpp/org/openvpp/jvpp/notification/NotificationRegistryProvider.java
new file mode 100644
index 00000000000..50b72be5805
--- /dev/null
+++ b/vpp-api/java/jvpp/org/openvpp/jvpp/notification/NotificationRegistryProvider.java
@@ -0,0 +1,12 @@
+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
new file mode 100644
index 00000000000..8e703812eee
--- /dev/null
+++ b/vpp-api/java/jvpp/org/openvpp/jvpp/notification/NotificationRegistryProviderContext.java
@@ -0,0 +1,20 @@
+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/CallbackJVppFacadeNotificationTest.java b/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackJVppFacadeNotificationTest.java
new file mode 100644
index 00000000000..430ce8812c2
--- /dev/null
+++ b/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackJVppFacadeNotificationTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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/CallbackNotificationApiTest.java b/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackNotificationApiTest.java
new file mode 100644
index 00000000000..5bf2b212f73
--- /dev/null
+++ b/vpp-api/java/jvpp/org/openvpp/jvpp/test/CallbackNotificationApiTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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/FutureApiNotificationTest.java b/vpp-api/java/jvpp/org/openvpp/jvpp/test/FutureApiNotificationTest.java
new file mode 100644
index 00000000000..c48f86d4f00
--- /dev/null
+++ b/vpp-api/java/jvpp/org/openvpp/jvpp/test/FutureApiNotificationTest.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.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/NotificationUtils.java b/vpp-api/java/jvpp/org/openvpp/jvpp/test/NotificationUtils.java
new file mode 100644
index 00000000000..9c24d572cbc
--- /dev/null
+++ b/vpp-api/java/jvpp/org/openvpp/jvpp/test/NotificationUtils.java
@@ -0,0 +1,38 @@
+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/Readme.txt b/vpp-api/java/jvpp/org/openvpp/jvpp/test/Readme.txt
index f9c67ddbcb6..e0aa4f4d085 100644
--- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/Readme.txt
+++ b/vpp-api/java/jvpp/org/openvpp/jvpp/test/Readme.txt
@@ -7,8 +7,11 @@ This package contains basic tests for jvpp. To run the tests:
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