c655933ddeab4e4b26cdc5045b118ff9a40f9906
[vpp.git] / src / vpp-api / java / jvpp / gen / jvppgen / types_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 util
20 import jni_gen
21 import dto_gen
22
23 type_template = Template("""
24 package $plugin_package.$type_package;
25
26 /**
27  * <p>This class represents $c_type_name type definition.
28  * <br>It was generated by types_gen.py based on $inputfile preparsed data:
29  * <pre>
30 $docs
31  * </pre>
32  */
33 public final class $java_type_name {
34 $fields
35 $methods
36 }
37 """)
38
39 field_template = Template("""    public $type $name;\n""")
40
41
42 def generate_type_fields(type_definition):
43     """
44     Generates fields for class representing typeonly definition
45     :param type_definition: python representation of typeonly definition
46     :return: string representing class fields
47     """
48     fields = ""
49     for t in zip(type_definition['types'], type_definition['args']):
50         field_name = util.underscore_to_camelcase(t[1])
51         fields += field_template.substitute(type=util.jni_2_java_type_mapping[t[0]],
52                                             name=field_name)
53     return fields
54
55 object_struct_setter_template = Template("""
56     {
57         jclass ${field_reference_name}Class = (*env)->FindClass(env, "${class_FQN}");
58         memset (&(mp->${c_name}), 0, sizeof (mp->${c_name}));
59         ${struct_initialization}
60     }
61 """)
62
63 object_array_struct_setter_template = Template("""
64     {
65         jclass ${field_reference_name}ArrayElementClass = (*env)->FindClass(env, "${class_FQN}");
66         if (${field_reference_name}) {
67             size_t _i;
68             jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name});
69             ${field_length_check}
70             for (_i = 0; _i < cnt; _i++) {
71                 jobject ${field_reference_name}ArrayElement = (*env)->GetObjectArrayElement(env, ${field_reference_name}, _i);
72                 memset (&(mp->${c_name}[_i]), 0, sizeof (mp->${c_name}[_i]));
73                 ${struct_initialization}
74             }
75         }
76     }
77 """)
78
79 object_dto_field_setter_template = Template("""
80     {
81         jclass ${field_reference_name}Class = (*env)->FindClass(env, "${class_FQN}");
82         jmethodID ${field_reference_name}Constructor = (*env)->GetMethodID(env, ${field_reference_name}Class, "<init>", "()V");
83         jobject ${field_reference_name} = (*env)->NewObject(env, ${field_reference_name}Class,  ${field_reference_name}Constructor);
84         ${type_initialization}
85         (*env)->SetObjectField(env, dto, ${field_reference_name}FieldId, ${field_reference_name});
86         (*env)->DeleteLocalRef(env, ${field_reference_name});
87     }
88 """)
89
90 object_array_dto_field_setter_template = Template("""
91     {
92         jclass ${field_reference_name}Class = (*env)->FindClass(env, "${class_FQN}");
93         jobjectArray ${field_reference_name} = (*env)->NewObjectArray(env, ${field_length}, ${field_reference_name}Class, 0);
94         jmethodID ${field_reference_name}Constructor = (*env)->GetMethodID(env, ${field_reference_name}Class, "<init>", "()V");
95         unsigned int _i;
96         for (_i = 0; _i < ${field_length}; _i++) {
97             jobject ${field_reference_name}ArrayElement = (*env)->NewObject(env, ${field_reference_name}Class,  ${field_reference_name}Constructor);
98             ${type_initialization}
99             (*env)->SetObjectArrayElement(env, ${field_reference_name}, _i, ${field_reference_name}ArrayElement);
100             (*env)->DeleteLocalRef(env, ${field_reference_name}ArrayElement);
101         }
102         (*env)->SetObjectField(env, dto, ${field_reference_name}FieldId, ${field_reference_name});
103         (*env)->DeleteLocalRef(env, ${field_reference_name});
104     }
105 """)
106
107
108 def generate_struct_initialization(type_def, c_name_prefix, object_name, indent):
109     struct_initialization = ""
110     # field identifiers
111     for t in zip(type_def['types'], type_def['args'], type_def['lengths']):
112         field_reference_name = "${c_name}" + util.underscore_to_camelcase_upper(t[1])
113         field_name = util.underscore_to_camelcase(t[1])
114         struct_initialization += jni_gen.jni_request_identifiers_for_type(field_type=t[0],
115                                                                           field_reference_name=field_reference_name,
116                                                                           field_name=field_name,
117                                                                           object_name=object_name)
118         struct_initialization += jni_gen.jni_request_binding_for_type(field_type=t[0], c_name=c_name_prefix + t[1],
119                                                                       field_reference_name=field_reference_name,
120                                                                       field_length=t[2][0],
121                                                                       is_variable_len_array=t[2][1])
122     return indent + struct_initialization.replace('\n', '\n' + indent)
123
124
125 def generate_type_setter(handler_name, type_def, c_name_prefix, object_name, indent):
126     type_initialization = ""
127     for t in zip(type_def['types'], type_def['args'], type_def['lengths']):
128         field_length = t[2][0]
129         is_variable_len_array = t[2][1]
130         length_field_type = None
131         if is_variable_len_array:
132             length_field_type = type_def['types'][type_def['args'].index(field_length)]
133         type_initialization += jni_gen.jni_reply_handler_for_type(handler_name=handler_name,
134                                                                   ref_name="${field_reference_name}",
135                                                                   field_type=t[0], c_name=c_name_prefix + t[1],
136                                                                   field_reference_name="${c_name}" + util.underscore_to_camelcase_upper(t[1]),
137                                                                   field_name=util.underscore_to_camelcase(t[1]),
138                                                                   field_length=field_length,
139                                                                   is_variable_len_array=is_variable_len_array,
140                                                                   length_field_type=length_field_type,
141                                                                   object_name=object_name)
142     return indent + type_initialization.replace('\n', '\n' + indent)
143
144
145 def generate_types(types_list, plugin_package, types_package, inputfile, logger):
146     """
147     Generates Java representation of custom types defined in api file.
148     """
149
150     if not types_list:
151         logger.debug("Skipping custom types generation (%s does not define custom types)." % inputfile)
152         return
153
154     logger.debug("Generating custom types for %s" % inputfile)
155
156     if not os.path.exists(types_package):
157         os.mkdir(types_package)
158
159     for type in types_list:
160         c_type_name = type['name']
161         java_type_name = util.underscore_to_camelcase_upper(type['name'])
162         dto_path = os.path.join(types_package, java_type_name + ".java")
163
164         fields = generate_type_fields(type)
165
166         dto_file = open(dto_path, 'w')
167         dto_file.write(type_template.substitute(plugin_package=plugin_package,
168                                                 type_package=types_package,
169                                                 c_type_name=c_type_name,
170                                                 inputfile=inputfile,
171                                                 docs=util.api_message_to_javadoc(type),
172                                                 java_type_name=java_type_name,
173                                                 fields=fields,
174                                                 methods=dto_gen.generate_dto_base_methods(java_type_name, type)
175                                                 ))
176
177         # update type mappings:
178         # todo fix vpe.api to use type_name instead of vl_api_type_name_t
179         type_name = "vl_api_" + c_type_name + "_t"
180         java_fqn = "%s.%s.%s" % (plugin_package, types_package, java_type_name)
181         util.vpp_2_jni_type_mapping[type_name] = "jobject"
182         util.vpp_2_jni_type_mapping[type_name + "[]"] = "jobjectArray"
183         util.jni_2_java_type_mapping[type_name] = java_fqn
184         util.jni_2_java_type_mapping[type_name + "[]"] = java_fqn + "[]"
185         jni_name = java_fqn.replace('.', "/")
186         jni_signature = "L" + jni_name + ";"
187         util.jni_2_signature_mapping[type_name] = "L" + jni_name + ";"
188         util.jni_2_signature_mapping[type_name + "[]"] = "[" + jni_signature
189         util.jni_field_accessors[type_name] = "ObjectField"
190         util.jni_field_accessors[type_name + "[]"] = "ObjectField"
191
192         jni_gen.struct_setter_templates[type_name] = Template(
193                 object_struct_setter_template.substitute(
194                         c_name="${c_name}",
195                         field_reference_name="${field_reference_name}",
196                         class_FQN=jni_name,
197                         struct_initialization=generate_struct_initialization(type, "${c_name}.",
198                                                                            "${field_reference_name}", ' ' * 4))
199         )
200
201         jni_gen.struct_setter_templates[type_name+ "[]"] = Template(
202                 object_array_struct_setter_template.substitute(
203                         c_name="${c_name}",
204                         field_reference_name="${field_reference_name}",
205                         field_length_check="${field_length_check}",
206                         class_FQN=jni_name,
207                         struct_initialization=generate_struct_initialization(type, "${c_name}[_i].",
208                                                                            "${field_reference_name}ArrayElement", ' ' * 8))
209         )
210
211         jni_gen.dto_field_setter_templates[type_name] = Template(
212                 object_dto_field_setter_template.substitute(
213                         field_reference_name="${field_reference_name}",
214                         field_length="${field_length}",
215                         class_FQN=jni_name,
216                         type_initialization=generate_type_setter(c_type_name, type, "${c_name}.",
217                                                                  "${field_reference_name}", ' ' * 4))
218         )
219
220         jni_gen.dto_field_setter_templates[type_name + "[]"] = Template(
221                 object_array_dto_field_setter_template.substitute(
222                         field_reference_name="${field_reference_name}",
223                         field_length="${field_length}",
224                         class_FQN=jni_name,
225                         type_initialization=generate_type_setter(c_type_name, type, "${c_name}[_i].",
226                                                                  "${field_reference_name}ArrayElement", ' ' * 8))
227         )
228
229         dto_file.flush()
230         dto_file.close()
231