API: Use string type instead of u8.
[vpp.git] / extras / japi / java / jvpp / gen / jvppgen / jvpp_callback_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_dump, is_request, is_event, is_control_ping_reply
18
19
20 def generate_callback_facade(work_dir, model, logger):
21     """ Generates callback facade """
22     logger.debug("Generating JVpp callback facade for %s" % model.json_api_files)
23     _generate_ifc(work_dir, model),
24     _generate_impl(work_dir, model)
25     _generate_callback(work_dir, model)
26
27
28 def _generate_ifc(work_dir, model):
29     with open("%s/CallbackJVpp%s.java" % (work_dir, model.plugin_java_name), "w") as f:
30         f.write(_IFC_TEMPLATE.substitute(
31             plugin_package=model.plugin_package,
32             json_filename=model.json_api_files,
33             plugin_name=model.plugin_java_name,
34             methods=_generate_ifc_methods(model)
35         ))
36
37 _IFC_TEMPLATE = Template("""
38 package $plugin_package.callfacade;
39
40 /**
41  * <p>Callback Java API representation of $plugin_package plugin.
42  * <br>It was generated by jvpp_callback_facade_gen.py based on $json_filename.
43  */
44 public interface CallbackJVpp${plugin_name} extends io.fd.vpp.jvpp.notification.EventRegistryProvider, java.lang.AutoCloseable {
45
46     // TODO add send
47
48 $methods
49 }
50 """)
51
52
53 def _generate_ifc_methods(model):
54     plugin_package = model.plugin_package
55     methods = []
56     for msg in model.messages:
57         if is_control_ping(msg):
58             # Skip control ping managed by jvpp registry.
59             continue
60         if not (is_dump(msg) or is_request(msg)):
61             # Skip replies and messages that do not not have replies (e.g events/counters).
62             continue
63         template = _IFC_NO_ARG_METHOD_TEMPLATE
64         if msg.has_fields:
65             template = _IFC_METHOD_TEMPLATE
66         methods.append(template.substitute(
67             name=msg.java_name_lower,
68             plugin_package=plugin_package,
69             request=msg.java_name_upper,
70             reply=msg.reply_java
71         ))
72     return "\n".join(methods)
73
74 _IFC_NO_ARG_METHOD_TEMPLATE = Template(
75     """    void $name($plugin_package.callback.${reply}Callback callback) throws io.fd.vpp.jvpp.VppInvocationException;""")
76
77 _IFC_METHOD_TEMPLATE = Template(
78     """    void $name($plugin_package.dto.$request request, $plugin_package.callback.${reply}Callback callback) throws io.fd.vpp.jvpp.VppInvocationException;""")
79
80
81 def _generate_impl(work_dir, model):
82     with open("%s/CallbackJVpp%sFacade.java" % (work_dir, model.plugin_java_name), "w") as f:
83         f.write(_IMPL_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_impl_methods(model)
88         ))
89
90 _IMPL_TEMPLATE = Template("""
91 package $plugin_package.callfacade;
92
93 /**
94  * <p>Default implementation of Callback${plugin_name}JVpp interface.
95  * <br>It was generated by jvpp_callback_facade_gen.py based on $json_filename.
96  */
97 public final class CallbackJVpp${plugin_name}Facade implements CallbackJVpp${plugin_name} {
98
99     private final $plugin_package.JVpp${plugin_name} jvpp;
100     private final java.util.Map<Integer, io.fd.vpp.jvpp.callback.JVppCallback> callbacks;
101     private final $plugin_package.notification.${plugin_name}EventRegistryImpl eventRegistry = new $plugin_package.notification.${plugin_name}EventRegistryImpl();
102     /**
103      * <p>Create CallbackJVpp${plugin_name}Facade object for provided JVpp instance.
104      * Constructor internally creates CallbackJVppFacadeCallback class for processing callbacks
105      * and then connects to provided JVpp instance
106      *
107      * @param jvpp provided io.fd.vpp.jvpp.JVpp instance
108      *
109      * @throws java.io.IOException in case instance cannot connect to JVPP
110      */
111     public CallbackJVpp${plugin_name}Facade(final io.fd.vpp.jvpp.JVppRegistry registry, final $plugin_package.JVpp${plugin_name} jvpp) throws java.io.IOException {
112         this.jvpp = java.util.Objects.requireNonNull(jvpp,"jvpp is null");
113         this.callbacks = new java.util.HashMap<>();
114         java.util.Objects.requireNonNull(registry, "JVppRegistry should not be null");
115         registry.register(jvpp, new CallbackJVpp${plugin_name}FacadeCallback(this.callbacks, eventRegistry));
116     }
117
118     @Override
119     public $plugin_package.notification.${plugin_name}EventRegistry getEventRegistry() {
120         return eventRegistry;
121     }
122
123     @Override
124     public void close() throws Exception {
125         jvpp.close();
126     }
127
128     // TODO add send()
129
130 $methods
131 }
132 """)
133
134
135 def _generate_impl_methods(model):
136     plugin_package = model.plugin_package
137     methods = []
138     for msg in model.messages:
139         if is_control_ping(msg):
140             # Skip control ping managed by jvpp registry.
141             continue
142         if not (is_dump(msg) or is_request(msg)):
143             # Skip replies and messages that do not not have replies (e.g events/counters).
144             continue
145         template = _IMPL_NO_ARG_METHOD_TEMPLATE
146         if msg.has_fields:
147             template = _IMPL_METHOD_TEMPLATE
148         methods.append(template.substitute(
149             name=msg.java_name_lower,
150             plugin_package=plugin_package,
151             request=msg.java_name_upper,
152             reply=msg.reply_java
153         ))
154     return "\n".join(methods)
155
156 _IMPL_NO_ARG_METHOD_TEMPLATE = Template(
157     """    public final void $name($plugin_package.callback.${reply}Callback callback) throws io.fd.vpp.jvpp.VppInvocationException {
158         synchronized (callbacks) {
159             callbacks.put(jvpp.$name(), callback);
160         }
161     }
162 """)
163
164 _IMPL_METHOD_TEMPLATE = Template("""    public final void $name($plugin_package.dto.$request request, $plugin_package.callback.${reply}Callback callback) throws io.fd.vpp.jvpp.VppInvocationException {
165         synchronized (callbacks) {
166             callbacks.put(jvpp.$name(request), callback);
167         }
168     }
169 """)
170
171
172 def _generate_callback(work_dir, model):
173     with open("%s/CallbackJVpp%sFacadeCallback.java" % (work_dir, model.plugin_java_name), "w") as f:
174         f.write(_CALLBACK_TEMPLATE.substitute(
175             plugin_package=model.plugin_package,
176             json_filename=model.json_api_files,
177             plugin_name=model.plugin_java_name,
178             methods=_generate_callback_methods(model)
179         ))
180
181 _CALLBACK_TEMPLATE = Template("""
182 package $plugin_package.callfacade;
183
184 /**
185  * <p>Implementation of JVppGlobalCallback interface for Java Callback API.
186  * <br>It was generated by jvpp_callback_facade_gen.py based on $json_filename.
187  */
188 public final class CallbackJVpp${plugin_name}FacadeCallback implements $plugin_package.callback.JVpp${plugin_name}GlobalCallback {
189
190     private final java.util.Map<Integer, io.fd.vpp.jvpp.callback.JVppCallback> requests;
191     private final $plugin_package.notification.Global${plugin_name}EventCallback eventCallback;
192     private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(CallbackJVpp${plugin_name}FacadeCallback.class.getName());
193
194     public CallbackJVpp${plugin_name}FacadeCallback(final java.util.Map<Integer, io.fd.vpp.jvpp.callback.JVppCallback> requestMap,
195                                       final $plugin_package.notification.Global${plugin_name}EventCallback eventCallback) {
196         this.requests = requestMap;
197         this.eventCallback = eventCallback;
198     }
199
200     @Override
201     public void onError(io.fd.vpp.jvpp.VppCallbackException reply) {
202
203         io.fd.vpp.jvpp.callback.JVppCallback failedCall;
204         synchronized(requests) {
205             failedCall = requests.remove(reply.getCtxId());
206         }
207
208         if(failedCall != null) {
209             try {
210                 failedCall.onError(reply);
211             } catch(RuntimeException ex) {
212                 ex.addSuppressed(reply);
213                 LOG.log(java.util.logging.Level.WARNING, java.lang.String.format("Callback: %s failed while handling exception: %s", failedCall, reply), ex);
214             }
215         }
216     }
217
218     @Override
219     @SuppressWarnings("unchecked")
220     public void onControlPingReply(final io.fd.vpp.jvpp.dto.ControlPingReply reply) {
221
222         io.fd.vpp.jvpp.callback.ControlPingCallback callback;
223         final int replyId = reply.context;
224         synchronized(requests) {
225             callback = (io.fd.vpp.jvpp.callback.ControlPingCallback) requests.remove(replyId);
226         }
227
228         if(callback != null) {
229             callback.onControlPingReply(reply);
230         }
231     }
232
233 $methods
234 }
235 """)
236
237
238 def _generate_callback_methods(model):
239     plugin_package = model.plugin_package
240     methods = []
241     for msg in model.messages:
242         if is_dump(msg) or is_request(msg):
243             continue
244         if is_control_ping_reply(msg):
245             # Skip control ping managed by jvpp registry.
246             continue
247
248         # Generate callbacks for all messages except for dumps and requests (handled by vpp, not client).
249         template = _CALLBACK_METHOD_TEMPLATE
250         if is_event(msg):
251             template = _CALLBACK_EVENT_METHOD_TEMPLATE
252         msg_name = msg.java_name_upper
253         methods.append(template.substitute(
254             message=msg_name,
255             callback="%sCallback" % msg_name,
256             plugin_package=plugin_package
257         ))
258     return "\n".join(methods)
259
260 _CALLBACK_METHOD_TEMPLATE = Template("""
261     @Override
262     @SuppressWarnings("unchecked")
263     public void on${message}(final $plugin_package.dto.${message} reply) {
264
265         $plugin_package.callback.$callback callback;
266         final int replyId = reply.context;
267         if (LOG.isLoggable(java.util.logging.Level.FINE)) {
268             LOG.fine(java.lang.String.format("Received ${message} event message: %s", reply));
269         }
270         synchronized(requests) {
271             callback = ($plugin_package.callback.$callback) requests.remove(replyId);
272         }
273
274         if(callback != null) {
275             callback.on${message}(reply);
276         }
277     }
278 """)
279
280 _CALLBACK_EVENT_METHOD_TEMPLATE = Template("""
281     @Override
282     @SuppressWarnings("unchecked")
283     public void on${message}($plugin_package.dto.${message} notification) {
284         if (LOG.isLoggable(java.util.logging.Level.FINE)) {
285             LOG.fine(java.lang.String.format("Received ${message} event message: %s", notification));
286         }
287         eventCallback.on${message}(notification);
288     }
289 """)