VPP-119: JVpp notifications
- add notification DTOs to JVpp
- add notification callbacks
- add notification registry
- provide/implement notification registry from future and callback facades
Change-Id: I1060ef2ec8ba1eb2e8cff279c93b73aa7c9f9aee
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
diff --git a/vpp-api/java/jvpp/gen/callback_gen.py b/vpp-api/java/jvpp/gen/callback_gen.py
index 8a0d201..eadf3b5 100644
--- a/vpp-api/java/jvpp/gen/callback_gen.py
+++ b/vpp-api/java/jvpp/gen/callback_gen.py
@@ -31,7 +31,7 @@
$docs
* </pre>
*/
-public interface $cls_name extends $base_package.$callback_package.JVppCallback {
+public interface $cls_name extends $base_package.$callback_package.$callback_type {
$callback_method
@@ -61,15 +61,21 @@
callbacks = []
for func in func_list:
- if util.is_notification(func['name']) or util.is_ignored(func['name']):
- # FIXME 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_name = util.remove_reply_suffix(camel_case_name_with_suffix)
+ if util.is_reply(camel_case_name_with_suffix):
+ camel_case_name = util.remove_reply_suffix(camel_case_name_with_suffix)
+ callback_type = "JVppCallback"
+ else:
+ camel_case_name_with_suffix = util.add_notification_suffix(camel_case_name_with_suffix)
+ 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))
callback_path = os.path.join(callback_package, camel_case_name + callback_suffix + ".java")
callback_file = open(callback_path, 'w')
@@ -82,7 +88,8 @@
cls_name=camel_case_name + callback_suffix,
callback_method=method,
base_package=base_package,
- callback_package=callback_package))
+ callback_package=callback_package,
+ callback_type=callback_type))
callback_file.flush()
callback_file.close()
diff --git a/vpp-api/java/jvpp/gen/dto_gen.py b/vpp-api/java/jvpp/gen/dto_gen.py
index 05859db..426cd96 100644
--- a/vpp-api/java/jvpp/gen/dto_gen.py
+++ b/vpp-api/java/jvpp/gen/dto_gen.py
@@ -13,9 +13,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import os, util
+import os
from string import Template
+import util
+
dto_template = Template("""
package $base_package.$dto_package;
@@ -40,6 +42,7 @@
return jvpp.$method_name($args);
}\n""")
+
def generate_dtos(func_list, base_package, dto_package, inputfile):
""" Generates dto objects in a dedicated package """
print "Generating DTOs"
@@ -52,8 +55,7 @@
camel_case_method_name = util.underscore_to_camelcase(func['name'])
dto_path = os.path.join(dto_package, camel_case_dto_name + ".java")
- if util.is_notification(func['name']) or util.is_ignored(func['name']):
- # TODO handle notifications
+ if util.is_ignored(func['name']):
continue
fields = ""
@@ -66,44 +68,63 @@
name=field_name)
methods = ""
base_type = ""
- if util.is_reply(camel_case_dto_name):
- description = "vpe.api 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,
- camel_case_method_name, func)
- else:
- base_type += "JVppReply<%s.%s.%s>" % (base_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,
- args=args)
- if util.is_dump(camel_case_dto_name):
- base_type += "JVppDump"
- description = "vpe.api dump request DTO"
- else:
- base_type += "JVppRequest"
- description = "vpe.api request DTO"
- dto_file = open(dto_path, 'w')
- dto_file.write(dto_template.substitute(inputfile=inputfile,
- description=description,
- docs=util.api_message_to_javadoc(func),
- cls_name=camel_case_dto_name,
- fields=fields,
- methods=methods,
- base_package=base_package,
- base_type=base_type,
- dto_package=dto_package))
- dto_file.flush()
- dto_file.close()
+ # 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"
+ 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,
+ camel_case_method_name, func)
+ else:
+ base_type += "JVppReply<%s.%s.%s>" % (base_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,
+ args=args)
+ if util.is_dump(camel_case_dto_name):
+ base_type += "JVppDump"
+ description = "vpe.api dump request DTO"
+ else:
+ base_type += "JVppRequest"
+ description = "vpe.api request DTO"
+
+ write_dto_file(base_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"
+ 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,
+ 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,
+ inputfile, methods):
+ dto_file = open(dto_path, 'w')
+ dto_file.write(dto_template.substitute(inputfile=inputfile,
+ description=description,
+ docs=util.api_message_to_javadoc(func),
+ cls_name=camel_case_dto_name,
+ fields=fields,
+ methods=methods,
+ base_package=base_package,
+ base_type=base_type,
+ dto_package=dto_package))
+ dto_file.flush()
+ dto_file.close()
+
+
dump_dto_suffix = "ReplyDump"
dump_reply_artificial_dtos = {}
diff --git a/vpp-api/java/jvpp/gen/jvpp_c_gen.py b/vpp-api/java/jvpp/gen/jvpp_c_gen.py
index 082fd5d..c006c34 100644
--- a/vpp-api/java/jvpp/gen/jvpp_c_gen.py
+++ b/vpp-api/java/jvpp/gen/jvpp_c_gen.py
@@ -53,16 +53,21 @@
class_name = util.underscore_to_camelcase_upper(c_name)
ref_name = util.underscore_to_camelcase(c_name)
- if not util.is_reply(class_name) or util.is_ignored(c_name) or util.is_notification(c_name):
- # TODO handle notifications
+ if util.is_ignored(c_name):
continue
- class_references.append(class_reference_template.substitute(
+ 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(
+ find_class_invocations.append(find_class_invocation_template.substitute(
ref_name=ref_name,
class_name=class_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(
+ ref_name=util.add_notification_suffix(ref_name),
+ class_name=util.add_notification_suffix(class_name)))
# add exception class to class cache
ref_name = 'callbackException'
@@ -73,7 +78,7 @@
ref_name=ref_name,
class_name=class_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))
# TODO: cache method and field identifiers to achieve better performance
@@ -174,7 +179,7 @@
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) \
- or util.is_ignored(f_name) or util.is_notification(f_name):
+ or util.is_ignored(f_name) or util.is_just_notification(f_name):
continue
arguments = ''
@@ -331,10 +336,16 @@
dto_name = util.underscore_to_camelcase_upper(handler_name)
ref_name = util.underscore_to_camelcase(handler_name)
- if is_manually_generated(handler_name) or not util.is_reply(dto_name) or util.is_ignored(handler_name) or util.is_notification(handler_name):
- # TODO handle notifications
+ if is_manually_generated(handler_name) or util.is_ignored(handler_name):
continue
+ if not util.is_reply(dto_name) and not util.is_notification(handler_name):
+ continue
+
+ if util.is_notification(handler_name):
+ dto_name = util.add_notification_suffix(dto_name)
+ ref_name = util.add_notification_suffix(ref_name)
+
dto_setters = ''
err_handler = ''
# dto setters
@@ -391,13 +402,12 @@
name = f['name']
camelcase_name = util.underscore_to_camelcase(f['name'])
- if not util.is_reply(camelcase_name) or util.is_ignored(name) or util.is_notification(name):
- # TODO handle notifications
+ if (not util.is_reply(camelcase_name) and not util.is_notification(name)) or util.is_ignored(name):
continue
handler_registration.append(handler_registration_template.substitute(
- name=name,
- upercase_name=name.upper()))
+ name=name,
+ upercase_name=name.upper()))
return "".join(handler_registration)
diff --git a/vpp-api/java/jvpp/gen/jvpp_callback_facade_gen.py b/vpp-api/java/jvpp/gen/jvpp_callback_facade_gen.py
index acf29eb..7df1748 100644
--- a/vpp-api/java/jvpp/gen/jvpp_callback_facade_gen.py
+++ b/vpp-api/java/jvpp/gen/jvpp_callback_facade_gen.py
@@ -27,7 +27,7 @@
* <br>It was generated by jvpp_callback_facade_gen.py based on $inputfile
* <br>(python representation of vpe.api generated by vppapigen).
*/
-public interface CallbackJVpp extends java.lang.AutoCloseable {
+public interface CallbackJVpp extends $base_package.$notification_package.NotificationRegistryProvider, java.lang.AutoCloseable {
@Override
void close();
@@ -46,7 +46,7 @@
* <br>It was generated by jvpp_callback_facade_gen.py based on $inputfile
* <br>(python representation of vpe.api generated by vppapigen).
*/
-public final class CallbackJVppFacade implements $base_package.$callback_facade_package.CallbackJVpp {
+public final class CallbackJVppFacade extends $base_package.$notification_package.NotificationRegistryProviderContext implements $base_package.$callback_facade_package.CallbackJVpp {
private final $base_package.JVpp jvpp;
private final java.util.Map<Integer, $base_package.$callback_package.JVppCallback> callbacks;
@@ -63,7 +63,7 @@
public CallbackJVppFacade(final $base_package.JVpp 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));
+ this.jvpp.connect(new CallbackJVppFacadeCallback(this.callbacks, getNotificationCallback()));
}
@Override
@@ -95,7 +95,7 @@
""")
-def generate_jvpp(func_list, base_package, dto_package, callback_package, callback_facade_package, inputfile):
+def generate_jvpp(func_list, base_package, dto_package, callback_package, notification_package, callback_facade_package, inputfile):
""" Generates callback facade """
print "Generating JVpp callback facade"
@@ -152,6 +152,7 @@
methods="\n".join(methods),
base_package=base_package,
dto_package=dto_package,
+ notification_package=notification_package,
callback_facade_package=callback_facade_package))
jvpp_file.flush()
jvpp_file.close()
@@ -161,12 +162,13 @@
methods="\n".join(methods_impl),
base_package=base_package,
dto_package=dto_package,
+ notification_package=notification_package,
callback_package=callback_package,
callback_facade_package=callback_facade_package))
jvpp_file.flush()
jvpp_file.close()
- generate_callback(func_list, base_package, dto_package, callback_package, callback_facade_package, inputfile)
+ generate_callback(func_list, base_package, dto_package, callback_package, notification_package, callback_facade_package, inputfile)
jvpp_facade_callback_template = Template("""
@@ -180,10 +182,13 @@
public final class CallbackJVppFacadeCallback implements $base_package.$callback_package.JVppGlobalCallback {
private final java.util.Map<Integer, $base_package.$callback_package.JVppCallback> requests;
+ private final $base_package.$notification_package.GlobalNotificationCallback notificationCallback;
private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(CallbackJVppFacadeCallback.class.getName());
- public CallbackJVppFacadeCallback(final java.util.Map<Integer, $base_package.$callback_package.JVppCallback> requestMap) {
+ public CallbackJVppFacadeCallback(final java.util.Map<Integer, $base_package.$callback_package.JVppCallback> requestMap,
+ final $base_package.$notification_package.GlobalNotificationCallback notificationCallback) {
this.requests = requestMap;
+ this.notificationCallback = notificationCallback;
}
@Override
@@ -224,29 +229,44 @@
}
""")
+jvpp_facade_callback_notification_method_template = Template("""
+ @Override
+ @SuppressWarnings("unchecked")
+ public void on$callback_dto($base_package.$dto_package.$callback_dto notification) {
+ notificationCallback.on$callback_dto(notification);
+ }
+""")
-def generate_callback(func_list, base_package, dto_package, callback_package, callback_facade_package, inputfile):
+
+def generate_callback(func_list, base_package, dto_package, callback_package, notification_package, callback_facade_package, inputfile):
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):
- continue
- callbacks.append(jvpp_facade_callback_method_template.substitute(base_package=base_package,
- dto_package=dto_package,
- callback_package=callback_package,
- callback=util.remove_reply_suffix(camel_case_name_with_suffix) + callback_gen.callback_suffix,
- callback_dto=camel_case_name_with_suffix))
+ if util.is_reply(camel_case_name_with_suffix):
+ callbacks.append(jvpp_facade_callback_method_template.substitute(base_package=base_package,
+ dto_package=dto_package,
+ callback_package=callback_package,
+ callback=util.remove_reply_suffix(camel_case_name_with_suffix) + callback_gen.callback_suffix,
+ callback_dto=camel_case_name_with_suffix))
+
+ 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,
+ 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.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),
callback_facade_package=callback_facade_package))
diff --git a/vpp-api/java/jvpp/gen/jvpp_future_facade_gen.py b/vpp-api/java/jvpp/gen/jvpp_future_facade_gen.py
index 7a5a166..e1ca4d0 100644
--- a/vpp-api/java/jvpp/gen/jvpp_future_facade_gen.py
+++ b/vpp-api/java/jvpp/gen/jvpp_future_facade_gen.py
@@ -30,12 +30,16 @@
public final class FutureJVppFacadeCallback implements $base_package.$callback_package.JVppGlobalCallback {
private final java.util.Map<java.lang.Integer, java.util.concurrent.CompletableFuture<? extends $base_package.$dto_package.JVppReply<?>>> requests;
+ private final $base_package.$notification_package.GlobalNotificationCallback notificationCallback;
- public FutureJVppFacadeCallback(final java.util.Map<java.lang.Integer, java.util.concurrent.CompletableFuture<? extends $base_package.$dto_package.JVppReply<?>>> requestMap) {
+ public FutureJVppFacadeCallback(final java.util.Map<java.lang.Integer, java.util.concurrent.CompletableFuture<? extends $base_package.$dto_package.JVppReply<?>>> requestMap,
+ final $base_package.$notification_package.GlobalNotificationCallback notificationCallback) {
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_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 @@
""")
-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 @@
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 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 e2ff2ad..c08593e 100755
--- a/vpp-api/java/jvpp/gen/jvpp_gen.py
+++ b/vpp-api/java/jvpp/gen/jvpp_gen.py
@@ -19,6 +19,7 @@
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 @@
#
# 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 @@
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 @@
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 dfec6a7..93ffd0f 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 @@
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 0000000..4ca3c07
--- /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;
+
+/**
+ * <p>Registry for notification callbacks.
+ * <br>It was generated by notification_gen.py based on $inputfile
+ * <br>(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;
+
+/**
+ * <p>Aggregated callback interface for notifications only.
+ * <br>It was generated by notification_gen.py based on $inputfile
+ * <br>(python representation of vpe.api generated by vppapigen).
+ */
+public interface GlobalNotificationCallback extends $callbacks {
+
+}
+""")
+
+notification_registry_impl_template = Template("""
+package $base_package.$notification_package;
+
+/**
+ * <p>Notification registry delegating notification processing to registered callbacks.
+ * <br>It was generated by notification_gen.py based on $inputfile
+ * <br>(python representation of vpe.api generated by vppapigen).
+ */
+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<Class<? extends $base_package.$dto_package.JVppNotification>, $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 072c9d5..12c8bc3 100644
--- a/vpp-api/java/jvpp/gen/util.py
+++ b/vpp-api/java/jvpp/gen/util.py
@@ -148,15 +148,21 @@
#
# 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 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 0000000..72a75c8
--- /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 0000000..7d0fecb
--- /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 9219e35..1683bd7 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.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 69967a1..a60e1b2 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.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 @@
private final Map<Integer, CompletableFuture<? extends JVppReply<?>>> requests;
public FutureJVppInvokerFacade(final JVpp jvpp,
- final Map<Integer, CompletableFuture<? extends JVppReply<?>>> requestMap) {
+ final Map<Integer, CompletableFuture<? extends JVppReply<?>>> 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 0000000..50b72be
--- /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 0000000..8e70381
--- /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 0000000..430ce88
--- /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 0000000..5bf2b21
--- /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 0000000..c48f86d
--- /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 0000000..9c24d57
--- /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 f9c67dd..e0aa4f4 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 @@
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