summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarek Gradzki <mgradzki@cisco.com>2018-06-20 14:49:39 +0200
committerOle Trøan <otroan@employees.org>2018-06-22 09:27:47 +0000
commit3e2d57d8773e1d03577048f497dc7ed567fd9344 (patch)
tree405258dffbc11e9c29ca10fc8c734ec311a374b4
parent9679c81b64a5da48932ec0b6aebfb473d3e0410b (diff)
jvpp: add support for enums (VPP-1153)
Change-Id: I2a1b946a71419e1fb3c5d70567c54a6a7d841f10 Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
-rwxr-xr-xsrc/vpp-api/java/jvpp/gen/jvpp_gen.py2
-rwxr-xr-xsrc/vpp-api/java/jvpp/gen/jvppgen/enums_gen.py74
-rwxr-xr-xsrc/vpp-api/java/jvpp/gen/jvppgen/jni_common_gen.py66
-rwxr-xr-xsrc/vpp-api/java/jvpp/gen/jvppgen/jni_type_handlers_gen.py52
-rwxr-xr-xsrc/vpp-api/java/jvpp/gen/jvppgen/jvpp_model.py54
5 files changed, 244 insertions, 4 deletions
diff --git a/src/vpp-api/java/jvpp/gen/jvpp_gen.py b/src/vpp-api/java/jvpp/gen/jvpp_gen.py
index a58c5809a6d..5b8c7fda27c 100755
--- a/src/vpp-api/java/jvpp/gen/jvpp_gen.py
+++ b/src/vpp-api/java/jvpp/gen/jvpp_gen.py
@@ -19,6 +19,7 @@ import os
import sys
from jvppgen.types_gen import generate_types
+from jvppgen.enums_gen import generate_enums
from jvppgen.dto_gen import generate_dtos
from jvppgen.jvpp_ifc_gen import generate_java_ifc
from jvppgen.jvpp_impl_gen import generate_java_impl
@@ -33,6 +34,7 @@ from jvppgen.jvpp_model import JVppModel
def generate_jvpp(root_dir, model, logger):
base_dir = "%s/target/%s" % (root_dir, model.plugin_package.replace(".", "/"))
generate_types(_work_dir(base_dir, "types"), model, logger)
+ generate_enums(_work_dir(base_dir, "types"), model, logger)
generate_dtos(_work_dir(base_dir, "dto"), model, logger)
generate_java_ifc(_work_dir(base_dir), model, logger)
generate_java_impl(_work_dir(base_dir), model, logger)
diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/enums_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/enums_gen.py
new file mode 100755
index 00000000000..8ba96558428
--- /dev/null
+++ b/src/vpp-api/java/jvpp/gen/jvppgen/enums_gen.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python2
+#
+# Copyright (c) 2016,2018 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+from string import Template
+
+from jvpp_model import Enum
+
+
+def generate_enums(work_dir, model, logger):
+ logger.debug("Generating enums for %s " % model.json_api_files)
+
+ for t in model.types:
+ if not isinstance(t, Enum):
+ continue
+ logger.debug("Generating DTO for enum %s", t)
+ type_class_name = t.java_name
+ type_class = _ENUM_TEMPLATE.substitute(
+ plugin_package=model.plugin_package,
+ c_type_name=t.name,
+ json_filename=model.json_api_files,
+ json_definition=t.doc,
+ java_enum_name=type_class_name,
+ constants=_generate_constants(t.constants),
+ value_type=t.value.type.java_name
+ )
+ with open("%s/%s.java" % (work_dir, type_class_name), "w") as f:
+ f.write(type_class)
+
+_ENUM_TEMPLATE = Template("""
+package $plugin_package.types;
+
+/**
+ * <p>This class represents $c_type_name enum definition.
+ * <br>It was generated by enums_gen.py based on $json_filename:
+ * <pre>
+$json_definition
+ * </pre>
+ */
+public enum $java_enum_name {
+$constants;
+
+ public final $value_type value;
+
+ $java_enum_name(final $value_type value) {
+ this.value = value;
+ }
+
+ public static $java_enum_name forValue(final $value_type value) {
+ for ($java_enum_name enumeration : $java_enum_name.values()) {
+ if (value == enumeration.value) {
+ return enumeration;
+ }
+ }
+ return null;
+ }
+}
+""")
+
+
+def _generate_constants(constants):
+ return ",\n".join(_CONSTANT_TEMPLATE.substitute(name=c['name'], value=c['value']) for c in constants)
+
+_CONSTANT_TEMPLATE = Template(""" $name($value)""")
diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/jni_common_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/jni_common_gen.py
index 3b9969c36e0..742c1736e22 100755
--- a/src/vpp-api/java/jvpp/gen/jvppgen/jni_common_gen.py
+++ b/src/vpp-api/java/jvpp/gen/jvppgen/jni_common_gen.py
@@ -15,7 +15,7 @@
#
from string import Template
-from jvpp_model import is_array, is_retval, Class
+from jvpp_model import is_array, is_retval, Class, Enum
def generate_j2c_identifiers(element, class_ref_name, object_ref_name):
@@ -53,7 +53,7 @@ def generate_j2c_swap(element, struct_ref_name):
def _generate_j2c_array_swap(field, struct_ref_name):
# TODO(VPP-1186): move the logic to JNI generators
base_type = field.type.base_type
- if isinstance(base_type, Class):
+ if isinstance(base_type, Class) or isinstance(base_type, Enum):
return _generate_j2c_object_array_swap(field, struct_ref_name)
elif base_type.is_swap_needed:
return _generate_j2c_primitive_type_array_swap(field, struct_ref_name)
@@ -183,6 +183,8 @@ def _generate_c2j_array_swap(msg_java_name, field, object_ref_name, struct_ref_n
base_type = field.type.base_type
if isinstance(base_type, Class):
return _generate_c2j_class_array_swap(msg_java_name, field, object_ref_name, struct_ref_name)
+ elif isinstance(base_type, Enum):
+ return _generate_c2j_enum_array_swap(msg_java_name, field, object_ref_name, struct_ref_name)
elif base_type.is_swap_needed:
return _generate_c2j_primitive_type_array_swap(msg_java_name, field, object_ref_name, struct_ref_name)
else:
@@ -222,6 +224,40 @@ _C2J_CLASS_ARRAY_SWAP_TEMPLATE = Template("""
""")
+def _generate_c2j_enum_array_swap(msg_java_name, field, object_ref_name, struct_ref_name):
+ field_type = field.type
+ base_type = field_type.base_type
+ return _C2J_ENUM_ARRAY_SWAP_TEMPLATE.substitute(
+ field_reference_name=field.java_name,
+ class_ref_name=msg_java_name,
+ jni_signature=field_type.jni_signature,
+ jni_name=base_type.jni_name,
+ field_length=_generate_array_length(field, struct_ref_name),
+ net_to_host_function=field_type.net_to_host_function,
+ jni_signature_enum_value=base_type.value.type.jni_signature,
+ struct_ref_name=struct_ref_name,
+ object_ref_name=object_ref_name,
+ c_name=field.name
+ )
+
+_C2J_ENUM_ARRAY_SWAP_TEMPLATE = Template("""
+ jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${field_reference_name}", "${jni_signature}");
+ {
+ jclass ${field_reference_name}Class = (*env)->FindClass(env, "${jni_name}");
+ jobjectArray ${field_reference_name} = (*env)->NewObjectArray(env, ${field_length}, ${field_reference_name}Class, 0);
+ jmethodID ${field_reference_name}Constructor = (*env)->GetStaticMethodID(env, ${field_reference_name}Class, "forValue", "(${jni_signature_enum_value})${jni_signature}");
+ unsigned int _i;
+ for (_i = 0; _i < ${field_length}; _i++) {
+ jobject ${field_reference_name}ArrayElement = (*env)->CallStaticObjectMethod(env, ${field_reference_name}Class, ${field_reference_name}Constructor, ${net_to_host_function}(${struct_ref_name}->${c_name}[_i]));
+ (*env)->SetObjectArrayElement(env, ${field_reference_name}, _i, ${field_reference_name}ArrayElement);
+ (*env)->DeleteLocalRef(env, ${field_reference_name}ArrayElement);
+ }
+ (*env)->SetObjectField(env, ${object_ref_name}, ${field_reference_name}FieldId, ${field_reference_name});
+ (*env)->DeleteLocalRef(env, ${field_reference_name});
+ }
+""")
+
+
def _generate_c2j_primitive_type_array_swap(msg_java_name, field, object_ref_name, struct_ref_name):
field_type = field.type
return _C2J_PRIMITIVE_TYPE_ARRAY_SWAP_TEMPLATE.substitute(
@@ -295,6 +331,8 @@ def _generate_c2j_scalar_swap(msg_java_name, field, object_ref_name, struct_ref_
# TODO(VPP-1186): move the logic to JNI generators
if isinstance(field_type, Class):
return _generate_c2j_class_swap(msg_java_name, field, object_ref_name, struct_ref_name)
+ elif isinstance(field_type, Enum):
+ return _generate_c2j_enum_swap(msg_java_name, field, object_ref_name, struct_ref_name)
else:
return _generate_c2j_primitive_type_swap(msg_java_name, field, object_ref_name, struct_ref_name)
else:
@@ -325,6 +363,30 @@ _C2J_CLASS_SWAP_TEMPLATE = Template("""
""")
+def _generate_c2j_enum_swap(msg_java_name, field, object_ref_name, struct_ref_name):
+ field_type = field.type
+ return _C2J_ENUM_SWAP_TEMPLATE.substitute(
+ java_name=field.java_name,
+ class_ref_name=msg_java_name,
+ jni_signature=field_type.jni_signature,
+ jni_signature_enum_value=field_type.value.type.jni_signature,
+ jni_name=field_type.jni_name,
+ jni_accessor=field_type.jni_accessor,
+ object_ref_name=object_ref_name,
+ struct_ref_name=struct_ref_name,
+ net_to_host_function=field_type.net_to_host_function,
+ c_name=field.name)
+
+_C2J_ENUM_SWAP_TEMPLATE = Template("""
+ jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");
+ jclass ${java_name}Class = (*env)->FindClass(env, "${jni_name}");
+ jmethodID ${java_name}Constructor = (*env)->GetStaticMethodID(env, ${java_name}Class, "forValue", "(${jni_signature_enum_value})${jni_signature}");
+ jobject ${java_name} = (*env)->CallStaticObjectMethod(env, ${java_name}Class, ${java_name}Constructor, ${net_to_host_function}(${struct_ref_name}->${c_name}));
+ (*env)->SetObjectField(env, ${object_ref_name}, ${java_name}FieldId, ${java_name});
+ (*env)->DeleteLocalRef(env, ${java_name});
+""")
+
+
def _generate_c2j_primitive_type_swap(msg_java_name, field, object_ref_name, struct_ref_name):
field_type = field.type
return _C2J_PRIMITIVE_TYPE_SWAP_TEMPLATE.substitute(
diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/jni_type_handlers_gen.py b/src/vpp-api/java/jvpp/gen/jvppgen/jni_type_handlers_gen.py
index c32acc1911c..31642e53a73 100755
--- a/src/vpp-api/java/jvpp/gen/jvppgen/jni_type_handlers_gen.py
+++ b/src/vpp-api/java/jvpp/gen/jvppgen/jni_type_handlers_gen.py
@@ -16,7 +16,7 @@
from string import Template
from jni_common_gen import generate_j2c_swap, generate_j2c_identifiers, generate_c2j_swap
-from jvpp_model import Class
+from jvpp_model import Class, Enum
def generate_type_handlers(model, logger):
@@ -30,6 +30,8 @@ def generate_type_handlers(model, logger):
#TODO(VPP-1186): move the logic to JNI generators
if isinstance(t, Class):
_generate_class(model, t, type_handlers)
+ elif isinstance(t, Enum):
+ _generate_enum(model, t, type_handlers)
else:
logger.debug("Skipping custom JNI type handler generation for %s", t)
@@ -85,6 +87,54 @@ $type_swap
}""")
+def _generate_enum(model, t, type_handlers):
+ value_type = t.value.type
+ type_handlers.append(_ENUM_NET_TO_HOST_TEMPLATE.substitute(
+ c_name=t.name,
+ json_filename=model.json_api_files,
+ json_definition=t.doc,
+ class_FQN=t.jni_name,
+ jni_signature=value_type.jni_signature,
+ jni_type=value_type.jni_type,
+ jni_accessor=value_type.jni_accessor,
+ swap=_generate_scalar_host_to_net_swap(t.value)
+ ))
+
+ type_handlers.append(_ENUM_HOST_TO_NET_TEMPLATE.substitute(
+ c_name=t.name,
+ json_filename=model.json_api_files,
+ json_definition=t.doc,
+ class_FQN=t.jni_name,
+ jni_type=value_type.jni_type,
+ type_swap=_generate_scalar_net_to_host_swap(t.value)
+ ))
+
+_ENUM_NET_TO_HOST_TEMPLATE = Template("""
+/**
+ * Host to network byte order conversion for ${c_name} enum.
+ * Generated based on $json_filename:
+$json_definition
+ */
+static inline void _host_to_net_${c_name}(JNIEnv * env, jobject _host, vl_api_${c_name}_t * _net)
+{
+ jclass enumClass = (*env)->FindClass(env, "${class_FQN}");
+ jfieldID valueFieldId = (*env)->GetStaticFieldID(env, enumClass, "value", "${jni_signature}");
+ ${jni_type} value = (*env)->GetStatic${jni_accessor}Field(env, enumClass, valueFieldId);
+ ${swap};
+}""")
+
+_ENUM_HOST_TO_NET_TEMPLATE = Template("""
+/**
+ * Network to host byte order conversion for ${c_name} type.
+ * Generated based on $json_filename:
+$json_definition
+ */
+static inline ${jni_type} _net_to_host_${c_name}(vl_api_${c_name}_t _net)
+{
+ return (${jni_type}) $type_swap
+}""")
+
+
def _generate_scalar_host_to_net_swap(field):
field_type = field.type
if field_type.is_swap_needed:
diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_model.py b/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_model.py
index 8b60c0dc4f3..024e8ffd7d8 100755
--- a/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_model.py
+++ b/src/vpp-api/java/jvpp/gen/jvppgen/jvpp_model.py
@@ -110,6 +110,34 @@ class Array(Type):
return "Array{name:%s, java_name:%s}" % (self.name, self.java_name)
+class Enum(Type):
+ def __init__(self, name, value, constants, definition, plugin_name):
+ _java_name = _underscore_to_camelcase_upper(name)
+
+ super(Enum, self).__init__(
+ name=name,
+ java_name=_java_name,
+ java_name_fqn="io.fd.vpp.jvpp.%s.types.%s" % (plugin_name, _java_name),
+ jni_signature="Lio/fd/vpp/jvpp/%s/types/%s;" % (plugin_name, _java_name),
+ jni_type="jobject",
+ jni_accessor="Object",
+ host_to_net_function="_host_to_net_%s" % name,
+ net_to_host_function="_net_to_host_%s" % name
+ )
+
+ self.value = value
+ self.constants = constants
+ self.doc = _message_to_javadoc(definition)
+ self.java_name_lower = _underscore_to_camelcase_lower(name)
+ self.vpp_name = "%s%s%s" % (_VPP_TYPE_PREFIX, name, _VPP_TYPE_SUFFIX)
+ # Fully qualified class name used by FindClass function, see:
+ # https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#FindClass
+ self.jni_name = "io/fd/vpp/jvpp/%s/types/%s" % (plugin_name, _java_name)
+
+ def get_host_to_net_function(self, host_ref_name, net_ref_name):
+ return "_host_to_net_%s(env, %s, &(%s))" % (self.name, host_ref_name, net_ref_name)
+
+
class Class(Type):
def __init__(self, name, crc, fields, definition, plugin_name):
_java_name = _underscore_to_camelcase_upper(name)
@@ -255,6 +283,8 @@ class JVppModel(object):
self.plugin_name = plugin_name
self.plugin_java_name = _underscore_to_camelcase_upper(plugin_name)
self._load_json_files(json_api_files)
+ self._parse_simple_types()
+ self._parse_enums()
self._parse_types()
self._parse_services()
self._parse_messages()
@@ -273,7 +303,7 @@ class JVppModel(object):
self._messages.extend(j['messages'])
self._services.update(j['services'])
- def _parse_types(self):
+ def _parse_simple_types(self):
# Mapping according to:
# http://docs.oracle.com/javase/7/do+'[]'cs/technotes/guides/jni/spec/types.html
# and
@@ -309,6 +339,28 @@ class JVppModel(object):
for n, t in self._types_by_name.items():
self._types_by_name[n + _ARRAY_SUFFIX] = Array(t)
+ def _parse_enums(self):
+ for json_type in self._enums:
+ name = json_type[0]
+ definition = json_type[1:]
+ _type = self._parse_enum(name, definition)
+ self._types_by_name[name] = _type
+ self._types_by_name[name + _ARRAY_SUFFIX] = Array(_type)
+
+ def _parse_enum(self, name, definition):
+ self.logger.debug("Parsing enum %s: %s", name, definition)
+ constants = []
+ type_name = None
+ for item in definition:
+ if type(item) is dict and 'enumtype' in item:
+ type_name = item['enumtype']
+ continue
+ constants.append({'name': item[0], 'value': item[1]})
+ if not type_name:
+ raise ParseException("'enumtype' was not defined for %s" % definition)
+ return Enum(name, Field('value', self._types_by_name[type_name]), constants, definition, self.plugin_name)
+
+ def _parse_types(self):
for json_type in self._types:
try:
name = json_type[0]