From 21f3798c7938d070725816214368394e6a16bd04 Mon Sep 17 00:00:00 2001 From: Michal Cmarada Date: Wed, 23 Jan 2019 09:05:07 +0100 Subject: initial commit - migrates source code from VPP code base - modifies cmake configuration - adds cpack configuration for deb and rpm packaging - adds documentation Change-Id: Ib6a39030f6c47c8ae654fcb886c618e159fb63b4 Signed-off-by: Michal Cmarada --- java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py | 338 ++++++++++++++++++++++++ 1 file changed, 338 insertions(+) create mode 100644 java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py (limited to 'java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py') diff --git a/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py b/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py new file mode 100644 index 0000000..3da367a --- /dev/null +++ b/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py @@ -0,0 +1,338 @@ +#!/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, is_details, is_reply, is_event + + +def generate_future_facade(work_dir, model, logger): + logger.debug("Generating JVpp future facade for %s" % model.json_api_files) + _generate_future_jvpp(work_dir, model), + _generate_future_jvpp_facade(work_dir, model) + _generate_future_jvpp_callback(work_dir, model) + + +def _generate_future_jvpp(work_dir, model): + with open("%s/FutureJVpp%s.java" % (work_dir, model.plugin_java_name), "w") as f: + f.write(_FUTURE_JVPP_TEMPLATE.substitute( + plugin_package=model.plugin_package, + json_filename=model.json_api_files, + plugin_name=model.plugin_java_name, + methods=_generate_future_jvpp_methods(model) + )) + +_FUTURE_JVPP_TEMPLATE = Template(''' +package $plugin_package.future; + +/** + *

