#!/usr/bin/env python2 # # Copyright (c) 2016,2018 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. from string import Template from jvpp_model import is_control_ping, is_control_ping_reply, is_dump, is_request def generate_notifications(work_dir, model, logger): """ Generates notification registry interface and implementation """ logger.debug("Generating Notification interfaces and implementation for %s" % model.json_api_files) messages = filter(_notification_filter, model.messages) _generate_global_event_callback(work_dir, model, messages) _generate_event_registry(work_dir, model, messages) _generate_event_registry_impl(work_dir, model, messages) _generate_event_registry_provider(work_dir, model) def _notification_filter(msg): # Generate callbacks for all messages except for dumps and requests (handled by vpp, not client). # Also skip control ping managed by jvpp registry. return (not is_control_ping(msg)) and \ (not is_control_ping_reply(msg)) and \ (not is_dump(msg)) and \ (not is_request(msg)) def _generate_event_registry(work_dir, model, messages): plugin_name = model.plugin_java_name plugin_package = model.plugin_package register_callback_methods = [] for msg in messages: name = _callback_name(msg) fqn_name = _fqn_callback_name(plugin_package, name) # 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%s(%s callback);" % (name, fqn_name)) with open("%s/%sEventRegistry.java" % (work_dir, plugin_name), "w") as f: f.write(_EVENT_REGISTRY_TEMPLATE.substitute( plugin_package=plugin_package, plugin_name=plugin_name, json_filename=model.json_api_files, register_callback_methods="\n".join(register_callback_methods) )) _EVENT_REGISTRY_TEMPLATE = Template(""" package $plugin_package.notification; /** *
Registry for notification callbacks defined in ${plugin_name}.
*
It was generated by notification_gen.py based on $json_filename.
*/
public interface ${plugin_name}EventRegistry extends io.fd.vpp.jvpp.notification.EventRegistry {
$register_callback_methods
@Override
void close();
}
""")
def _generate_event_registry_impl(work_dir, model, messages):
plugin_name = model.plugin_java_name
plugin_package = model.plugin_package
register_callback_methods = []
handler_methods = []
for msg in messages:
notification = msg.java_name_upper
callback = "%sCallback" % notification
register_callback_methods.append(_REGISTER_CALLBACK_IMPL_TEMPLATE.substitute(
plugin_package=plugin_package,
notification=notification,
callback=callback
))
handler_methods.append(_HANDLER_IMPL_TEMPLATE.substitute(
plugin_package=plugin_package,
notification=notification,
callback=callback
))
with open("%s/%sEventRegistryImpl.java" % (work_dir, plugin_name), "w") as f:
f.write(_EVENT_REGISTRY_IMPL_TEMPLATE.substitute(
plugin_package=plugin_package,
plugin_name=plugin_name,
json_filename=model.json_api_files,
register_callback_methods="".join(register_callback_methods),
handler_methods="".join(handler_methods)
))
_REGISTER_CALLBACK_IMPL_TEMPLATE = Template("""
public java.lang.AutoCloseable register$callback(final $plugin_package.callback.$callback callback){
if(null != registeredCallbacks.putIfAbsent($plugin_package.dto.$notification.class, callback)){
throw new IllegalArgumentException("Callback for " + $plugin_package.dto.$notification.class +
"notification already registered");
}
return () -> registeredCallbacks.remove($plugin_package.dto.$notification.class);
}
""")
_HANDLER_IMPL_TEMPLATE = Template("""
@Override
public void on$notification(
final $plugin_package.dto.$notification notification) {
if (LOG.isLoggable(java.util.logging.Level.FINE)) {
LOG.fine(String.format("Received $notification event message: %s", notification));
}
final io.fd.vpp.jvpp.callback.JVppCallback jVppCallback = registeredCallbacks.get($plugin_package.dto.$notification.class);
if (null != jVppCallback) {
(($plugin_package.callback.$callback) registeredCallbacks
.get($plugin_package.dto.$notification.class))
.on$notification(notification);
}
}
""")
_EVENT_REGISTRY_IMPL_TEMPLATE = Template("""
package $plugin_package.notification;
/**
*
Notification registry delegating notification processing to registered callbacks.
* Aggregated callback interface for notifications only.
*
It was generated by notification_gen.py based on $json_filename.
*/
public final class ${plugin_name}EventRegistryImpl implements ${plugin_name}EventRegistry, Global${plugin_name}EventCallback {
// TODO add a special NotificationCallback interface and only allow those to be registered
private final java.util.concurrent.ConcurrentMap
It was generated by notification_gen.py based on $json_filename.
*/
public interface Global${plugin_name}EventCallback$callbacks {
}
""")
def _generate_event_registry_provider(work_dir, model):
plugin_name = model.plugin_java_name
with open("%s/%sEventRegistryProvider.java" % (work_dir, plugin_name), "w") as f:
f.write(_EVENT_REGISTRY_PROVIDER_TEMPLATE.substitute(
plugin_package=model.plugin_package,
plugin_name=plugin_name,
json_filename=model.json_api_files
))
_EVENT_REGISTRY_PROVIDER_TEMPLATE = Template("""
package $plugin_package.notification;
/**
* Provides ${plugin_name}EventRegistry.
*
The file was generated by notification_gen.py based on $json_filename.
*/
public interface ${plugin_name}EventRegistryProvider extends io.fd.vpp.jvpp.notification.EventRegistryProvider {
@Override
public ${plugin_name}EventRegistry getEventRegistry();
}
""")
def _callback_name(msg):
return "%sCallback" % msg.java_name_upper
def _fqn_callback_name(plugin_package, callback_name):
return "%s.callback.%s" % (plugin_package, callback_name)