API: Use string type instead of u8.
[vpp.git] / extras / japi / java / jvpp / gen / jvppgen / jvpp_future_facade_gen.py
1 #!/usr/bin/env python2
2 #
3 # Copyright (c) 2016,2018 Cisco and/or its affiliates.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 from string import Template
16
17 from jvpp_model import is_control_ping, is_control_ping_reply, is_dump, is_request, is_details, is_reply, is_event
18
19
20 def generate_future_facade(work_dir, model, logger):
21     logger.debug("Generating JVpp future facade for %s" % model.json_api_files)
22     _generate_future_jvpp(work_dir, model),
23     _generate_future_jvpp_facade(work_dir, model)
24     _generate_future_jvpp_callback(work_dir, model)
25
26
27 def _generate_future_jvpp(work_dir, model):
28     with open("%s/FutureJVpp%s.java" % (work_dir, model.plugin_java_name), "w") as f:
29         f.write(_FUTURE_JVPP_TEMPLATE.substitute(
30             plugin_package=model.plugin_package,
31             json_filename=model.json_api_files,
32             plugin_name=model.plugin_java_name,
33             methods=_generate_future_jvpp_methods(model)
34         ))
35
36 _FUTURE_JVPP_TEMPLATE = Template('''
37 package $plugin_package.future;
38
39 /**
40  * <p>Async facade extension adding specific methods for each request invocation
41  * <br>It was generated by jvpp_future_facade_gen.py based on $json_filename.
42  */
43 public interface FutureJVpp${plugin_name} extends io.fd.vpp.jvpp.future.FutureJVppInvoker {
44 $methods
45
46     @Override
47     public $plugin_package.notification.${plugin_name}EventRegistry getEventRegistry();
48
49 }
50 ''')
51
52
53 def _generate_future_jvpp_methods(model):
54     methods = []
55     for msg in model.messages:
56         if is_control_ping(msg) or is_control_ping_reply(msg):
57             # Skip control_ping managed by jvpp registry.
58             continue
59         reply_name = None
60         if is_request(msg):
61             reply_name = msg.reply_java
62         elif is_dump(msg):
63             # use reply dump wrappers
64             reply_name = "%sReplyDump" % msg.reply_java
65         else:
66             continue
67
68         methods.append(_FUTURE_JVPP_METHOD_TEMPLATE.substitute(
69             plugin_package=model.plugin_package,
70             method_name=msg.java_name_lower,
71             reply_name=reply_name,
72             request_name=msg.java_name_upper
73         ))
74     return "".join(methods)
75
76 _FUTURE_JVPP_METHOD_TEMPLATE = Template('''
77     java.util.concurrent.CompletionStage<${plugin_package}.dto.${reply_name}> ${method_name}(${plugin_package}.dto.${request_name} request);
78 ''')
79
80
81 def _generate_future_jvpp_facade(work_dir, model):
82     with open("%s/FutureJVpp%sFacade.java" % (work_dir, model.plugin_java_name), "w") as f:
83         f.write(_FUTURE_JVPP_FACADE_TEMPLATE.substitute(
84             plugin_package=model.plugin_package,
85             json_filename=model.json_api_files,
86             plugin_name=model.plugin_java_name,
87             methods=_generate_future_jvpp_facade_methods(model)
88         ))
89
90 _FUTURE_JVPP_FACADE_TEMPLATE = Template('''
91 package $plugin_package.future;
92
93 /**
94  * <p>Implementation of FutureJVpp based on AbstractFutureJVppInvoker
95  * <br>It was generated by jvpp_future_facade_gen.py based on $json_filename.
96  */
97 public class FutureJVpp${plugin_name}Facade extends io.fd.vpp.jvpp.future.AbstractFutureJVppInvoker implements FutureJVpp${plugin_name} {
98
99     private final $plugin_package.notification.${plugin_name}EventRegistryImpl eventRegistry = new $plugin_package.notification.${plugin_name}EventRegistryImpl();
100
101     /**
102      * <p>Create FutureJVpp${plugin_name}Facade object for provided JVpp instance.
103      * Constructor internally creates FutureJVppFacadeCallback class for processing callbacks
104      * and then connects to provided JVpp instance
105      *
106      * @param jvpp provided io.fd.vpp.jvpp.JVpp instance
107      *
108      * @throws java.io.IOException in case instance cannot connect to JVPP
109      */
110     public FutureJVpp${plugin_name}Facade(final io.fd.vpp.jvpp.JVppRegistry registry, final io.fd.vpp.jvpp.JVpp jvpp) throws java.io.IOException {
111         super(jvpp, registry, new java.util.HashMap<>());
112         java.util.Objects.requireNonNull(registry, "JVppRegistry should not be null");
113         registry.register(jvpp, new FutureJVpp${plugin_name}FacadeCallback(getRequests(), eventRegistry));
114     }
115
116     @Override
117     public $plugin_package.notification.${plugin_name}EventRegistry getEventRegistry() {
118         return eventRegistry;
119     }
120
121 $methods
122 }
123 ''')
124
125
126 def _generate_future_jvpp_facade_methods(model):
127     methods = []
128     for msg in model.messages:
129         if is_control_ping(msg) or is_control_ping_reply(msg):
130             # Skip control_ping managed by jvpp registry.
131             continue
132         template = None
133         if is_request(msg):
134             template = _FUTURE_JVPP_FACADE_REQUEST_TEMPLATE
135         elif is_dump(msg):
136             template = _FUTURE_JVPP_FACADE_DUMP_TEMPLATE
137         else:
138             continue
139
140         methods.append(template.substitute(
141             plugin_package=model.plugin_package,
142             method_name=msg.java_name_lower,
143             reply_name=msg.reply_java,
144             request_name=msg.java_name_upper
145         ))
146     return "".join(methods)
147
148 _FUTURE_JVPP_FACADE_REQUEST_TEMPLATE = Template('''
149     @Override
150     public java.util.concurrent.CompletionStage<${plugin_package}.dto.${reply_name}> ${method_name}(${plugin_package}.dto.${request_name} request) {
151         return send(request);
152     }
153 ''')
154
155 _FUTURE_JVPP_FACADE_DUMP_TEMPLATE = Template('''
156     @Override
157     public java.util.concurrent.CompletionStage<${plugin_package}.dto.${reply_name}ReplyDump> ${method_name}(${plugin_package}.dto.${request_name} request) {
158         return send(request, new ${plugin_package}.dto.${reply_name}ReplyDump());
159     }
160 ''')
161
162
163 def _generate_future_jvpp_callback(work_dir, model):
164     with open("%s/FutureJVpp%sFacadeCallback.java" % (work_dir, model.plugin_java_name), "w") as f:
165         f.write(_FUTURE_JVPP_CALLBACK_TEMPLATE.substitute(
166             plugin_package=model.plugin_package,
167             json_filename=model.json_api_files,
168             plugin_name=model.plugin_java_name,
169             methods=_generate_future_jvpp_callback_methods(model)
170         ))
171
172 _FUTURE_JVPP_CALLBACK_TEMPLATE = Template("""
173 package $plugin_package.future;
174
175 /**
176  * <p>Async facade callback setting values to future objects
177  * <br>It was generated by jvpp_future_facade_gen.py based on $json_filename.
178  */
179 public final class FutureJVpp${plugin_name}FacadeCallback implements $plugin_package.callback.JVpp${plugin_name}GlobalCallback {
180
181     private final java.util.Map<java.lang.Integer, java.util.concurrent.CompletableFuture<? extends io.fd.vpp.jvpp.dto.JVppReply<?>>> requests;
182     private final $plugin_package.notification.Global${plugin_name}EventCallback notificationCallback;
183     private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(FutureJVpp${plugin_name}FacadeCallback.class.getName());
184
185     public FutureJVpp${plugin_name}FacadeCallback(
186         final java.util.Map<java.lang.Integer, java.util.concurrent.CompletableFuture<? extends io.fd.vpp.jvpp.dto.JVppReply<?>>> requestMap,
187         final $plugin_package.notification.Global${plugin_name}EventCallback notificationCallback) {
188         this.requests = requestMap;
189         this.notificationCallback = notificationCallback;
190     }
191
192     @Override
193     @SuppressWarnings("unchecked")
194     public void onError(io.fd.vpp.jvpp.VppCallbackException reply) {
195         final java.util.concurrent.CompletableFuture<io.fd.vpp.jvpp.dto.JVppReply<?>> completableFuture;
196
197         synchronized(requests) {
198             completableFuture = (java.util.concurrent.CompletableFuture<io.fd.vpp.jvpp.dto.JVppReply<?>>) requests.get(reply.getCtxId());
199         }
200
201         if(completableFuture != null) {
202             completableFuture.completeExceptionally(reply);
203
204             synchronized(requests) {
205                 requests.remove(reply.getCtxId());
206             }
207         }
208     }
209
210     @Override
211     @SuppressWarnings("unchecked")
212     public void onControlPingReply(final io.fd.vpp.jvpp.dto.ControlPingReply reply) {
213         java.util.concurrent.CompletableFuture<io.fd.vpp.jvpp.dto.JVppReply<?>> completableFuture;
214
215         final int replyId = reply.context;
216         synchronized(requests) {
217             completableFuture = (java.util.concurrent.CompletableFuture<io.fd.vpp.jvpp.dto.JVppReply<?>>) requests.get(replyId);
218
219             if(completableFuture != null) {
220                 // Finish dump call
221                 if (completableFuture instanceof io.fd.vpp.jvpp.future.AbstractFutureJVppInvoker.CompletableDumpFuture) {
222                     completableFuture.complete(((io.fd.vpp.jvpp.future.AbstractFutureJVppInvoker.CompletableDumpFuture) completableFuture).getReplyDump());
223                     // Remove future mapped to dump call context id
224                     requests.remove(((io.fd.vpp.jvpp.future.AbstractFutureJVppInvoker.CompletableDumpFuture) completableFuture).getContextId());
225                 } else {
226                     // reply to regular control ping, complete the future
227                     completableFuture.complete(reply);
228                 }
229                 requests.remove(replyId);
230             } else {
231                 // future not yet created by writer, create new future, complete it and put to map under ping id
232                 completableFuture = new java.util.concurrent.CompletableFuture<>();
233                 completableFuture.complete(reply);
234                 requests.put(replyId, completableFuture);
235             }
236         }
237     }
238
239 $methods
240 }
241 """)
242
243
244 def _generate_future_jvpp_callback_methods(model):
245     methods = []
246     for msg in model.messages:
247         if is_control_ping(msg) or is_control_ping_reply(msg):
248             # Skip control_ping managed by jvpp registry.
249             continue
250         if is_dump(msg) or is_request(msg):
251             continue
252
253         # Generate callbacks for all messages except for dumps and requests (handled by vpp, not client).
254         template = None
255         request_dto = None
256         if is_details(msg):
257             template = _FUTURE_JVPP_FACADE_DETAILS_CALLBACK_TEMPLATE
258             request_dto = msg.request_java
259         elif is_reply(msg):
260             template = _FUTURE_JVPP_FACADE_REPLY_CALLBACK_TEMPLATE
261             request_dto = msg.request_java
262         elif is_event(msg):
263             template = _FUTURE_JVPP_FACADE_EVENT_CALLBACK_TEMPLATE
264         else:
265             raise TypeError("Unknown message type %s", msg)
266
267         methods.append(template.substitute(
268             plugin_package=model.plugin_package,
269             callback_dto=msg.java_name_upper,
270             request_dto=request_dto,
271             callback_dto_field=msg.java_name_lower,
272         ))
273     return "".join(methods)
274
275
276 _FUTURE_JVPP_FACADE_DETAILS_CALLBACK_TEMPLATE = Template("""
277     @Override
278     @SuppressWarnings("unchecked")
279     public void on$callback_dto(final $plugin_package.dto.$callback_dto reply) {
280         io.fd.vpp.jvpp.future.AbstractFutureJVppInvoker.CompletableDumpFuture<$plugin_package.dto.${callback_dto}ReplyDump> completableFuture;
281         final int replyId = reply.context;
282         if (LOG.isLoggable(java.util.logging.Level.FINE)) {
283             LOG.fine(java.lang.String.format("Received $callback_dto event message: %s", reply));
284         }
285         synchronized(requests) {
286             completableFuture = (io.fd.vpp.jvpp.future.AbstractFutureJVppInvoker.CompletableDumpFuture<$plugin_package.dto.${callback_dto}ReplyDump>) requests.get(replyId);
287
288             if(completableFuture == null) {
289                 // reply received before writer created future,
290                 // create new future, and put into map to notify sender that reply is already received,
291                 // following details replies will add information to this future
292                 completableFuture = new io.fd.vpp.jvpp.future.AbstractFutureJVppInvoker.CompletableDumpFuture<>(replyId,
293                     new $plugin_package.dto.${callback_dto}ReplyDump());
294                 requests.put(replyId, completableFuture);
295             }
296             completableFuture.getReplyDump().$callback_dto_field.add(reply);
297         }
298     }
299 """)
300
301 _FUTURE_JVPP_FACADE_REPLY_CALLBACK_TEMPLATE = Template("""
302     @Override
303     @SuppressWarnings("unchecked")
304     public void on$callback_dto(final $plugin_package.dto.$callback_dto reply) {
305         java.util.concurrent.CompletableFuture<io.fd.vpp.jvpp.dto.JVppReply<$plugin_package.dto.$request_dto>> completableFuture;
306         final int replyId = reply.context;
307         if (LOG.isLoggable(java.util.logging.Level.FINE)) {
308             LOG.fine(java.lang.String.format("Received $callback_dto event message: %s", reply));
309         }
310         synchronized(requests) {
311             completableFuture =
312             (java.util.concurrent.CompletableFuture<io.fd.vpp.jvpp.dto.JVppReply<$plugin_package.dto.$request_dto>>) requests.get(replyId);
313
314             if(completableFuture != null) {
315                 // received reply on request, complete future created by sender and remove it from map
316                 completableFuture.complete(reply);
317                 requests.remove(replyId);
318             } else {
319                 // reply received before writer created future,
320                 // create new future, complete it and put into map to
321                 // notify sender that reply is already received
322                 completableFuture = new  java.util.concurrent.CompletableFuture<>();
323                 completableFuture.complete(reply);
324                 requests.put(replyId, completableFuture);
325             }
326         }
327     }
328 """)
329
330 _FUTURE_JVPP_FACADE_EVENT_CALLBACK_TEMPLATE = Template("""
331     @Override
332     public void on$callback_dto($plugin_package.dto.$callback_dto notification) {
333         if (LOG.isLoggable(java.util.logging.Level.FINE)) {
334             LOG.fine(java.lang.String.format("Received $callback_dto event message: %s", notification));
335         }
336         notificationCallback.on$callback_dto(notification);
337     }
338 """)