jvpp: adding callbacks for all messages (VPP-914)
[vpp.git] / src / vpp-api / java / jvpp / gen / jvppgen / jvpp_future_facade_gen.py
1 #!/usr/bin/env python
2 #
3 # Copyright (c) 2016 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
16 import os
17 from string import Template
18
19 import dto_gen
20 import util
21
22 jvpp_facade_callback_template = Template("""
23 package $plugin_package.$future_package;
24
25 /**
26  * <p>Async facade callback setting values to future objects
27  * <br>It was generated by jvpp_future_facade_gen.py based on $inputfile
28  * <br>(python representation of api file generated by vppapigen).
29  */
30 public final class FutureJVpp${plugin_name}FacadeCallback implements $plugin_package.$callback_package.JVpp${plugin_name}GlobalCallback {
31
32     private final java.util.Map<java.lang.Integer, java.util.concurrent.CompletableFuture<? extends $base_package.$dto_package.JVppReply<?>>> requests;
33     private final $plugin_package.$notification_package.Global${plugin_name}EventCallback notificationCallback;
34     private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(FutureJVpp${plugin_name}FacadeCallback.class.getName());
35
36     public FutureJVpp${plugin_name}FacadeCallback(
37         final java.util.Map<java.lang.Integer, java.util.concurrent.CompletableFuture<? extends $base_package.$dto_package.JVppReply<?>>> requestMap,
38         final $plugin_package.$notification_package.Global${plugin_name}EventCallback notificationCallback) {
39         this.requests = requestMap;
40         this.notificationCallback = notificationCallback;
41     }
42
43     @Override
44     @SuppressWarnings("unchecked")
45     public void onError($base_package.VppCallbackException reply) {
46         final java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply<?>> completableFuture;
47
48         synchronized(requests) {
49             completableFuture = (java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply<?>>) requests.get(reply.getCtxId());
50         }
51
52         if(completableFuture != null) {
53             completableFuture.completeExceptionally(reply);
54
55             synchronized(requests) {
56                 requests.remove(reply.getCtxId());
57             }
58         }
59     }
60
61     @Override
62     @SuppressWarnings("unchecked")
63     public void onControlPingReply(final $base_package.$dto_package.ControlPingReply reply) {
64         final java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply<?>> completableFuture;
65
66         final int replyId = reply.context;
67         synchronized(requests) {
68             completableFuture = (java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply<?>>) requests.get(replyId);
69         }
70
71         if(completableFuture != null) {
72             // Finish dump call
73             if (completableFuture instanceof $base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture) {
74                 completableFuture.complete((($base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture) completableFuture).getReplyDump());
75                 // Remove future mapped to dump call context id
76                 synchronized(requests) {
77                     requests.remove((($base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture) completableFuture).getContextId());
78                 }
79             } else {
80                 completableFuture.complete(reply);
81             }
82             synchronized(requests) {
83                 requests.remove(replyId);
84             }
85         }
86     }
87
88 $methods
89 }
90 """)
91
92 jvpp_facade_callback_method_template = Template("""
93     @Override
94     @SuppressWarnings("unchecked")
95     public void on$callback_dto(final $plugin_package.$dto_package.$callback_dto reply) {
96         final java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply<?>> completableFuture;
97         final int replyId = reply.context;
98         if (LOG.isLoggable(java.util.logging.Level.FINE)) {
99             LOG.fine(String.format("Received $callback_dto event message: %s", reply));
100         }
101         synchronized(requests) {
102             completableFuture = (java.util.concurrent.CompletableFuture<$base_package.$dto_package.JVppReply<?>>) requests.get(replyId);
103         }
104
105         if(completableFuture != null) {
106             completableFuture.complete(reply);
107
108             synchronized(requests) {
109                 requests.remove(replyId);
110             }
111         }
112     }
113 """)
114
115 jvpp_facade_callback_notification_method_template = Template("""
116     @Override
117     public void on$callback_dto($plugin_package.$dto_package.$callback_dto notification) {
118         if (LOG.isLoggable(java.util.logging.Level.FINE)) {
119             LOG.fine(String.format("Received $callback_dto event message: %s", notification));
120         }
121         notificationCallback.on$callback_dto(notification);
122     }
123 """)
124
125 jvpp_facade_details_callback_method_template = Template("""
126     @Override
127     @SuppressWarnings("unchecked")
128     public void on$callback_dto(final $plugin_package.$dto_package.$callback_dto reply) {
129         final $base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture<$plugin_package.$dto_package.$callback_dto_reply_dump> completableFuture;
130         final int replyId = reply.context;
131         if (LOG.isLoggable(java.util.logging.Level.FINE)) {
132             LOG.fine(String.format("Received $callback_dto event message: %s", reply));
133         }
134         synchronized(requests) {
135             completableFuture = ($base_package.$future_package.AbstractFutureJVppInvoker.CompletableDumpFuture<$plugin_package.$dto_package.$callback_dto_reply_dump>) requests.get(replyId);
136         }
137
138         if(completableFuture != null) {
139             completableFuture.getReplyDump().$callback_dto_field.add(reply);
140         }
141     }
142 """)
143
144
145 def generate_jvpp(func_list, base_package, plugin_package, plugin_name, dto_package, callback_package, notification_package, future_facade_package, inputfile):
146     """ Generates JVpp interface and JNI implementation """
147     print "Generating JVpp future facade"
148
149     if not os.path.exists(future_facade_package):
150         os.mkdir(future_facade_package)
151
152     methods = []
153     methods_impl = []
154     callbacks = []
155     for func in func_list:
156         camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name'])
157
158         if util.is_ignored(func['name']) or util.is_control_ping(camel_case_name_with_suffix):
159             continue
160
161         if not util.is_reply(camel_case_name_with_suffix) and not util.is_notification(func['name']):
162             continue
163
164         camel_case_method_name = util.underscore_to_camelcase(func['name'])
165
166         if not util.is_notification(func["name"]):
167             camel_case_request_method_name = util.remove_reply_suffix(util.underscore_to_camelcase(func['name']))
168             if util.is_details(camel_case_name_with_suffix):
169                 camel_case_reply_name = get_standard_dump_reply_name(util.underscore_to_camelcase_upper(func['name']),
170                                                                      func['name'])
171                 callbacks.append(jvpp_facade_details_callback_method_template.substitute(base_package=base_package,
172                                                                                          plugin_package=plugin_package,
173                                                                                          dto_package=dto_package,
174                                                                                          callback_dto=camel_case_name_with_suffix,
175                                                                                          callback_dto_field=camel_case_method_name,
176                                                                                          callback_dto_reply_dump=camel_case_reply_name + dto_gen.dump_dto_suffix,
177                                                                                          future_package=future_facade_package))
178
179                 methods.append(future_jvpp_method_template.substitute(plugin_package=plugin_package,
180                                                                       dto_package=dto_package,
181                                                                       method_name=camel_case_request_method_name +
182                                                                                   util.underscore_to_camelcase_upper(util.dump_suffix),
183                                                                       reply_name=camel_case_reply_name + dto_gen.dump_dto_suffix,
184                                                                       request_name=util.remove_reply_suffix(camel_case_reply_name) +
185                                                                                    util.underscore_to_camelcase_upper(util.dump_suffix)))
186                 methods_impl.append(future_jvpp_dump_method_impl_template.substitute(plugin_package=plugin_package,
187                                                                                      dto_package=dto_package,
188                                                                                      method_name=camel_case_request_method_name +
189                                                                                                  util.underscore_to_camelcase_upper(util.dump_suffix),
190                                                                                      reply_name=camel_case_reply_name + dto_gen.dump_dto_suffix,
191                                                                                      request_name=util.remove_reply_suffix(camel_case_reply_name) +
192                                                                                                   util.underscore_to_camelcase_upper(util.dump_suffix)))
193             else:
194                 request_name = util.underscore_to_camelcase_upper(util.unconventional_naming_rep_req[func['name']]) \
195                     if func['name'] in util.unconventional_naming_rep_req else util.remove_reply_suffix(camel_case_name_with_suffix)
196
197                 methods.append(future_jvpp_method_template.substitute(plugin_package=plugin_package,
198                                                                       dto_package=dto_package,
199                                                                       method_name=camel_case_request_method_name,
200                                                                       reply_name=camel_case_name_with_suffix,
201                                                                       request_name=request_name))
202                 methods_impl.append(future_jvpp_method_impl_template.substitute(plugin_package=plugin_package,
203                                                                                 dto_package=dto_package,
204                                                                                 method_name=camel_case_request_method_name,
205                                                                                 reply_name=camel_case_name_with_suffix,
206                                                                                 request_name=request_name))
207
208                 callbacks.append(jvpp_facade_callback_method_template.substitute(base_package=base_package,
209                                                                                  plugin_package=plugin_package,
210                                                                                  dto_package=dto_package,
211                                                                                  callback_dto=camel_case_name_with_suffix))
212
213         if util.is_notification(func["name"]):
214             callbacks.append(jvpp_facade_callback_notification_method_template.substitute(plugin_package=plugin_package,
215                                                                                           dto_package=dto_package,
216                                                                                           callback_dto=camel_case_name_with_suffix))
217
218     jvpp_file = open(os.path.join(future_facade_package, "FutureJVpp%sFacadeCallback.java" % plugin_name), 'w')
219     jvpp_file.write(jvpp_facade_callback_template.substitute(inputfile=inputfile,
220                                                              base_package=base_package,
221                                                              plugin_package=plugin_package,
222                                                              plugin_name=plugin_name,
223                                                              dto_package=dto_package,
224                                                              notification_package=notification_package,
225                                                              callback_package=callback_package,
226                                                              methods="".join(callbacks),
227                                                              future_package=future_facade_package))
228     jvpp_file.flush()
229     jvpp_file.close()
230
231     jvpp_file = open(os.path.join(future_facade_package, "FutureJVpp%s.java" % plugin_name), 'w')
232     jvpp_file.write(future_jvpp_template.substitute(inputfile=inputfile,
233                                                     base_package=base_package,
234                                                     plugin_package=plugin_package,
235                                                     plugin_name=plugin_name,
236                                                     notification_package=notification_package,
237                                                     methods="".join(methods),
238                                                     future_package=future_facade_package))
239     jvpp_file.flush()
240     jvpp_file.close()
241
242     jvpp_file = open(os.path.join(future_facade_package, "FutureJVpp%sFacade.java" % plugin_name), 'w')
243     jvpp_file.write(future_jvpp_facade_template.substitute(inputfile=inputfile,
244                                                            base_package=base_package,
245                                                            plugin_package=plugin_package,
246                                                            plugin_name=plugin_name,
247                                                            dto_package=dto_package,
248                                                            notification_package=notification_package,
249                                                            methods="".join(methods_impl),
250                                                            future_package=future_facade_package))
251     jvpp_file.flush()
252     jvpp_file.close()
253
254
255 future_jvpp_template = Template('''
256 package $plugin_package.$future_package;
257
258 /**
259  * <p>Async facade extension adding specific methods for each request invocation
260  * <br>It was generated by jvpp_future_facade_gen.py based on $inputfile
261  * <br>(python representation of api file generated by vppapigen).
262  */
263 public interface FutureJVpp${plugin_name} extends $base_package.$future_package.FutureJVppInvoker {
264 $methods
265
266     @Override
267     public $plugin_package.$notification_package.${plugin_name}EventRegistry getEventRegistry();
268
269 }
270 ''')
271
272 future_jvpp_method_template = Template('''
273     java.util.concurrent.CompletionStage<$plugin_package.$dto_package.$reply_name> $method_name($plugin_package.$dto_package.$request_name request);
274 ''')
275
276
277 future_jvpp_facade_template = Template('''
278 package $plugin_package.$future_package;
279
280 /**
281  * <p>Implementation of FutureJVpp based on AbstractFutureJVppInvoker
282  * <br>It was generated by jvpp_future_facade_gen.py based on $inputfile
283  * <br>(python representation of api file generated by vppapigen).
284  */
285 public class FutureJVpp${plugin_name}Facade extends $base_package.$future_package.AbstractFutureJVppInvoker implements FutureJVpp${plugin_name} {
286
287     private final $plugin_package.$notification_package.${plugin_name}EventRegistryImpl eventRegistry = new $plugin_package.$notification_package.${plugin_name}EventRegistryImpl();
288
289     /**
290      * <p>Create FutureJVpp${plugin_name}Facade object for provided JVpp instance.
291      * Constructor internally creates FutureJVppFacadeCallback class for processing callbacks
292      * and then connects to provided JVpp instance
293      *
294      * @param jvpp provided $base_package.JVpp instance
295      *
296      * @throws java.io.IOException in case instance cannot connect to JVPP
297      */
298     public FutureJVpp${plugin_name}Facade(final $base_package.JVppRegistry registry, final $base_package.JVpp jvpp) throws java.io.IOException {
299         super(jvpp, registry, new java.util.HashMap<>());
300         java.util.Objects.requireNonNull(registry, "JVppRegistry should not be null");
301         registry.register(jvpp, new FutureJVpp${plugin_name}FacadeCallback(getRequests(), eventRegistry));
302     }
303
304     @Override
305     public $plugin_package.$notification_package.${plugin_name}EventRegistry getEventRegistry() {
306         return eventRegistry;
307     }
308
309 $methods
310 }
311 ''')
312
313 future_jvpp_method_impl_template = Template('''
314     @Override
315     public java.util.concurrent.CompletionStage<$plugin_package.$dto_package.$reply_name> $method_name($plugin_package.$dto_package.$request_name request) {
316         return send(request);
317     }
318 ''')
319
320 future_jvpp_dump_method_impl_template = Template('''
321     @Override
322     public java.util.concurrent.CompletionStage<$plugin_package.$dto_package.$reply_name> $method_name($plugin_package.$dto_package.$request_name request) {
323         return send(request, new $plugin_package.$dto_package.$reply_name());
324     }
325 ''')
326
327
328 # Returns request name or special one from unconventional_naming_rep_req map
329 def get_standard_dump_reply_name(camel_case_dto_name, func_name):
330     # FIXME this is a hotfix for sub-details callbacks
331     # FIXME also for L2FibTableEntry
332     # It's all because unclear mapping between
333     #  request -> reply,
334     #  dump -> reply, details,
335     #  notification_start -> reply, notifications
336
337     # vpe.api needs to be "standardized" so we can parse the information and create maps before generating java code
338     suffix = func_name.split("_")[-1]
339     return util.underscore_to_camelcase_upper(
340         util.unconventional_naming_rep_req[func_name]) + util.underscore_to_camelcase_upper(suffix) if func_name in util.unconventional_naming_rep_req \
341         else camel_case_dto_name