Async facade extension adding specific methods for each request invocation + *
It was generated by jvpp_future_facade_gen.py based on $json_filename. + */ +public interface FutureJVpp${plugin_name} extends io.fd.vpp.jvpp.future.FutureJVppInvoker { +$methods + + @Override + public $plugin_package.notification.${plugin_name}EventRegistry getEventRegistry(); + +} +''') + + +def _generate_future_jvpp_methods(model): + methods = [] + for msg in model.messages: + if is_control_ping(msg) or is_control_ping_reply(msg): + # Skip control_ping managed by jvpp registry. + continue + reply_name = None + if is_request(msg): + reply_name = msg.reply_java + elif is_dump(msg): + # use reply dump wrappers + reply_name = "%sReplyDump" % msg.reply_java + else: + continue + + methods.append(_FUTURE_JVPP_METHOD_TEMPLATE.substitute( + plugin_package=model.plugin_package, + method_name=msg.java_name_lower, + reply_name=reply_name, + request_name=msg.java_name_upper + )) + return "".join(methods) + +_FUTURE_JVPP_METHOD_TEMPLATE = Template(''' + java.util.concurrent.CompletionStage<${plugin_package}.dto.${reply_name}> ${method_name}(${plugin_package}.dto.${request_name} request); +''') + + +def _generate_future_jvpp_facade(work_dir, model): + with open("%s/FutureJVpp%sFacade.java" % (work_dir, model.plugin_java_name), "w") as f: + f.write(_FUTURE_JVPP_FACADE_TEMPLATE.substitute( + plugin_package=model.plugin_package, + json_filename=model.json_api_files, + plugin_name=model.plugin_java_name, + methods=_generate_future_jvpp_facade_methods(model) + )) + +_FUTURE_JVPP_FACADE_TEMPLATE = Template(''' +package $plugin_package.future; + +/** + *

Implementation of FutureJVpp based on AbstractFutureJVppInvoker + *
It was generated by jvpp_future_facade_gen.py based on $json_filename. + */ +public class FutureJVpp${plugin_name}Facade extends io.fd.vpp.jvpp.future.AbstractFutureJVppInvoker implements FutureJVpp${plugin_name} { + + private final $plugin_package.notification.${plugin_name}EventRegistryImpl eventRegistry = new $plugin_package.notification.${plugin_name}EventRegistryImpl(); + + /** + *

Create FutureJVpp${plugin_name}Facade object for provided JVpp instance. + * Constructor internally creates FutureJVppFacadeCallback class for processing callbacks + * and then connects to provided JVpp instance + * + * @param jvpp provided io.fd.vpp.jvpp.JVpp instance + * + * @throws java.io.IOException in case instance cannot connect to JVPP + */ + public FutureJVpp${plugin_name}Facade(final io.fd.vpp.jvpp.JVppRegistry registry, final io.fd.vpp.jvpp.JVpp jvpp) throws java.io.IOException { + super(jvpp, registry, new java.util.HashMap<>()); + java.util.Objects.requireNonNull(registry, "JVppRegistry should not be null"); + registry.register(jvpp, new FutureJVpp${plugin_name}FacadeCallback(getRequests(), eventRegistry)); + } + + @Override + public $plugin_package.notification.${plugin_name}EventRegistry getEventRegistry() { + return eventRegistry; + } + +$methods +} +''') + + +def _generate_future_jvpp_facade_methods(model): + methods = [] + for msg in model.messages: + if is_control_ping(msg) or is_control_ping_reply(msg): + # Skip control_ping managed by jvpp registry. + continue + template = None + if is_request(msg): + template = _FUTURE_JVPP_FACADE_REQUEST_TEMPLATE + elif is_dump(msg): + template = _FUTURE_JVPP_FACADE_DUMP_TEMPLATE + else: + continue + + methods.append(template.substitute( + plugin_package=model.plugin_package, + method_name=msg.java_name_lower, + reply_name=msg.reply_java, + request_name=msg.java_name_upper + )) + return "".join(methods) + +_FUTURE_JVPP_FACADE_REQUEST_TEMPLATE = Template(''' + @Override + public java.util.concurrent.CompletionStage<${plugin_package}.dto.${reply_name}> ${method_name}(${plugin_package}.dto.${request_name} request) { + return send(request); + } +''') + +_FUTURE_JVPP_FACADE_DUMP_TEMPLATE = Template(''' + @Override + public java.util.concurrent.CompletionStage<${plugin_package}.dto.${reply_name}ReplyDump> ${method_name}(${plugin_package}.dto.${request_name} request) { + return send(request, new ${plugin_package}.dto.${reply_name}ReplyDump()); + } +''') + + +def _generate_future_jvpp_callback(work_dir, model): + with open("%s/FutureJVpp%sFacadeCallback.java" % (work_dir, model.plugin_java_name), "w") as f: + f.write(_FUTURE_JVPP_CALLBACK_TEMPLATE.substitute( + plugin_package=model.plugin_package, + json_filename=model.json_api_files, + plugin_name=model.plugin_java_name, + methods=_generate_future_jvpp_callback_methods(model) + )) + +_FUTURE_JVPP_CALLBACK_TEMPLATE = Template(""" +package $plugin_package.future; + +/** + *

Async facade callback setting values to future objects + *
It was generated by jvpp_future_facade_gen.py based on $json_filename. + */ +public final class FutureJVpp${plugin_name}FacadeCallback implements $plugin_package.callback.JVpp${plugin_name}GlobalCallback { + + private final java.util.Map>> requests; + private final $plugin_package.notification.Global${plugin_name}EventCallback notificationCallback; + private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(FutureJVpp${plugin_name}FacadeCallback.class.getName()); + + public FutureJVpp${plugin_name}FacadeCallback( + final java.util.Map>> requestMap, + final $plugin_package.notification.Global${plugin_name}EventCallback notificationCallback) { + this.requests = requestMap; + this.notificationCallback = notificationCallback; + } + + @Override + @SuppressWarnings("unchecked") + public void onError(io.fd.vpp.jvpp.VppCallbackException reply) { + final java.util.concurrent.CompletableFuture> completableFuture; + + synchronized(requests) { + completableFuture = (java.util.concurrent.CompletableFuture>) requests.get(reply.getCtxId()); + } + + if(completableFuture != null) { + completableFuture.completeExceptionally(reply); + + synchronized(requests) { + requests.remove(reply.getCtxId()); + } + } + } + + @Override + @SuppressWarnings("unchecked") + public void onControlPingReply(final io.fd.vpp.jvpp.dto.ControlPingReply reply) { + java.util.concurrent.CompletableFuture> completableFuture; + + final int replyId = reply.context; + synchronized(requests) { + completableFuture = (java.util.concurrent.CompletableFuture>) requests.get(replyId); + + if(completableFuture != null) { + // Finish dump call + if (completableFuture instanceof io.fd.vpp.jvpp.future.AbstractFutureJVppInvoker.CompletableDumpFuture) { + completableFuture.complete(((io.fd.vpp.jvpp.future.AbstractFutureJVppInvoker.CompletableDumpFuture) completableFuture).getReplyDump()); + // Remove future mapped to dump call context id + requests.remove(((io.fd.vpp.jvpp.future.AbstractFutureJVppInvoker.CompletableDumpFuture) completableFuture).getContextId()); + } else { + // reply to regular control ping, complete the future + completableFuture.complete(reply); + } + requests.remove(replyId); + } else { + // future not yet created by writer, create new future, complete it and put to map under ping id + completableFuture = new java.util.concurrent.CompletableFuture<>(); + completableFuture.complete(reply); + requests.put(replyId, completableFuture); + } + } + } + +$methods +} +""") + + +def _generate_future_jvpp_callback_methods(model): + methods = [] + for msg in model.messages: + if is_control_ping(msg) or is_control_ping_reply(msg): + # Skip control_ping managed by jvpp registry. + continue + if is_dump(msg) or is_request(msg): + continue + + # Generate callbacks for all messages except for dumps and requests (handled by vpp, not client). + template = None + request_dto = None + if is_details(msg): + template = _FUTURE_JVPP_FACADE_DETAILS_CALLBACK_TEMPLATE + request_dto = msg.request_java + elif is_reply(msg): + template = _FUTURE_JVPP_FACADE_REPLY_CALLBACK_TEMPLATE + request_dto = msg.request_java + elif is_event(msg): + template = _FUTURE_JVPP_FACADE_EVENT_CALLBACK_TEMPLATE + else: + raise TypeError("Unknown message type %s", msg) + + methods.append(template.substitute( + plugin_package=model.plugin_package, + callback_dto=msg.java_name_upper, + request_dto=request_dto, + callback_dto_field=msg.java_name_lower, + )) + return "".join(methods) + + +_FUTURE_JVPP_FACADE_DETAILS_CALLBACK_TEMPLATE = Template(""" + @Override + @SuppressWarnings("unchecked") + public void on$callback_dto(final $plugin_package.dto.$callback_dto reply) { + io.fd.vpp.jvpp.future.AbstractFutureJVppInvoker.CompletableDumpFuture<$plugin_package.dto.${callback_dto}ReplyDump> completableFuture; + final int replyId = reply.context; + if (LOG.isLoggable(java.util.logging.Level.FINE)) { + LOG.fine(java.lang.String.format("Received $callback_dto event message: %s", reply)); + } + synchronized(requests) { + completableFuture = (io.fd.vpp.jvpp.future.AbstractFutureJVppInvoker.CompletableDumpFuture<$plugin_package.dto.${callback_dto}ReplyDump>) requests.get(replyId); + + if(completableFuture == null) { + // reply received before writer created future, + // create new future, and put into map to notify sender that reply is already received, + // following details replies will add information to this future + completableFuture = new io.fd.vpp.jvpp.future.AbstractFutureJVppInvoker.CompletableDumpFuture<>(replyId, + new $plugin_package.dto.${callback_dto}ReplyDump()); + requests.put(replyId, completableFuture); + } + completableFuture.getReplyDump().$callback_dto_field.add(reply); + } + } +""") + +_FUTURE_JVPP_FACADE_REPLY_CALLBACK_TEMPLATE = Template(""" + @Override + @SuppressWarnings("unchecked") + public void on$callback_dto(final $plugin_package.dto.$callback_dto reply) { + java.util.concurrent.CompletableFuture> completableFuture; + final int replyId = reply.context; + if (LOG.isLoggable(java.util.logging.Level.FINE)) { + LOG.fine(java.lang.String.format("Received $callback_dto event message: %s", reply)); + } + synchronized(requests) { + completableFuture = + (java.util.concurrent.CompletableFuture>) requests.get(replyId); + + if(completableFuture != null) { + // received reply on request, complete future created by sender and remove it from map + completableFuture.complete(reply); + requests.remove(replyId); + } else { + // reply received before writer created future, + // create new future, complete it and put into map to + // notify sender that reply is already received + completableFuture = new java.util.concurrent.CompletableFuture<>(); + completableFuture.complete(reply); + requests.put(replyId, completableFuture); + } + } + } +""") + +_FUTURE_JVPP_FACADE_EVENT_CALLBACK_TEMPLATE = Template(""" + @Override + public void on$callback_dto($plugin_package.dto.$callback_dto notification) { + if (LOG.isLoggable(java.util.logging.Level.FINE)) { + LOG.fine(java.lang.String.format("Received $callback_dto event message: %s", notification)); + } + notificationCallback.on$callback_dto(notification); + } +""") -- cgit 1.2.3-korg