jvpp: adding callbacks for all messages (VPP-914)
[vpp.git] / src / vpp-api / java / jvpp / gen / jvppgen / jvpp_impl_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, util
17 from string import Template
18
19 jvpp_ifc_template = Template("""
20 package $plugin_package;
21
22 /**
23  * <p>Java representation of plugin's api file.
24  * <br>It was generated by jvpp_impl_gen.py based on $inputfile
25  * <br>(python representation of api file generated by vppapigen).
26  */
27 public interface JVpp${plugin_name} extends $base_package.JVpp {
28
29     /**
30      * Generic dispatch method for sending requests to VPP
31      *
32      * @throws io.fd.vpp.jvpp.VppInvocationException if send request had failed
33      */
34     int send($base_package.$dto_package.JVppRequest request) throws io.fd.vpp.jvpp.VppInvocationException;
35
36 $methods
37 }
38 """)
39
40 jvpp_impl_template = Template("""
41 package $plugin_package;
42
43 import java.io.IOException;
44 import java.io.InputStream;
45 import java.nio.file.Files;
46 import java.nio.file.Path;
47 import java.nio.file.StandardCopyOption;
48 import java.nio.file.attribute.PosixFilePermission;
49 import java.nio.file.attribute.PosixFilePermissions;
50 import java.util.Set;
51 import java.util.logging.Logger;
52 import java.util.logging.Level;
53 import $base_package.callback.JVppCallback;
54 import $base_package.VppConnection;
55 import $base_package.JVppRegistry;
56
57 /**
58  * <p>Default implementation of JVpp interface.
59  * <br>It was generated by jvpp_impl_gen.py based on $inputfile
60  * <br>(python representation of api file generated by vppapigen).
61  */
62 public final class JVpp${plugin_name}Impl implements $plugin_package.JVpp${plugin_name} {
63
64     private final static Logger LOG = Logger.getLogger(JVpp${plugin_name}Impl.class.getName());
65     private static final String LIBNAME = "libjvpp_${plugin_name_underscore}.so";
66
67     // FIXME using NativeLibraryLoader makes load fail could not find (WantInterfaceEventsReply).
68     static {
69         try {
70             loadLibrary();
71         } catch (Exception e) {
72             LOG.severe("Can't find jvpp jni library: " + LIBNAME);
73             throw new ExceptionInInitializerError(e);
74         }
75     }
76
77     private static void loadStream(final InputStream is) throws IOException {
78         final Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rwxr-x---");
79         final Path p = Files.createTempFile(LIBNAME, null, PosixFilePermissions.asFileAttribute(perms));
80         try {
81             Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING);
82
83             try {
84                 Runtime.getRuntime().load(p.toString());
85             } catch (UnsatisfiedLinkError e) {
86                 throw new IOException("Failed to load library " + p, e);
87             }
88         } finally {
89             try {
90                 Files.deleteIfExists(p);
91             } catch (IOException e) {
92             }
93         }
94     }
95
96     private static void loadLibrary() throws IOException {
97         try (final InputStream is = JVpp${plugin_name}Impl.class.getResourceAsStream('/' + LIBNAME)) {
98             if (is == null) {
99                 throw new IOException("Failed to open library resource " + LIBNAME);
100             }
101             loadStream(is);
102         }
103     }
104
105     private VppConnection connection;
106     private JVppRegistry registry;
107
108     private static native void init0(final JVppCallback callback, final long queueAddress, final int clientIndex);
109     @Override
110     public void init(final JVppRegistry registry, final JVppCallback callback, final long queueAddress, final int clientIndex) {
111         this.registry = java.util.Objects.requireNonNull(registry, "registry should not be null");
112         this.connection = java.util.Objects.requireNonNull(registry.getConnection(), "connection should not be null");
113         connection.checkActive();
114         init0(callback, queueAddress, clientIndex);
115     }
116
117     private static native void close0();
118     @Override
119     public void close() {
120         close0();
121     }
122
123     @Override
124     public int send($base_package.$dto_package.JVppRequest request) throws io.fd.vpp.jvpp.VppInvocationException {
125         return request.send(this);
126     }
127
128     @Override
129     public final int controlPing(final io.fd.vpp.jvpp.dto.ControlPing controlPing) throws io.fd.vpp.jvpp.VppInvocationException {
130         return registry.controlPing(JVpp${plugin_name}Impl.class);
131     }
132
133 $methods
134 }
135 """)
136
137 method_template = Template("""    int $name($plugin_package.$dto_package.$request request) throws io.fd.vpp.jvpp.VppInvocationException;""")
138 method_native_template = Template(
139     """    private static native int ${name}0($plugin_package.$dto_package.$request request);""")
140 method_impl_template = Template("""    public final int $name($plugin_package.$dto_package.$request request) throws io.fd.vpp.jvpp.VppInvocationException {
141         java.util.Objects.requireNonNull(request,"Null request object");
142         connection.checkActive();
143         if(LOG.isLoggable(Level.FINE)) {
144             LOG.fine(String.format("Sending $name event message: %s", request));
145         }
146         int result=${name}0(request);
147         if(result<0){
148             throw new io.fd.vpp.jvpp.VppInvocationException("${name}",result);
149         }
150         return result;
151     }
152 """)
153
154 no_arg_method_template = Template("""    int $name() throws io.fd.vpp.jvpp.VppInvocationException;""")
155 no_arg_method_native_template = Template("""    private static native int ${name}0() throws io.fd.vpp.jvpp.VppInvocationException;""")
156 no_arg_method_impl_template = Template("""    public final int $name() throws io.fd.vpp.jvpp.VppInvocationException {
157         connection.checkActive();
158         LOG.fine("Sending $name event message");
159         int result=${name}0();
160         if(result<0){
161             throw new io.fd.vpp.jvpp.VppInvocationException("${name}",result);
162         }
163         return result;
164     }
165 """)
166
167
168 def generate_jvpp(func_list, base_package, plugin_package, plugin_name_underscore, dto_package, inputfile):
169     """ Generates JVpp interface and JNI implementation """
170     print "Generating JVpp"
171     plugin_name = util.underscore_to_camelcase_upper(plugin_name_underscore)
172
173     methods = []
174     methods_impl = []
175     for func in func_list:
176
177         # Skip structures that are used only as notifications
178         if util.is_ignored(func['name']):
179             continue
180
181         camel_case_name = util.underscore_to_camelcase(func['name'])
182         camel_case_name_upper = util.underscore_to_camelcase_upper(func['name'])
183         if util.is_reply(camel_case_name):
184             continue
185
186         if len(func['args']) == 0:
187             methods.append(no_arg_method_template.substitute(name=camel_case_name))
188             methods_impl.append(no_arg_method_native_template.substitute(name=camel_case_name))
189             methods_impl.append(no_arg_method_impl_template.substitute(name=camel_case_name))
190         else:
191             methods.append(method_template.substitute(name=camel_case_name,
192                                                       request=camel_case_name_upper,
193                                                       plugin_package=plugin_package,
194                                                       dto_package=dto_package))
195             methods_impl.append(method_native_template.substitute(name=camel_case_name,
196                                                                   request=camel_case_name_upper,
197                                                                   plugin_package=plugin_package,
198                                                                   dto_package=dto_package))
199             methods_impl.append(method_impl_template.substitute(name=camel_case_name,
200                                                                 request=camel_case_name_upper,
201                                                                 plugin_package=plugin_package,
202                                                                 dto_package=dto_package))
203
204     jvpp_file = open("JVpp%s.java" % plugin_name, 'w')
205     jvpp_file.write(
206         jvpp_ifc_template.substitute(inputfile=inputfile,
207                                      methods="\n".join(methods),
208                                      base_package=base_package,
209                                      plugin_package=plugin_package,
210                                      plugin_name=plugin_name,
211                                      dto_package=dto_package))
212     jvpp_file.flush()
213     jvpp_file.close()
214
215     jvpp_file = open("JVpp%sImpl.java" % plugin_name, 'w')
216     jvpp_file.write(jvpp_impl_template.substitute(inputfile=inputfile,
217                                                   methods="\n".join(methods_impl),
218                                                   base_package=base_package,
219                                                   plugin_package=plugin_package,
220                                                   plugin_name=plugin_name,
221                                                   plugin_name_underscore=plugin_name_underscore,
222                                                   dto_package=dto_package))
223     jvpp_file.flush()
224     jvpp_file.close()