Move java api to extras/
Change-Id: Ibd5cbbdfb22a235442cddaebc9eae9a3c4e35ec9 Signed-off-by: Damjan Marion <damarion@cisco.com>
This commit is contained in:

committed by
Dave Barach

parent
a14c166740
commit
cc4a5e8089
93
extras/japi/java/jvpp/gen/jvpp_gen.py
Executable file
93
extras/japi/java/jvpp/gen/jvpp_gen.py
Executable file
@ -0,0 +1,93 @@
|
||||
#!/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.
|
||||
#
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
from jvppgen.types_gen import generate_types
|
||||
from jvppgen.enums_gen import generate_enums
|
||||
from jvppgen.unions_gen import generate_unions
|
||||
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
|
||||
from jvppgen.callback_gen import generate_callbacks
|
||||
from jvppgen.jni_gen import generate_jni
|
||||
from jvppgen.notification_gen import generate_notifications
|
||||
from jvppgen.jvpp_future_facade_gen import generate_future_facade
|
||||
from jvppgen.jvpp_callback_facade_gen import generate_callback_facade
|
||||
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_unions(_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)
|
||||
generate_callbacks(_work_dir(base_dir, "callback"), model, logger)
|
||||
generate_jni(root_dir, model, logger)
|
||||
generate_notifications(_work_dir(base_dir, "notification"), model, logger)
|
||||
generate_future_facade(_work_dir(base_dir, "future"), model, logger)
|
||||
generate_callback_facade(_work_dir(base_dir, "callfacade"), model, logger)
|
||||
|
||||
|
||||
def _work_dir(work_dir, sub_dir=None):
|
||||
if sub_dir:
|
||||
work_dir = "%s/%s" % (work_dir, sub_dir)
|
||||
try:
|
||||
os.makedirs(work_dir)
|
||||
except OSError:
|
||||
if not os.path.isdir(work_dir):
|
||||
raise
|
||||
return work_dir
|
||||
|
||||
|
||||
def _init_logger():
|
||||
try:
|
||||
verbose = int(os.getenv("V", 0))
|
||||
except:
|
||||
verbose = 0
|
||||
|
||||
log_level = logging.WARNING
|
||||
if verbose == 1:
|
||||
log_level = logging.INFO
|
||||
elif verbose >= 2:
|
||||
log_level = logging.DEBUG
|
||||
|
||||
logging.basicConfig(stream=sys.stdout, level=log_level)
|
||||
logger = logging.getLogger("JVPP GEN")
|
||||
logger.setLevel(log_level)
|
||||
return logger
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logger = _init_logger()
|
||||
|
||||
argparser = argparse.ArgumentParser(description="VPP Java API generator")
|
||||
argparser.add_argument('-i', nargs='+', metavar='api_file.json', help="json vpp api file(s)")
|
||||
argparser.add_argument('--plugin_name')
|
||||
argparser.add_argument('--root_dir')
|
||||
args = argparser.parse_args()
|
||||
|
||||
logger.info("Generating Java API for %s" % args.i)
|
||||
logger.debug("plugin_name: %s" % args.plugin_name)
|
||||
logger.debug("root_dir: %s" % args.root_dir)
|
||||
|
||||
model = JVppModel(logger, args.i, args.plugin_name)
|
||||
generate_jvpp(args.root_dir, model, logger)
|
0
extras/japi/java/jvpp/gen/jvppgen/__init__.py
Normal file
0
extras/japi/java/jvpp/gen/jvppgen/__init__.py
Normal file
73
extras/japi/java/jvpp/gen/jvppgen/callback_gen.py
Executable file
73
extras/japi/java/jvpp/gen/jvppgen/callback_gen.py
Executable file
@ -0,0 +1,73 @@
|
||||
#!/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 is_request, is_dump, is_control_ping, is_control_ping_reply
|
||||
|
||||
|
||||
def generate_callbacks(work_dir, model, logger):
|
||||
json_api_files = model.json_api_files
|
||||
logger.debug("Generating Callback interfaces for %s" % json_api_files)
|
||||
plugin_package = model.plugin_package
|
||||
|
||||
callbacks = []
|
||||
for msg in model.messages:
|
||||
name = msg.java_name_upper
|
||||
if is_control_ping(msg) or is_control_ping_reply(msg):
|
||||
# Skip control_ping managed by jvpp registry.
|
||||
continue
|
||||
if is_dump(msg) or is_request(msg):
|
||||
continue
|
||||
|
||||
callbacks.append("%s.callback.%sCallback" % (plugin_package, name))
|
||||
callback = _CALLBACK_TEMPLATE.substitute(
|
||||
plugin_package=plugin_package,
|
||||
json_filename=json_api_files,
|
||||
name=name)
|
||||
|
||||
with open("%s/%sCallback.java" % (work_dir, name), "w") as f:
|
||||
f.write(callback)
|
||||
|
||||
plugin_name = model.plugin_java_name
|
||||
with open("%s/JVpp%sGlobalCallback.java" % (work_dir, plugin_name), "w") as f:
|
||||
f.write(_GLOBAL_CALLBACK_TEMPLATE.substitute(
|
||||
plugin_package=plugin_package,
|
||||
json_filename=json_api_files,
|
||||
plugin_name=plugin_name,
|
||||
callbacks=", ".join(callbacks)
|
||||
))
|
||||
|
||||
_CALLBACK_TEMPLATE = Template("""package $plugin_package.callback;
|
||||
|
||||
/**
|
||||
* <p>Represents callback for plugin's api message.
|
||||
* <br>It was generated by jvpp_callback_gen.py based on $json_filename.
|
||||
*/
|
||||
public interface ${name}Callback extends io.fd.vpp.jvpp.callback.JVppCallback {
|
||||
|
||||
void on${name}(${plugin_package}.dto.${name} reply);
|
||||
}
|
||||
""")
|
||||
|
||||
_GLOBAL_CALLBACK_TEMPLATE = Template("""package $plugin_package.callback;
|
||||
|
||||
/**
|
||||
* <p>Global aggregated callback interface.
|
||||
* <br>It was generated by jvpp_callback_gen.py based on $json_filename.
|
||||
*/
|
||||
public interface JVpp${plugin_name}GlobalCallback extends io.fd.vpp.jvpp.callback.ControlPingCallback, $callbacks {
|
||||
}
|
||||
""")
|
231
extras/japi/java/jvpp/gen/jvppgen/dto_gen.py
Executable file
231
extras/japi/java/jvpp/gen/jvppgen/dto_gen.py
Executable file
@ -0,0 +1,231 @@
|
||||
#!/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_common_gen import generate_hash_code, generate_equals, generate_to_string, generate_fields
|
||||
from jvpp_model import is_request, is_reply, is_retval, is_dump, is_details, is_event, is_control_ping, \
|
||||
is_control_ping_reply
|
||||
|
||||
|
||||
def generate_dtos(work_dir, model, logger):
|
||||
logger.debug("Generating DTOs for %s " % model.json_api_files)
|
||||
_generate_message_dtos(work_dir, model, logger)
|
||||
_generate_dump_reply_wrappers(work_dir, model, logger)
|
||||
|
||||
|
||||
def _generate_message_dtos(work_dir, model, logger):
|
||||
for msg in model.messages:
|
||||
logger.debug("Generating DTO for message %s", msg)
|
||||
class_name = msg.java_name_upper
|
||||
|
||||
if is_control_ping(msg) or is_control_ping_reply(msg):
|
||||
# Skip control_ping managed by jvpp registry.
|
||||
continue
|
||||
if is_request(msg):
|
||||
dto = _generate_request_dto(msg, model, base_type="JVppRequest")
|
||||
elif is_dump(msg):
|
||||
dto = _generate_request_dto(msg, model, base_type="JVppDump")
|
||||
elif is_reply(msg) or is_details(msg):
|
||||
dto = _generate_reply_dto(msg, model)
|
||||
elif is_event(msg):
|
||||
dto = _generate_event_dto(msg, model)
|
||||
else:
|
||||
logger.warn("Failed to generate DTO for: %s. Message type is not supported." % msg)
|
||||
continue
|
||||
with open("%s/%s.java" % (work_dir, class_name), "w") as f:
|
||||
f.write(dto)
|
||||
|
||||
|
||||
def _generate_request_dto(msg, model, base_type):
|
||||
msg_java_name_upper = msg.java_name_upper
|
||||
fields = msg.fields
|
||||
return _REQUEST_TEMPLATE.substitute(
|
||||
plugin_package=model.plugin_package,
|
||||
json_filename=model.json_api_files,
|
||||
json_definition=msg.doc,
|
||||
class_name=msg_java_name_upper,
|
||||
base_type=base_type,
|
||||
fields=generate_fields(fields),
|
||||
hash_code=generate_hash_code(fields),
|
||||
equals=generate_equals(msg_java_name_upper, fields),
|
||||
to_string=generate_to_string(msg_java_name_upper, fields),
|
||||
send=_generate_send(model, msg))
|
||||
|
||||
_REQUEST_TEMPLATE = Template("""
|
||||
package $plugin_package.dto;
|
||||
|
||||
/**
|
||||
* <p>This class represents request DTO.
|
||||
* <br>It was generated by dto_gen.py based on $json_filename:
|
||||
* <pre>
|
||||
$json_definition
|
||||
* </pre>
|
||||
*/
|
||||
public final class $class_name implements io.fd.vpp.jvpp.dto.$base_type {
|
||||
$fields
|
||||
$hash_code
|
||||
$equals
|
||||
$to_string
|
||||
$send
|
||||
}
|
||||
""")
|
||||
|
||||
|
||||
def _generate_send(model, msg):
|
||||
return _SEND_TEMPLATE.substitute(
|
||||
plugin_package=model.plugin_package,
|
||||
plugin_name=model.plugin_java_name,
|
||||
method_name=msg.java_name_lower,
|
||||
args="this" if msg.has_fields else ""
|
||||
)
|
||||
|
||||
_SEND_TEMPLATE = Template("""
|
||||
@Override
|
||||
public int send(final io.fd.vpp.jvpp.JVpp jvpp) throws io.fd.vpp.jvpp.VppInvocationException {
|
||||
return (($plugin_package.JVpp${plugin_name})jvpp).$method_name($args);
|
||||
}""")
|
||||
|
||||
|
||||
def _generate_reply_dto(msg, model):
|
||||
msg_java_name_upper = msg.java_name_upper
|
||||
# Negative retval is mapped to java exception, so filter it out:
|
||||
fields = filter(lambda field: not is_retval(field), msg.fields)
|
||||
return _REPLY_TEMPLATE.substitute(
|
||||
plugin_package=model.plugin_package,
|
||||
json_filename=model.json_api_files,
|
||||
json_definition=msg.doc,
|
||||
class_name=msg_java_name_upper,
|
||||
request_name=msg.request_java,
|
||||
fields=generate_fields(fields),
|
||||
hash_code=generate_hash_code(fields),
|
||||
equals=generate_equals(msg_java_name_upper, fields),
|
||||
to_string=generate_to_string(msg_java_name_upper, fields))
|
||||
|
||||
_REPLY_TEMPLATE = Template("""
|
||||
package $plugin_package.dto;
|
||||
|
||||
/**
|
||||
* <p>This class represents reply DTO.
|
||||
* <br>It was generated by jvpp_dto_gen.py based on $json_filename:
|
||||
* <pre>
|
||||
$json_definition
|
||||
* </pre>
|
||||
*/
|
||||
public final class $class_name implements io.fd.vpp.jvpp.dto.JVppReply<$plugin_package.dto.$request_name> {
|
||||
$fields
|
||||
$hash_code
|
||||
$equals
|
||||
$to_string
|
||||
}
|
||||
""")
|
||||
|
||||
|
||||
def _generate_event_dto(msg, model):
|
||||
msg_java_name_upper = msg.java_name_upper
|
||||
# Negative retval is mapped to java exception, so filter it out:
|
||||
fields = filter(lambda field: not is_retval(field), msg.fields)
|
||||
return _EVENT_TEMPLATE.substitute(
|
||||
plugin_package=model.plugin_package,
|
||||
json_filename=model.json_api_files,
|
||||
json_definition=msg.doc,
|
||||
class_name=msg_java_name_upper,
|
||||
fields=generate_fields(fields),
|
||||
hash_code=generate_hash_code(fields),
|
||||
equals=generate_equals(msg_java_name_upper, fields),
|
||||
to_string=generate_to_string(msg_java_name_upper, fields))
|
||||
|
||||
_EVENT_TEMPLATE = Template("""
|
||||
package $plugin_package.dto;
|
||||
|
||||
/**
|
||||
* <p>This class represents event DTO.
|
||||
* <br>It was generated by jvpp_dto_gen.py based on $json_filename:
|
||||
* <pre>
|
||||
$json_definition
|
||||
* </pre>
|
||||
*/
|
||||
public final class $class_name {
|
||||
$fields
|
||||
$hash_code
|
||||
$equals
|
||||
$to_string
|
||||
}
|
||||
""")
|
||||
|
||||
|
||||
def _generate_dump_reply_wrappers(work_dir, model, logger):
|
||||
for msg in model.messages:
|
||||
if is_details(msg):
|
||||
logger.debug("Generating ReplyDump DTO for message %s", msg)
|
||||
details_class = msg.java_name_upper
|
||||
dto = _REPLY_DUMP_TEMPLATE.substitute(
|
||||
plugin_package=model.plugin_package,
|
||||
json_filename=model.json_api_files,
|
||||
json_definition=msg.doc,
|
||||
details_class=details_class,
|
||||
details_field=msg.java_name_lower,
|
||||
dump_class=msg.request_java
|
||||
)
|
||||
with open("%s/%sReplyDump.java" % (work_dir, details_class), "w") as f:
|
||||
f.write(dto)
|
||||
|
||||
_REPLY_DUMP_TEMPLATE = Template("""
|
||||
package $plugin_package.dto;
|
||||
|
||||
/**
|
||||
* <p>This class represents dump reply wrapper.
|
||||
* <br>It was generated by jvpp_dto_gen.py based on $json_filename:
|
||||
* <pre>
|
||||
$json_definition
|
||||
* </pre>
|
||||
*/
|
||||
public final class ${details_class}ReplyDump implements io.fd.vpp.jvpp.dto.JVppReplyDump<${plugin_package}.dto.${dump_class}, ${plugin_package}.dto.${details_class}> {
|
||||
|
||||
public java.util.List<${details_class}> ${details_field} = new java.util.ArrayList<>();
|
||||
|
||||
@Override
|
||||
@io.fd.vpp.jvpp.coverity.SuppressFBWarnings("UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD")
|
||||
public int hashCode() {
|
||||
return java.util.Objects.hash(${details_field});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final ${details_class}ReplyDump other = (${details_class}ReplyDump) o;
|
||||
|
||||
if (!java.util.Objects.equals(this.${details_field}, other.${details_field})) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "${details_class}ReplyDump{" +
|
||||
"${details_field}=" + ${details_field} + "}";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
""")
|
74
extras/japi/java/jvpp/gen/jvppgen/enums_gen.py
Executable file
74
extras/japi/java/jvpp/gen/jvppgen/enums_gen.py
Executable file
@ -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)""")
|
427
extras/japi/java/jvpp/gen/jvppgen/jni_common_gen.py
Executable file
427
extras/japi/java/jvpp/gen/jvppgen/jni_common_gen.py
Executable file
File diff suppressed because it is too large
Load Diff
160
extras/japi/java/jvpp/gen/jvppgen/jni_gen.py
Executable file
160
extras/japi/java/jvpp/gen/jvppgen/jni_gen.py
Executable file
@ -0,0 +1,160 @@
|
||||
#!/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 jni_impl_gen import generate_jni_impl
|
||||
from jni_msg_handlers_gen import generate_jni_handlers
|
||||
from jni_type_handlers_gen import generate_type_handlers
|
||||
from jvpp_model import is_control_ping, is_dump, is_request, is_control_ping_reply
|
||||
|
||||
|
||||
def generate_jni(work_dir, model, logger):
|
||||
logger.debug("Generating jvpp C for %s" % model.json_api_files)
|
||||
plugin_name = model.plugin_name
|
||||
messages = model.messages
|
||||
|
||||
with open("%s/jvpp_%s_gen.h" % (work_dir, plugin_name), "w") as f:
|
||||
f.write(_JVPP_C_TEMPLATE.substitute(
|
||||
json_filename=model.json_api_files,
|
||||
class_cache=_generate_class_cache(plugin_name, messages),
|
||||
api_verification=_generate_api_verification(messages),
|
||||
type_handlers=generate_type_handlers(model, logger),
|
||||
jni_implementations=generate_jni_impl(model),
|
||||
msg_handlers=generate_jni_handlers(model),
|
||||
handler_registration=_generate_handler_registration(messages)))
|
||||
|
||||
_JVPP_C_TEMPLATE = Template("""/**
|
||||
* This file contains JNI bindings for jvpp Java API.
|
||||
* It was generated by jvpp_jni_gen.py based on $json_filename.
|
||||
*/
|
||||
$class_cache
|
||||
|
||||
$api_verification
|
||||
|
||||
// Type handlers
|
||||
$type_handlers
|
||||
|
||||
// JNI bindings
|
||||
$jni_implementations
|
||||
|
||||
// Message handlers
|
||||
$msg_handlers
|
||||
|
||||
$handler_registration
|
||||
""")
|
||||
|
||||
|
||||
def _generate_class_cache(plugin_name, messages):
|
||||
references = []
|
||||
for msg in messages:
|
||||
if is_control_ping(msg) or is_control_ping_reply(msg):
|
||||
# Skip control_ping managed by jvpp registry.
|
||||
continue
|
||||
references.append((
|
||||
msg.java_name_lower,
|
||||
'io/fd/vpp/jvpp/%s/dto/%s' % (plugin_name, msg.java_name_upper)
|
||||
))
|
||||
|
||||
references.append(('callbackException', 'io/fd/vpp/jvpp/VppCallbackException'))
|
||||
|
||||
return _CLASS_CACHE_TEMPLATE.substitute(
|
||||
class_references=_generate_class_references(references),
|
||||
create_references=_generate_create_references(references),
|
||||
delete_references=_generate_delete_references(references)
|
||||
)
|
||||
|
||||
_CLASS_CACHE_TEMPLATE = Template("""
|
||||
// JAVA class reference cache
|
||||
$class_references
|
||||
|
||||
static int cache_class_references(JNIEnv* env) {
|
||||
$create_references
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void delete_class_references(JNIEnv* env) {
|
||||
$delete_references
|
||||
}""")
|
||||
|
||||
|
||||
def _generate_class_references(references):
|
||||
return "\n".join("jclass %sClass;" % r[0] for r in references)
|
||||
|
||||
|
||||
def _generate_create_references(references):
|
||||
items = []
|
||||
for r in references:
|
||||
items.append(_CREATE_GLOBAL_REF_TEMPLATE.substitute(
|
||||
ref_name=r[0],
|
||||
fqn_name=r[1]
|
||||
))
|
||||
return "".join(items)
|
||||
|
||||
_CREATE_GLOBAL_REF_TEMPLATE = Template("""
|
||||
${ref_name}Class = (jclass)(*env)->NewGlobalRef(env, (*env)->FindClass(env, "${fqn_name}"));
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
(*env)->ExceptionDescribe(env);
|
||||
return JNI_ERR;
|
||||
}""")
|
||||
|
||||
|
||||
def _generate_delete_references(references):
|
||||
items = []
|
||||
for r in references:
|
||||
items.append(_DELETE_CLASS_INVOCATION_TEMPLATE.substitute(ref_name=r[0]))
|
||||
return "".join(items)
|
||||
|
||||
_DELETE_CLASS_INVOCATION_TEMPLATE = Template("""
|
||||
if (${ref_name}Class) {
|
||||
(*env)->DeleteGlobalRef(env, ${ref_name}Class);
|
||||
}""")
|
||||
|
||||
|
||||
def _generate_api_verification(messages):
|
||||
items = []
|
||||
for msg in messages:
|
||||
items.append("_(%s_%s) \\" % (msg.name, msg.crc))
|
||||
return _API_VERIFICATION_TEMPLATE.substitute(messages="\n".join(items))
|
||||
|
||||
_API_VERIFICATION_TEMPLATE = Template("""
|
||||
// List of supported API messages used for verification
|
||||
#define foreach_supported_api_message \\
|
||||
$messages
|
||||
""")
|
||||
|
||||
|
||||
def _generate_handler_registration(messages):
|
||||
"""
|
||||
Generates msg handler registration for all messages except for dumps and requests.
|
||||
:param messages: collection of VPP API messages.
|
||||
"""
|
||||
handlers = []
|
||||
for msg in messages:
|
||||
if is_control_ping(msg) or is_control_ping_reply(msg):
|
||||
# Skip control_ping managed by jvpp registry.
|
||||
continue
|
||||
if is_dump(msg) or is_request(msg):
|
||||
continue
|
||||
name = msg.name
|
||||
crc = msg.crc
|
||||
handlers.append("_(%s_%s, %s) \\" % (name, crc, name))
|
||||
return _HANDLER_REGISTRATION_TEMPLATE.substitute(handlers="\n".join(handlers))
|
||||
|
||||
_HANDLER_REGISTRATION_TEMPLATE = Template("""
|
||||
// Registration of message handlers in vlib
|
||||
#define foreach_api_reply_handler \\
|
||||
$handlers
|
||||
""")
|
115
extras/japi/java/jvpp/gen/jvppgen/jni_impl_gen.py
Executable file
115
extras/japi/java/jvpp/gen/jvppgen/jni_impl_gen.py
Executable file
@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env python2
|
||||
#
|
||||
# Copyright (c) 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 jni_common_gen import generate_j2c_identifiers, generate_j2c_swap
|
||||
from jvpp_model import is_dump, is_request, is_control_ping, is_control_ping_reply
|
||||
|
||||
|
||||
def generate_jni_impl(model):
|
||||
"""
|
||||
Generates JNI bindings for sending dump and request messages.
|
||||
:param model: meta-model of VPP API used for jVPP generation.
|
||||
"""
|
||||
jni_impl = []
|
||||
for msg in model.messages:
|
||||
if is_control_ping(msg) or is_control_ping_reply(msg):
|
||||
# Skip control ping managed by jvpp registry.
|
||||
continue
|
||||
if not (is_dump(msg) or is_request(msg)):
|
||||
continue
|
||||
arguments = ""
|
||||
request_class = ""
|
||||
jni_identifiers = ""
|
||||
msg_initialization = ""
|
||||
|
||||
if msg.has_fields:
|
||||
arguments = ", jobject request"
|
||||
request_class = _REQUEST_CLASS_TEMPLATE.substitute(
|
||||
plugin_name=model.plugin_name,
|
||||
java_dto_name=msg.java_name_upper
|
||||
)
|
||||
jni_identifiers = generate_j2c_identifiers(msg, class_ref_name="requestClass", object_ref_name="request")
|
||||
msg_initialization = generate_j2c_swap(msg, struct_ref_name="mp")
|
||||
|
||||
jni_impl.append(_JNI_IMPL_TEMPLATE.substitute(
|
||||
c_name=msg.name,
|
||||
json_filename=model.json_api_files,
|
||||
json_definition=msg.doc,
|
||||
plugin_name=model.plugin_name,
|
||||
plugin_java_name=model.plugin_java_name,
|
||||
java_method_name=msg.java_name_lower,
|
||||
arguments=arguments,
|
||||
request_class=request_class,
|
||||
jni_identifiers=jni_identifiers,
|
||||
msg_size=_generate_msg_size(msg),
|
||||
crc=msg.crc,
|
||||
msg_initialization=msg_initialization
|
||||
))
|
||||
return "".join(jni_impl)
|
||||
|
||||
|
||||
_JNI_IMPL_TEMPLATE = Template("""
|
||||
/**
|
||||
* JNI binding for sending ${c_name} message.
|
||||
* Generated based on $json_filename:
|
||||
$json_definition
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_io_fd_vpp_jvpp_${plugin_name}_JVpp${plugin_java_name}Impl_${java_method_name}0
|
||||
(JNIEnv * env, jclass clazz${arguments}) {
|
||||
${plugin_name}_main_t *plugin_main = &${plugin_name}_main;
|
||||
vl_api_${c_name}_t * mp;
|
||||
u32 my_context_id = vppjni_get_context_id (&jvpp_main);
|
||||
$request_class
|
||||
$jni_identifiers
|
||||
|
||||
// create message:
|
||||
const size_t _size = ${msg_size};
|
||||
mp = vl_msg_api_alloc(_size);
|
||||
memset (mp, 0, _size);
|
||||
mp->_vl_msg_id = ntohs (get_message_id(env, "${c_name}_${crc}"));
|
||||
mp->client_index = plugin_main->my_client_index;
|
||||
mp->context = clib_host_to_net_u32 (my_context_id);
|
||||
|
||||
$msg_initialization
|
||||
|
||||
// send message:
|
||||
if (CLIB_DEBUG > 1)
|
||||
clib_warning ("Sending ${c_name} message");
|
||||
vl_msg_api_send_shmem (plugin_main->vl_input_queue, (u8 *)&mp);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
return my_context_id;
|
||||
}""")
|
||||
|
||||
# TODO: cache method and field identifiers to achieve better performance
|
||||
# https://jira.fd.io/browse/HONEYCOMB-42
|
||||
_REQUEST_CLASS_TEMPLATE = Template(""" jclass requestClass = (*env)->FindClass(env, "io/fd/vpp/jvpp/${plugin_name}/dto/${java_dto_name}");
|
||||
""")
|
||||
|
||||
|
||||
def _generate_msg_size(msg):
|
||||
msg_size = "sizeof(*mp)"
|
||||
_size_components = []
|
||||
for field in msg.fields:
|
||||
# Ignore ZLAs for simplicity (to support them we need to call JNI functions to check actual size)
|
||||
if field.array_len_field:
|
||||
_size_components += " + %s*sizeof(%s)" % (field.array_len_field.java_name, field.type.base_type.vpp_name)
|
||||
# FIXME(VPP-586): for proper nested structures support, we need generate functions computing type sizes
|
||||
# and use it instead of sizeof
|
||||
|
||||
return msg_size + "".join(_size_components)
|
105
extras/japi/java/jvpp/gen/jvppgen/jni_msg_handlers_gen.py
Executable file
105
extras/japi/java/jvpp/gen/jvppgen/jni_msg_handlers_gen.py
Executable file
@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env python2
|
||||
#
|
||||
# Copyright (c) 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 jni_common_gen import generate_c2j_swap
|
||||
from jvpp_model import is_dump, is_request, is_control_ping, is_control_ping_reply, is_retval
|
||||
|
||||
|
||||
def generate_jni_handlers(model):
|
||||
"""
|
||||
Generates msg handlers for all messages except for dumps and requests (handled by vpp, not client).
|
||||
:param model: meta-model of VPP API used for jVPP generation.
|
||||
"""
|
||||
jni_impl = []
|
||||
for msg in model.messages:
|
||||
msg_name = msg.name
|
||||
if is_control_ping(msg) or is_control_ping_reply(msg):
|
||||
# Skip control ping managed by jvpp registry.
|
||||
continue
|
||||
if is_dump(msg) or is_request(msg):
|
||||
continue
|
||||
|
||||
jni_impl.append(_MSG_HANDLER_TEMPLATE.substitute(
|
||||
c_name=msg_name,
|
||||
json_filename=model.json_api_files,
|
||||
json_definition=msg.doc,
|
||||
plugin_name=model.plugin_name,
|
||||
err_handler=_generate_error_handler(msg),
|
||||
class_ref_name=msg.java_name_lower,
|
||||
dto_name=msg.java_name_upper,
|
||||
dto_setters=generate_c2j_swap(msg, object_ref_name="dto", struct_ref_name="mp")
|
||||
))
|
||||
return "".join(jni_impl)
|
||||
|
||||
_MSG_HANDLER_TEMPLATE = Template("""
|
||||
/**
|
||||
* Handler for ${c_name} message.
|
||||
* Generated based on $json_filename:
|
||||
$json_definition
|
||||
*/
|
||||
static void vl_api_${c_name}_t_handler (vl_api_${c_name}_t * mp)
|
||||
{
|
||||
${plugin_name}_main_t *plugin_main = &${plugin_name}_main;
|
||||
JNIEnv *env = jvpp_main.jenv;
|
||||
jthrowable exc;
|
||||
$err_handler
|
||||
|
||||
if (CLIB_DEBUG > 1)
|
||||
clib_warning ("Received ${c_name} event message");
|
||||
|
||||
jmethodID constructor = (*env)->GetMethodID(env, ${class_ref_name}Class, "<init>", "()V");
|
||||
|
||||
// User does not have to provide callbacks for all VPP messages.
|
||||
// We are ignoring messages that are not supported by user.
|
||||
(*env)->ExceptionClear(env); // just in case exception occurred in different place and was not properly cleared
|
||||
jmethodID callbackMethod = (*env)->GetMethodID(env, plugin_main->callbackClass, "on${dto_name}", "(Lio/fd/vpp/jvpp/${plugin_name}/dto/${dto_name};)V");
|
||||
exc = (*env)->ExceptionOccurred(env);
|
||||
if (exc) {
|
||||
clib_warning("Unable to extract on${dto_name} method reference from ${plugin_name} plugin's callbackClass. Ignoring message.\\n");
|
||||
(*env)->ExceptionDescribe(env);
|
||||
(*env)->ExceptionClear(env);
|
||||
return;
|
||||
}
|
||||
|
||||
jobject dto = (*env)->NewObject(env, ${class_ref_name}Class, constructor);
|
||||
$dto_setters
|
||||
|
||||
(*env)->CallVoidMethod(env, plugin_main->callbackObject, callbackMethod, dto);
|
||||
// free DTO as per http://stackoverflow.com/questions/1340938/memory-leak-when-calling-java-code-from-c-using-jni
|
||||
(*env)->DeleteLocalRef(env, dto);
|
||||
}""")
|
||||
|
||||
|
||||
def _generate_error_handler(msg):
|
||||
err_handler = ""
|
||||
for field in msg.fields:
|
||||
if is_retval(field):
|
||||
err_handler = _ERR_HANDLER_TEMPLATE.substitute(name=msg.name)
|
||||
return err_handler
|
||||
|
||||
# Code fragment for checking result of the operation before sending request reply.
|
||||
# Error checking is optional (some messages, e.g. detail messages do not have retval field).
|
||||
_ERR_HANDLER_TEMPLATE = Template("""
|
||||
// for negative result don't send callback message but send error callback
|
||||
if (mp->retval<0) {
|
||||
call_on_error("${name}", mp->context, mp->retval, plugin_main->callbackClass, plugin_main->callbackObject, callbackExceptionClass);
|
||||
return;
|
||||
}
|
||||
if (mp->retval == VNET_API_ERROR_IN_PROGRESS) {
|
||||
clib_warning("Result in progress");
|
||||
return;
|
||||
}""")
|
222
extras/japi/java/jvpp/gen/jvppgen/jni_type_handlers_gen.py
Executable file
222
extras/japi/java/jvpp/gen/jvppgen/jni_type_handlers_gen.py
Executable file
@ -0,0 +1,222 @@
|
||||
#!/usr/bin/env python2
|
||||
#
|
||||
# Copyright (c) 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 jni_common_gen import generate_j2c_swap, generate_j2c_field_swap, generate_j2c_identifiers, generate_c2j_swap
|
||||
from jvpp_model import Class, Enum, Union
|
||||
|
||||
|
||||
def generate_type_handlers(model, logger):
|
||||
"""
|
||||
Generates host-to-net and net-to-host functions for all custom types defined in the VPP API
|
||||
:param model: meta-model of VPP API used for jVPP generation.
|
||||
:param logger: jVPP logger
|
||||
"""
|
||||
type_handlers = []
|
||||
for t in model.types:
|
||||
#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)
|
||||
elif isinstance(t, Union):
|
||||
_generate_union(model, t, type_handlers)
|
||||
else:
|
||||
logger.debug("Skipping custom JNI type handler generation for %s", t)
|
||||
|
||||
return "\n".join(type_handlers)
|
||||
|
||||
|
||||
def _generate_class(model, t, type_handlers):
|
||||
ref_name = t.java_name_lower
|
||||
type_handlers.append(_TYPE_HOST_TO_NET_TEMPLATE.substitute(
|
||||
c_name=t.name,
|
||||
json_filename=model.json_api_files,
|
||||
json_definition=t.doc,
|
||||
type_reference_name=ref_name,
|
||||
class_FQN=t.jni_name,
|
||||
jni_identifiers=generate_j2c_identifiers(t, class_ref_name="%sClass" % ref_name, object_ref_name="_host"),
|
||||
type_swap=generate_j2c_swap(t, struct_ref_name="_net")
|
||||
))
|
||||
type_handlers.append(_TYPE_NET_TO_HOST_TEMPLATE.substitute(
|
||||
c_name=t.name,
|
||||
json_filename=model.json_api_files,
|
||||
json_definition=t.doc,
|
||||
type_reference_name=ref_name,
|
||||
class_FQN=t.jni_name,
|
||||
type_swap=generate_c2j_swap(t, object_ref_name="_host", struct_ref_name="_net")
|
||||
))
|
||||
|
||||
_TYPE_HOST_TO_NET_TEMPLATE = Template("""
|
||||
/**
|
||||
* Host to network byte order conversion for ${c_name} type.
|
||||
* 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 ${type_reference_name}Class = (*env)->FindClass(env, "${class_FQN}");
|
||||
$jni_identifiers
|
||||
$type_swap
|
||||
}""")
|
||||
|
||||
_TYPE_NET_TO_HOST_TEMPLATE = Template("""
|
||||
/**
|
||||
* Network to host byte order conversion for ${c_name} type.
|
||||
* Generated based on $json_filename:
|
||||
$json_definition
|
||||
*/
|
||||
static inline void _net_to_host_${c_name}(JNIEnv * env, vl_api_${c_name}_t * _net, jobject _host)
|
||||
{
|
||||
jclass ${type_reference_name}Class = (*env)->FindClass(env, "${class_FQN}");
|
||||
$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:
|
||||
return field_type.get_host_to_net_function(field.java_name, "*_net")
|
||||
else:
|
||||
return "*_net = %s" % field.java_name
|
||||
|
||||
|
||||
def _generate_scalar_net_to_host_swap(field):
|
||||
field_type = field.type
|
||||
if field_type.is_swap_needed:
|
||||
return "%s((%s) _net);" % (field_type.net_to_host_function, field_type.name)
|
||||
else:
|
||||
return "_net"
|
||||
|
||||
|
||||
def _generate_union(model, t, type_handlers):
|
||||
type_handlers.append(_generate_union_host_to_net(model, t))
|
||||
type_handlers.append(_generate_union_net_to_host(model, t))
|
||||
|
||||
|
||||
def _generate_union_host_to_net(model, t):
|
||||
swap = []
|
||||
for i, field in enumerate(t.fields):
|
||||
field_type = field.type
|
||||
swap.append(_UNION_FIELD_HOST_TO_NET_TEMPLATE.substitute(
|
||||
field_index=i,
|
||||
java_name=field.java_name,
|
||||
jni_signature=field_type.jni_signature,
|
||||
jni_type=field_type.jni_type,
|
||||
jni_accessor=field_type.jni_accessor,
|
||||
swap=generate_j2c_field_swap(field, struct_ref_name="_net")
|
||||
))
|
||||
|
||||
return _UNION_HOST_TO_NET_TEMPLATE.substitute(
|
||||
c_name=t.name,
|
||||
json_filename=model.json_api_files,
|
||||
json_definition=t.doc,
|
||||
class_FQN=t.jni_name,
|
||||
swap="".join(swap)
|
||||
)
|
||||
|
||||
_UNION_FIELD_HOST_TO_NET_TEMPLATE = Template("""
|
||||
if (_activeMember == ${field_index}) {
|
||||
jfieldID fieldId = (*env)->GetFieldID(env, _class, "${java_name}", "${jni_signature}");
|
||||
${jni_type} ${java_name} = (*env)->Get${jni_accessor}Field(env, _host, fieldId);
|
||||
${swap}
|
||||
}""")
|
||||
|
||||
_UNION_HOST_TO_NET_TEMPLATE = Template("""
|
||||
/**
|
||||
* Host to network byte order conversion for ${c_name} union.
|
||||
* 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 _class = (*env)->FindClass(env, "${class_FQN}");
|
||||
|
||||
jfieldID _activeMemberFieldId = (*env)->GetFieldID(env, _class, "_activeMember", "I");
|
||||
jint _activeMember = (*env)->GetIntField(env, _host, _activeMemberFieldId);
|
||||
$swap
|
||||
}""")
|
||||
|
||||
|
||||
def _generate_union_net_to_host(model, t):
|
||||
return _UNION_NET_TO_HOST_TEMPLATE.substitute(
|
||||
c_name=t.name,
|
||||
json_filename=model.json_api_files,
|
||||
json_definition=t.doc,
|
||||
type_reference_name=t.java_name_lower,
|
||||
class_FQN=t.jni_name,
|
||||
swap=generate_c2j_swap(t, object_ref_name="_host", struct_ref_name="_net")
|
||||
)
|
||||
|
||||
_UNION_NET_TO_HOST_TEMPLATE = Template("""
|
||||
/**
|
||||
* Network to host byte order conversion for ${c_name} union.
|
||||
* Generated based on $json_filename:
|
||||
$json_definition
|
||||
*/
|
||||
static inline void _net_to_host_${c_name}(JNIEnv * env, vl_api_${c_name}_t * _net, jobject _host)
|
||||
{
|
||||
jclass ${type_reference_name}Class = (*env)->FindClass(env, "${class_FQN}");
|
||||
$swap
|
||||
}""")
|
289
extras/japi/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py
Normal file
289
extras/japi/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py
Normal file
@ -0,0 +1,289 @@
|
||||
#!/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 is_control_ping, is_dump, is_request, is_event, is_control_ping_reply
|
||||
|
||||
|
||||
def generate_callback_facade(work_dir, model, logger):
|
||||
""" Generates callback facade """
|
||||
logger.debug("Generating JVpp callback facade for %s" % model.json_api_files)
|
||||
_generate_ifc(work_dir, model),
|
||||
_generate_impl(work_dir, model)
|
||||
_generate_callback(work_dir, model)
|
||||
|
||||
|
||||
def _generate_ifc(work_dir, model):
|
||||
with open("%s/CallbackJVpp%s.java" % (work_dir, model.plugin_java_name), "w") as f:
|
||||
f.write(_IFC_TEMPLATE.substitute(
|
||||
plugin_package=model.plugin_package,
|
||||
json_filename=model.json_api_files,
|
||||
plugin_name=model.plugin_java_name,
|
||||
methods=_generate_ifc_methods(model)
|
||||
))
|
||||
|
||||
_IFC_TEMPLATE = Template("""
|
||||
package $plugin_package.callfacade;
|
||||
|
||||
/**
|
||||
* <p>Callback Java API representation of $plugin_package plugin.
|
||||
* <br>It was generated by jvpp_callback_facade_gen.py based on $json_filename.
|
||||
*/
|
||||
public interface CallbackJVpp${plugin_name} extends io.fd.vpp.jvpp.notification.EventRegistryProvider, java.lang.AutoCloseable {
|
||||
|
||||
// TODO add send
|
||||
|
||||
$methods
|
||||
}
|
||||
""")
|
||||
|
||||
|
||||
def _generate_ifc_methods(model):
|
||||
plugin_package = model.plugin_package
|
||||
methods = []
|
||||
for msg in model.messages:
|
||||
if is_control_ping(msg):
|
||||
# Skip control ping managed by jvpp registry.
|
||||
continue
|
||||
if not (is_dump(msg) or is_request(msg)):
|
||||
# Skip replies and messages that do not not have replies (e.g events/counters).
|
||||
continue
|
||||
template = _IFC_NO_ARG_METHOD_TEMPLATE
|
||||
if msg.has_fields:
|
||||
template = _IFC_METHOD_TEMPLATE
|
||||
methods.append(template.substitute(
|
||||
name=msg.java_name_lower,
|
||||
plugin_package=plugin_package,
|
||||
request=msg.java_name_upper,
|
||||
reply=msg.reply_java
|
||||
))
|
||||
return "\n".join(methods)
|
||||
|
||||
_IFC_NO_ARG_METHOD_TEMPLATE = Template(
|
||||
""" void $name($plugin_package.callback.${reply}Callback callback) throws io.fd.vpp.jvpp.VppInvocationException;""")
|
||||
|
||||
_IFC_METHOD_TEMPLATE = Template(
|
||||
""" void $name($plugin_package.dto.$request request, $plugin_package.callback.${reply}Callback callback) throws io.fd.vpp.jvpp.VppInvocationException;""")
|
||||
|
||||
|
||||
def _generate_impl(work_dir, model):
|
||||
with open("%s/CallbackJVpp%sFacade.java" % (work_dir, model.plugin_java_name), "w") as f:
|
||||
f.write(_IMPL_TEMPLATE.substitute(
|
||||
plugin_package=model.plugin_package,
|
||||
json_filename=model.json_api_files,
|
||||
plugin_name=model.plugin_java_name,
|
||||
methods=_generate_impl_methods(model)
|
||||
))
|
||||
|
||||
_IMPL_TEMPLATE = Template("""
|
||||
package $plugin_package.callfacade;
|
||||
|
||||
/**
|
||||
* <p>Default implementation of Callback${plugin_name}JVpp interface.
|
||||
* <br>It was generated by jvpp_callback_facade_gen.py based on $json_filename.
|
||||
*/
|
||||
public final class CallbackJVpp${plugin_name}Facade implements CallbackJVpp${plugin_name} {
|
||||
|
||||
private final $plugin_package.JVpp${plugin_name} jvpp;
|
||||
private final java.util.Map<Integer, io.fd.vpp.jvpp.callback.JVppCallback> callbacks;
|
||||
private final $plugin_package.notification.${plugin_name}EventRegistryImpl eventRegistry = new $plugin_package.notification.${plugin_name}EventRegistryImpl();
|
||||
/**
|
||||
* <p>Create CallbackJVpp${plugin_name}Facade object for provided JVpp instance.
|
||||
* Constructor internally creates CallbackJVppFacadeCallback class for processing callbacks
|
||||
* and then connects to provided JVpp instance
|
||||
*
|
||||
* @param jvpp provided io.fd.vpp.jvpp.JVpp instance
|
||||
*
|
||||
* @throws java.io.IOException in case instance cannot connect to JVPP
|
||||
*/
|
||||
public CallbackJVpp${plugin_name}Facade(final io.fd.vpp.jvpp.JVppRegistry registry, final $plugin_package.JVpp${plugin_name} jvpp) throws java.io.IOException {
|
||||
this.jvpp = java.util.Objects.requireNonNull(jvpp,"jvpp is null");
|
||||
this.callbacks = new java.util.HashMap<>();
|
||||
java.util.Objects.requireNonNull(registry, "JVppRegistry should not be null");
|
||||
registry.register(jvpp, new CallbackJVpp${plugin_name}FacadeCallback(this.callbacks, eventRegistry));
|
||||
}
|
||||
|
||||
@Override
|
||||
public $plugin_package.notification.${plugin_name}EventRegistry getEventRegistry() {
|
||||
return eventRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
jvpp.close();
|
||||
}
|
||||
|
||||
// TODO add send()
|
||||
|
||||
$methods
|
||||
}
|
||||
""")
|
||||
|
||||
|
||||
def _generate_impl_methods(model):
|
||||
plugin_package = model.plugin_package
|
||||
methods = []
|
||||
for msg in model.messages:
|
||||
if is_control_ping(msg):
|
||||
# Skip control ping managed by jvpp registry.
|
||||
continue
|
||||
if not (is_dump(msg) or is_request(msg)):
|
||||
# Skip replies and messages that do not not have replies (e.g events/counters).
|
||||
continue
|
||||
template = _IMPL_NO_ARG_METHOD_TEMPLATE
|
||||
if msg.has_fields:
|
||||
template = _IMPL_METHOD_TEMPLATE
|
||||
methods.append(template.substitute(
|
||||
name=msg.java_name_lower,
|
||||
plugin_package=plugin_package,
|
||||
request=msg.java_name_upper,
|
||||
reply=msg.reply_java
|
||||
))
|
||||
return "\n".join(methods)
|
||||
|
||||
_IMPL_NO_ARG_METHOD_TEMPLATE = Template(
|
||||
""" public final void $name($plugin_package.callback.${reply}Callback callback) throws io.fd.vpp.jvpp.VppInvocationException {
|
||||
synchronized (callbacks) {
|
||||
callbacks.put(jvpp.$name(), callback);
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
||||
_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 {
|
||||
synchronized (callbacks) {
|
||||
callbacks.put(jvpp.$name(request), callback);
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
||||
|
||||
def _generate_callback(work_dir, model):
|
||||
with open("%s/CallbackJVpp%sFacadeCallback.java" % (work_dir, model.plugin_java_name), "w") as f:
|
||||
f.write(_CALLBACK_TEMPLATE.substitute(
|
||||
plugin_package=model.plugin_package,
|
||||
json_filename=model.json_api_files,
|
||||
plugin_name=model.plugin_java_name,
|
||||
methods=_generate_callback_methods(model)
|
||||
))
|
||||
|
||||
_CALLBACK_TEMPLATE = Template("""
|
||||
package $plugin_package.callfacade;
|
||||
|
||||
/**
|
||||
* <p>Implementation of JVppGlobalCallback interface for Java Callback API.
|
||||
* <br>It was generated by jvpp_callback_facade_gen.py based on $json_filename.
|
||||
*/
|
||||
public final class CallbackJVpp${plugin_name}FacadeCallback implements $plugin_package.callback.JVpp${plugin_name}GlobalCallback {
|
||||
|
||||
private final java.util.Map<Integer, io.fd.vpp.jvpp.callback.JVppCallback> requests;
|
||||
private final $plugin_package.notification.Global${plugin_name}EventCallback eventCallback;
|
||||
private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(CallbackJVpp${plugin_name}FacadeCallback.class.getName());
|
||||
|
||||
public CallbackJVpp${plugin_name}FacadeCallback(final java.util.Map<Integer, io.fd.vpp.jvpp.callback.JVppCallback> requestMap,
|
||||
final $plugin_package.notification.Global${plugin_name}EventCallback eventCallback) {
|
||||
this.requests = requestMap;
|
||||
this.eventCallback = eventCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(io.fd.vpp.jvpp.VppCallbackException reply) {
|
||||
|
||||
io.fd.vpp.jvpp.callback.JVppCallback failedCall;
|
||||
synchronized(requests) {
|
||||
failedCall = requests.remove(reply.getCtxId());
|
||||
}
|
||||
|
||||
if(failedCall != null) {
|
||||
try {
|
||||
failedCall.onError(reply);
|
||||
} catch(RuntimeException ex) {
|
||||
ex.addSuppressed(reply);
|
||||
LOG.log(java.util.logging.Level.WARNING, String.format("Callback: %s failed while handling exception: %s", failedCall, reply), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void onControlPingReply(final io.fd.vpp.jvpp.dto.ControlPingReply reply) {
|
||||
|
||||
io.fd.vpp.jvpp.callback.ControlPingCallback callback;
|
||||
final int replyId = reply.context;
|
||||
synchronized(requests) {
|
||||
callback = (io.fd.vpp.jvpp.callback.ControlPingCallback) requests.remove(replyId);
|
||||
}
|
||||
|
||||
if(callback != null) {
|
||||
callback.onControlPingReply(reply);
|
||||
}
|
||||
}
|
||||
|
||||
$methods
|
||||
}
|
||||
""")
|
||||
|
||||
|
||||
def _generate_callback_methods(model):
|
||||
plugin_package = model.plugin_package
|
||||
methods = []
|
||||
for msg in model.messages:
|
||||
if is_dump(msg) or is_request(msg):
|
||||
continue
|
||||
if is_control_ping_reply(msg):
|
||||
# Skip control ping managed by jvpp registry.
|
||||
continue
|
||||
|
||||
# Generate callbacks for all messages except for dumps and requests (handled by vpp, not client).
|
||||
template = _CALLBACK_METHOD_TEMPLATE
|
||||
if is_event(msg):
|
||||
template = _CALLBACK_EVENT_METHOD_TEMPLATE
|
||||
msg_name = msg.java_name_upper
|
||||
methods.append(template.substitute(
|
||||
message=msg_name,
|
||||
callback="%sCallback" % msg_name,
|
||||
plugin_package=plugin_package
|
||||
))
|
||||
return "\n".join(methods)
|
||||
|
||||
_CALLBACK_METHOD_TEMPLATE = Template("""
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void on${message}(final $plugin_package.dto.${message} reply) {
|
||||
|
||||
$plugin_package.callback.$callback callback;
|
||||
final int replyId = reply.context;
|
||||
if (LOG.isLoggable(java.util.logging.Level.FINE)) {
|
||||
LOG.fine(String.format("Received ${message} event message: %s", reply));
|
||||
}
|
||||
synchronized(requests) {
|
||||
callback = ($plugin_package.callback.$callback) requests.remove(replyId);
|
||||
}
|
||||
|
||||
if(callback != null) {
|
||||
callback.on${message}(reply);
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
||||
_CALLBACK_EVENT_METHOD_TEMPLATE = Template("""
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void on${message}($plugin_package.dto.${message} notification) {
|
||||
if (LOG.isLoggable(java.util.logging.Level.FINE)) {
|
||||
LOG.fine(String.format("Received ${message} event message: %s", notification));
|
||||
}
|
||||
eventCallback.on${message}(notification);
|
||||
}
|
||||
""")
|
114
extras/japi/java/jvpp/gen/jvppgen/jvpp_common_gen.py
Executable file
114
extras/japi/java/jvpp/gen/jvppgen/jvpp_common_gen.py
Executable file
@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env python2
|
||||
#
|
||||
# Copyright (c) 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 is_array
|
||||
|
||||
|
||||
def generate_fields(fields, access_modifier="public"):
|
||||
return "\n".join(_FIELD_TEMPLATE
|
||||
.substitute(access_modifier=access_modifier, type=f.type.java_name_fqn, name=f.java_name)
|
||||
for f in fields)
|
||||
|
||||
_FIELD_TEMPLATE = Template(""" ${access_modifier} ${type} ${name};""")
|
||||
|
||||
|
||||
def generate_hash_code(fields):
|
||||
if len(fields) == 1 and is_array(fields[0]):
|
||||
return _HASH_CODE_SINGLE_ARRAY_TEMPLATE.substitute(array_field=fields[0].java_name)
|
||||
return _HASH_CODE_TEMPLATE.substitute(fields=", ".join(f.java_name for f in fields))
|
||||
|
||||
_HASH_CODE_TEMPLATE = Template("""
|
||||
@Override
|
||||
@io.fd.vpp.jvpp.coverity.SuppressFBWarnings("UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD")
|
||||
public int hashCode() {
|
||||
return java.util.Objects.hash($fields);
|
||||
}""")
|
||||
|
||||
_HASH_CODE_SINGLE_ARRAY_TEMPLATE = Template("""
|
||||
@Override
|
||||
@io.fd.vpp.jvpp.coverity.SuppressFBWarnings("UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD")
|
||||
public int hashCode() {
|
||||
return java.util.Arrays.hashCode($array_field);
|
||||
}""")
|
||||
|
||||
|
||||
def generate_equals(class_name, fields):
|
||||
comparisons = []
|
||||
for f in fields:
|
||||
if is_array(f):
|
||||
comparisons.append(_EQUALS_ARRAY_FIELD_TEMPLATE.substitute(field_name=f.java_name))
|
||||
else:
|
||||
comparisons.append(_EQUALS_FIELD_TEMPLATE.substitute(field_name=f.java_name))
|
||||
|
||||
if comparisons:
|
||||
comparisons.insert(0, _EQUALS_OTHER_TEMPLATE.substitute(cls_name=class_name))
|
||||
return _EQUALS_TEMPLATE.substitute(comparisons="\n".join(comparisons))
|
||||
|
||||
_EQUALS_TEMPLATE = Template("""
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
$comparisons
|
||||
|
||||
return true;
|
||||
}""")
|
||||
|
||||
_EQUALS_OTHER_TEMPLATE = Template("""
|
||||
final $cls_name other = ($cls_name) o;
|
||||
""")
|
||||
|
||||
_EQUALS_FIELD_TEMPLATE = Template(""" if (!java.util.Objects.equals(this.$field_name, other.$field_name)) {
|
||||
return false;
|
||||
}""")
|
||||
|
||||
_EQUALS_ARRAY_FIELD_TEMPLATE = Template(""" if (!java.util.Arrays.equals(this.$field_name, other.$field_name)) {
|
||||
return false;
|
||||
}""")
|
||||
|
||||
|
||||
def generate_to_string(class_name, fields):
|
||||
to_string = []
|
||||
for f in fields:
|
||||
if is_array(f):
|
||||
to_string.append(_TO_STRING_ARRAY_FIELD_TEMPLATE.substitute(field_name=f.java_name))
|
||||
else:
|
||||
to_string.append(_TO_STRING_FIELD_TEMPLATE.substitute(field_name=f.java_name))
|
||||
|
||||
to_string_fields = " \"}\";"
|
||||
if to_string:
|
||||
to_string_fields = " + \", \" +\n".join(to_string) + " + \"}\";"
|
||||
|
||||
return _TO_STRING_TEMPLATE.substitute(
|
||||
class_name=class_name,
|
||||
to_string_fields=to_string_fields
|
||||
)
|
||||
|
||||
_TO_STRING_TEMPLATE = Template("""
|
||||
@Override
|
||||
public String toString() {
|
||||
return "$class_name{" +
|
||||
$to_string_fields
|
||||
}""")
|
||||
|
||||
_TO_STRING_FIELD_TEMPLATE = Template(""" \"$field_name=\" + $field_name""")
|
||||
|
||||
_TO_STRING_ARRAY_FIELD_TEMPLATE = Template(
|
||||
""" \"$field_name=\" + java.util.Arrays.toString($field_name)""")
|
338
extras/japi/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py
Normal file
338
extras/japi/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py
Normal file
File diff suppressed because it is too large
Load Diff
71
extras/japi/java/jvpp/gen/jvppgen/jvpp_ifc_gen.py
Executable file
71
extras/japi/java/jvpp/gen/jvppgen/jvpp_ifc_gen.py
Executable file
@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env python2
|
||||
#
|
||||
# Copyright (c) 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 is_request, is_dump, is_event
|
||||
|
||||
|
||||
def generate_java_ifc(work_dir, model, logger):
|
||||
logger.debug("Generating JVpp interface for %s" % model.json_api_files)
|
||||
messages = filter(_jvpp_ifc_filter, model.messages)
|
||||
plugin_package = model.plugin_package
|
||||
methods = []
|
||||
for msg in messages:
|
||||
if msg.has_fields:
|
||||
methods.append(_JVPP_IFC_METHOD_TEMPLATE.substitute(
|
||||
name=msg.java_name_lower,
|
||||
plugin_package=plugin_package,
|
||||
type=msg.java_name_upper))
|
||||
else:
|
||||
methods.append(_JVPP_IFC_NO_ARG_METHOD_TEMPLATE.substitute(name=msg.java_name_lower))
|
||||
|
||||
plugin_name = model.plugin_java_name
|
||||
jvpp_interface = _JVPP_IFC_TEMPLATE.substitute(
|
||||
plugin_package=plugin_package,
|
||||
json_filename=model.json_api_files,
|
||||
plugin_name=plugin_name,
|
||||
methods="\n".join(methods)
|
||||
)
|
||||
with open("%s/JVpp%s.java" % (work_dir, plugin_name), "w") as f:
|
||||
f.write(jvpp_interface)
|
||||
|
||||
|
||||
def _jvpp_ifc_filter(msg):
|
||||
return is_request(msg) or is_dump(msg) or is_event(msg)
|
||||
|
||||
|
||||
_JVPP_IFC_METHOD_TEMPLATE = Template(
|
||||
""" int $name($plugin_package.dto.$type request) throws io.fd.vpp.jvpp.VppInvocationException;""")
|
||||
|
||||
_JVPP_IFC_NO_ARG_METHOD_TEMPLATE = Template(""" int $name() throws io.fd.vpp.jvpp.VppInvocationException;""")
|
||||
|
||||
_JVPP_IFC_TEMPLATE = Template("""package $plugin_package;
|
||||
|
||||
/**
|
||||
* <p>Java representation of plugin's api file.
|
||||
* <br>It was generated by jvpp_impl_gen.py based on $json_filename.
|
||||
* <br>(python representation of api file generated by vppapigen)
|
||||
*/
|
||||
public interface JVpp${plugin_name} extends io.fd.vpp.jvpp.JVpp {
|
||||
/**
|
||||
* Generic dispatch method for sending requests to VPP
|
||||
*
|
||||
* @throws io.fd.vpp.jvpp.VppInvocationException if send request had failed
|
||||
*/
|
||||
int send(io.fd.vpp.jvpp.dto.JVppRequest request) throws io.fd.vpp.jvpp.VppInvocationException;
|
||||
$methods
|
||||
}
|
||||
""")
|
173
extras/japi/java/jvpp/gen/jvppgen/jvpp_impl_gen.py
Executable file
173
extras/japi/java/jvpp/gen/jvppgen/jvpp_impl_gen.py
Executable file
@ -0,0 +1,173 @@
|
||||
#!/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 is_request, is_dump, is_event
|
||||
|
||||
|
||||
def generate_java_impl(work_dir, model, logger):
|
||||
logger.debug("Generating JVpp implementation for %s" % model.json_api_files)
|
||||
messages = filter(_jvpp_impl_filter, model.messages)
|
||||
plugin_package = model.plugin_package
|
||||
methods = []
|
||||
for msg in messages:
|
||||
if msg.has_fields:
|
||||
methods.append(_JVPP_IMPL_METHOD_TEMPLATE.substitute(
|
||||
name=msg.java_name_lower,
|
||||
plugin_package=plugin_package,
|
||||
type=msg.java_name_upper))
|
||||
else:
|
||||
methods.append(_JVPP_IMPL_NO_ARG_METHOD_TEMPLATE.substitute(
|
||||
name=msg.java_name_lower,
|
||||
type=msg.java_name_upper))
|
||||
|
||||
plugin_name = model.plugin_java_name
|
||||
jvpp_impl = _JVPP_IMPL_TEMPLATE.substitute(
|
||||
plugin_package=plugin_package,
|
||||
json_filename=model.json_api_files,
|
||||
plugin_name=model.plugin_java_name,
|
||||
plugin_name_underscore=model.plugin_name,
|
||||
methods="\n".join(methods))
|
||||
|
||||
with open("%s/JVpp%sImpl.java" % (work_dir, plugin_name), "w") as f:
|
||||
f.write(jvpp_impl)
|
||||
|
||||
|
||||
def _jvpp_impl_filter(msg):
|
||||
return is_request(msg) or is_dump(msg) or is_event(msg)
|
||||
|
||||
|
||||
_JVPP_IMPL_TEMPLATE = Template("""package $plugin_package;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.nio.file.attribute.PosixFilePermissions;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.logging.Level;
|
||||
import io.fd.vpp.jvpp.callback.JVppCallback;
|
||||
import io.fd.vpp.jvpp.VppConnection;
|
||||
import io.fd.vpp.jvpp.JVppRegistry;
|
||||
|
||||
/**
|
||||
* <p>Default implementation of JVpp interface.
|
||||
* <br>It was generated by jvpp_impl_gen.py based on $json_filename.
|
||||
* <br>(python representation of api file generated by vppapigen)
|
||||
*/
|
||||
public final class JVpp${plugin_name}Impl implements $plugin_package.JVpp${plugin_name} {
|
||||
|
||||
private final static Logger LOG = Logger.getLogger(JVpp${plugin_name}Impl.class.getName());
|
||||
private static final String LIBNAME = "libjvpp_${plugin_name_underscore}.so";
|
||||
|
||||
// FIXME using NativeLibraryLoader makes load fail could not find (WantInterfaceEventsReply).
|
||||
static {
|
||||
try {
|
||||
loadLibrary();
|
||||
} catch (Exception e) {
|
||||
LOG.severe("Can't find jvpp jni library: " + LIBNAME);
|
||||
throw new ExceptionInInitializerError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadStream(final InputStream is) throws IOException {
|
||||
final Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rwxr-x---");
|
||||
final Path p = Files.createTempFile(LIBNAME, null, PosixFilePermissions.asFileAttribute(perms));
|
||||
try {
|
||||
Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING);
|
||||
|
||||
try {
|
||||
Runtime.getRuntime().load(p.toString());
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
throw new IOException("Failed to load library " + p, e);
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
Files.deleteIfExists(p);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadLibrary() throws IOException {
|
||||
try (final InputStream is = JVpp${plugin_name}Impl.class.getResourceAsStream('/' + LIBNAME)) {
|
||||
if (is == null) {
|
||||
throw new IOException("Failed to open library resource " + LIBNAME);
|
||||
}
|
||||
loadStream(is);
|
||||
}
|
||||
}
|
||||
|
||||
private VppConnection connection;
|
||||
private JVppRegistry registry;
|
||||
|
||||
private static native void init0(final JVppCallback callback, final long queueAddress, final int clientIndex);
|
||||
@Override
|
||||
public void init(final JVppRegistry registry, final JVppCallback callback, final long queueAddress, final int clientIndex) {
|
||||
this.registry = java.util.Objects.requireNonNull(registry, "registry should not be null");
|
||||
this.connection = java.util.Objects.requireNonNull(registry.getConnection(), "connection should not be null");
|
||||
connection.checkActive();
|
||||
init0(callback, queueAddress, clientIndex);
|
||||
}
|
||||
|
||||
private static native void close0();
|
||||
@Override
|
||||
public void close() {
|
||||
close0();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int send(io.fd.vpp.jvpp.dto.JVppRequest request) throws io.fd.vpp.jvpp.VppInvocationException {
|
||||
return request.send(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int controlPing(final io.fd.vpp.jvpp.dto.ControlPing controlPing) throws io.fd.vpp.jvpp.VppInvocationException {
|
||||
return registry.controlPing(JVpp${plugin_name}Impl.class);
|
||||
}
|
||||
$methods
|
||||
}
|
||||
""")
|
||||
|
||||
_JVPP_IMPL_METHOD_TEMPLATE = Template("""
|
||||
private static native int ${name}0($plugin_package.dto.$type request);
|
||||
public final int $name($plugin_package.dto.$type request) throws io.fd.vpp.jvpp.VppInvocationException {
|
||||
java.util.Objects.requireNonNull(request, "Null request object");
|
||||
connection.checkActive();
|
||||
if (LOG.isLoggable(Level.FINE)) {
|
||||
LOG.fine(String.format("Sending $type event message: %s", request));
|
||||
}
|
||||
int result=${name}0(request);
|
||||
if (result<0){
|
||||
throw new io.fd.vpp.jvpp.VppInvocationException("${name}", result);
|
||||
}
|
||||
return result;
|
||||
}""")
|
||||
|
||||
_JVPP_IMPL_NO_ARG_METHOD_TEMPLATE = Template("""
|
||||
private static native int ${name}0() throws io.fd.vpp.jvpp.VppInvocationException;
|
||||
public final int $name() throws io.fd.vpp.jvpp.VppInvocationException {
|
||||
connection.checkActive();
|
||||
LOG.fine("Sending $type event message");
|
||||
int result=${name}0();
|
||||
if(result<0){
|
||||
throw new io.fd.vpp.jvpp.VppInvocationException("${name}", result);
|
||||
}
|
||||
return result;
|
||||
}""")
|
570
extras/japi/java/jvpp/gen/jvppgen/jvpp_model.py
Executable file
570
extras/japi/java/jvpp/gen/jvppgen/jvpp_model.py
Executable file
File diff suppressed because it is too large
Load Diff
226
extras/japi/java/jvpp/gen/jvppgen/notification_gen.py
Normal file
226
extras/japi/java/jvpp/gen/jvppgen/notification_gen.py
Normal file
@ -0,0 +1,226 @@
|
||||
#!/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 is_control_ping, is_control_ping_reply, is_dump, is_request
|
||||
|
||||
|
||||
def generate_notifications(work_dir, model, logger):
|
||||
""" Generates notification registry interface and implementation """
|
||||
logger.debug("Generating Notification interfaces and implementation for %s" % model.json_api_files)
|
||||
messages = filter(_notification_filter, model.messages)
|
||||
_generate_global_event_callback(work_dir, model, messages)
|
||||
_generate_event_registry(work_dir, model, messages)
|
||||
_generate_event_registry_impl(work_dir, model, messages)
|
||||
_generate_event_registry_provider(work_dir, model)
|
||||
|
||||
|
||||
def _notification_filter(msg):
|
||||
# Generate callbacks for all messages except for dumps and requests (handled by vpp, not client).
|
||||
# Also skip control ping managed by jvpp registry.
|
||||
return (not is_control_ping(msg)) and \
|
||||
(not is_control_ping_reply(msg)) and \
|
||||
(not is_dump(msg)) and \
|
||||
(not is_request(msg))
|
||||
|
||||
|
||||
def _generate_event_registry(work_dir, model, messages):
|
||||
plugin_name = model.plugin_java_name
|
||||
plugin_package = model.plugin_package
|
||||
|
||||
register_callback_methods = []
|
||||
for msg in messages:
|
||||
name = _callback_name(msg)
|
||||
fqn_name = _fqn_callback_name(plugin_package, name)
|
||||
# TODO create NotificationListenerRegistration and return that instead of AutoCloseable to better indicate
|
||||
# that the registration should be closed
|
||||
register_callback_methods.append(" java.lang.AutoCloseable register%s(%s callback);" % (name, fqn_name))
|
||||
|
||||
with open("%s/%sEventRegistry.java" % (work_dir, plugin_name), "w") as f:
|
||||
f.write(_EVENT_REGISTRY_TEMPLATE.substitute(
|
||||
plugin_package=plugin_package,
|
||||
plugin_name=plugin_name,
|
||||
json_filename=model.json_api_files,
|
||||
register_callback_methods="\n".join(register_callback_methods)
|
||||
))
|
||||
|
||||
_EVENT_REGISTRY_TEMPLATE = Template("""
|
||||
package $plugin_package.notification;
|
||||
|
||||
/**
|
||||
* <p>Registry for notification callbacks defined in ${plugin_name}.
|
||||
* <br>It was generated by notification_gen.py based on $json_filename.
|
||||
*/
|
||||
public interface ${plugin_name}EventRegistry extends io.fd.vpp.jvpp.notification.EventRegistry {
|
||||
|
||||
$register_callback_methods
|
||||
|
||||
@Override
|
||||
void close();
|
||||
}
|
||||
""")
|
||||
|
||||
|
||||
def _generate_event_registry_impl(work_dir, model, messages):
|
||||
plugin_name = model.plugin_java_name
|
||||
plugin_package = model.plugin_package
|
||||
|
||||
register_callback_methods = []
|
||||
handler_methods = []
|
||||
for msg in messages:
|
||||
notification = msg.java_name_upper
|
||||
callback = "%sCallback" % notification
|
||||
register_callback_methods.append(_REGISTER_CALLBACK_IMPL_TEMPLATE.substitute(
|
||||
plugin_package=plugin_package,
|
||||
notification=notification,
|
||||
callback=callback
|
||||
))
|
||||
handler_methods.append(_HANDLER_IMPL_TEMPLATE.substitute(
|
||||
plugin_package=plugin_package,
|
||||
notification=notification,
|
||||
callback=callback
|
||||
))
|
||||
|
||||
with open("%s/%sEventRegistryImpl.java" % (work_dir, plugin_name), "w") as f:
|
||||
f.write(_EVENT_REGISTRY_IMPL_TEMPLATE.substitute(
|
||||
plugin_package=plugin_package,
|
||||
plugin_name=plugin_name,
|
||||
json_filename=model.json_api_files,
|
||||
register_callback_methods="".join(register_callback_methods),
|
||||
handler_methods="".join(handler_methods)
|
||||
))
|
||||
|
||||
_REGISTER_CALLBACK_IMPL_TEMPLATE = Template("""
|
||||
public java.lang.AutoCloseable register$callback(final $plugin_package.callback.$callback callback){
|
||||
if(null != registeredCallbacks.putIfAbsent($plugin_package.dto.$notification.class, callback)){
|
||||
throw new IllegalArgumentException("Callback for " + $plugin_package.dto.$notification.class +
|
||||
"notification already registered");
|
||||
}
|
||||
return () -> registeredCallbacks.remove($plugin_package.dto.$notification.class);
|
||||
}
|
||||
""")
|
||||
|
||||
_HANDLER_IMPL_TEMPLATE = Template("""
|
||||
@Override
|
||||
public void on$notification(
|
||||
final $plugin_package.dto.$notification notification) {
|
||||
if (LOG.isLoggable(java.util.logging.Level.FINE)) {
|
||||
LOG.fine(String.format("Received $notification event message: %s", notification));
|
||||
}
|
||||
final io.fd.vpp.jvpp.callback.JVppCallback jVppCallback = registeredCallbacks.get($plugin_package.dto.$notification.class);
|
||||
if (null != jVppCallback) {
|
||||
(($plugin_package.callback.$callback) registeredCallbacks
|
||||
.get($plugin_package.dto.$notification.class))
|
||||
.on$notification(notification);
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
||||
_EVENT_REGISTRY_IMPL_TEMPLATE = Template("""
|
||||
package $plugin_package.notification;
|
||||
|
||||
/**
|
||||
* <p>Notification registry delegating notification processing to registered callbacks.
|
||||
* <br>It was generated by notification_gen.py based on $json_filename.
|
||||
*/
|
||||
public final class ${plugin_name}EventRegistryImpl implements ${plugin_name}EventRegistry, Global${plugin_name}EventCallback {
|
||||
|
||||
// TODO add a special NotificationCallback interface and only allow those to be registered
|
||||
private final java.util.concurrent.ConcurrentMap<Class<?>, io.fd.vpp.jvpp.callback.JVppCallback> registeredCallbacks =
|
||||
new java.util.concurrent.ConcurrentHashMap<>();
|
||||
private static java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(${plugin_name}EventRegistryImpl.class.getName());
|
||||
|
||||
$register_callback_methods
|
||||
$handler_methods
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
registeredCallbacks.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(io.fd.vpp.jvpp.VppCallbackException ex) {
|
||||
java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(${plugin_name}EventRegistryImpl.class.getName());
|
||||
LOG.log(java.util.logging.Level.WARNING, String.format("Received onError exception: call=%s, context=%d, retval=%d%n", ex.getMethodName(),
|
||||
ex.getCtxId(), ex.getErrorCode()), ex);
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
||||
|
||||
def _generate_global_event_callback(work_dir, model, messages):
|
||||
plugin_name = model.plugin_java_name
|
||||
plugin_package = model.plugin_package
|
||||
|
||||
callbacks = ""
|
||||
callback_list = []
|
||||
for msg in messages:
|
||||
fqn_name = _fqn_callback_name(plugin_package, _callback_name(msg))
|
||||
callback_list.append(fqn_name)
|
||||
|
||||
if callback_list:
|
||||
callbacks = " extends %s" % ", ".join(callback_list)
|
||||
|
||||
with open("%s/Global%sEventCallback.java" % (work_dir, plugin_name), "w") as f:
|
||||
f.write(_GLOBAL_EVENT_CALLBACK_TEMPLATE.substitute(
|
||||
plugin_package=plugin_package,
|
||||
plugin_name=plugin_name,
|
||||
json_filename=model.json_api_files,
|
||||
callbacks=callbacks
|
||||
))
|
||||
|
||||
_GLOBAL_EVENT_CALLBACK_TEMPLATE = Template("""
|
||||
package $plugin_package.notification;
|
||||
|
||||
/**
|
||||
* <p>Aggregated callback interface for notifications only.
|
||||
* <br>It was generated by notification_gen.py based on $json_filename.
|
||||
*/
|
||||
public interface Global${plugin_name}EventCallback$callbacks {
|
||||
|
||||
}
|
||||
""")
|
||||
|
||||
|
||||
def _generate_event_registry_provider(work_dir, model):
|
||||
plugin_name = model.plugin_java_name
|
||||
with open("%s/%sEventRegistryProvider.java" % (work_dir, plugin_name), "w") as f:
|
||||
f.write(_EVENT_REGISTRY_PROVIDER_TEMPLATE.substitute(
|
||||
plugin_package=model.plugin_package,
|
||||
plugin_name=plugin_name,
|
||||
json_filename=model.json_api_files
|
||||
))
|
||||
|
||||
_EVENT_REGISTRY_PROVIDER_TEMPLATE = Template("""
|
||||
package $plugin_package.notification;
|
||||
|
||||
/**
|
||||
* Provides ${plugin_name}EventRegistry.
|
||||
* <br>The file was generated by notification_gen.py based on $json_filename.
|
||||
*/
|
||||
public interface ${plugin_name}EventRegistryProvider extends io.fd.vpp.jvpp.notification.EventRegistryProvider {
|
||||
|
||||
@Override
|
||||
public ${plugin_name}EventRegistry getEventRegistry();
|
||||
}
|
||||
""")
|
||||
|
||||
|
||||
def _callback_name(msg):
|
||||
return "%sCallback" % msg.java_name_upper
|
||||
|
||||
|
||||
def _fqn_callback_name(plugin_package, callback_name):
|
||||
return "%s.callback.%s" % (plugin_package, callback_name)
|
60
extras/japi/java/jvpp/gen/jvppgen/types_gen.py
Executable file
60
extras/japi/java/jvpp/gen/jvppgen/types_gen.py
Executable file
@ -0,0 +1,60 @@
|
||||
#!/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_common_gen import generate_hash_code, generate_equals, generate_to_string, generate_fields
|
||||
from jvpp_model import Class
|
||||
|
||||
|
||||
def generate_types(work_dir, model, logger):
|
||||
logger.debug("Generating custom types for %s " % model.json_api_files)
|
||||
|
||||
for t in model.types:
|
||||
if not isinstance(t, Class):
|
||||
continue
|
||||
logger.debug("Generating DTO for type %s", t)
|
||||
type_class_name = t.java_name
|
||||
fields = t.fields
|
||||
type_class = _TYPE_TEMPLATE.substitute(
|
||||
plugin_package=model.plugin_package,
|
||||
c_type_name=t.name,
|
||||
json_filename=model.json_api_files,
|
||||
json_definition=t.doc,
|
||||
java_type_name=type_class_name,
|
||||
fields=generate_fields(fields),
|
||||
hash_code=generate_hash_code(fields),
|
||||
equals=generate_equals(type_class_name, fields),
|
||||
to_string=generate_to_string(type_class_name, fields)
|
||||
)
|
||||
with open("%s/%s.java" % (work_dir, type_class_name), "w") as f:
|
||||
f.write(type_class)
|
||||
|
||||
_TYPE_TEMPLATE = Template("""
|
||||
package $plugin_package.types;
|
||||
|
||||
/**
|
||||
* <p>This class represents $c_type_name type definition.
|
||||
* <br>It was generated by jvpp_types_gen.py based on $json_filename:
|
||||
* <pre>
|
||||
$json_definition
|
||||
* </pre>
|
||||
*/
|
||||
public final class $java_type_name {
|
||||
$fields
|
||||
$hash_code
|
||||
$equals
|
||||
$to_string
|
||||
}
|
||||
""")
|
98
extras/japi/java/jvpp/gen/jvppgen/unions_gen.py
Executable file
98
extras/japi/java/jvpp/gen/jvppgen/unions_gen.py
Executable file
@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env python2
|
||||
#
|
||||
# Copyright (c) 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_common_gen import generate_hash_code, generate_equals, generate_to_string, generate_fields
|
||||
from jvpp_model import Union
|
||||
|
||||
|
||||
def generate_unions(work_dir, model, logger):
|
||||
logger.debug("Generating unions for %s " % model.json_api_files)
|
||||
|
||||
for t in model.types:
|
||||
if not isinstance(t, Union):
|
||||
continue
|
||||
logger.debug("Generating DTO for union %s", t)
|
||||
java_union_name = t.java_name
|
||||
fields = t.fields
|
||||
type_class = _UNION_TEMPLATE.substitute(
|
||||
plugin_package=model.plugin_package,
|
||||
c_type_name=t.name,
|
||||
json_filename=model.json_api_files,
|
||||
json_definition=t.doc,
|
||||
java_union_name=java_union_name,
|
||||
fields=generate_fields(fields, access_modifier="private"),
|
||||
constructors=_generate_constructors(java_union_name, fields),
|
||||
getters=_generate_getters(fields),
|
||||
hash_code=generate_hash_code(fields),
|
||||
equals=generate_equals(java_union_name, fields),
|
||||
to_string=generate_to_string(java_union_name, fields)
|
||||
)
|
||||
with open("%s/%s.java" % (work_dir, java_union_name), "w") as f:
|
||||
f.write(type_class)
|
||||
|
||||
_UNION_TEMPLATE = Template("""
|
||||
package ${plugin_package}.types;
|
||||
|
||||
/**
|
||||
* <p>This class represents ${c_type_name} union definition.
|
||||
* <br>It was generated by unions_gen.py based on ${json_filename}:
|
||||
* <pre>
|
||||
${json_definition}
|
||||
* </pre>
|
||||
*/
|
||||
public class ${java_union_name} {
|
||||
private final int _activeMember;
|
||||
${fields}
|
||||
private ${java_union_name}() {
|
||||
// Constructor for JNI usage. All members can be read.
|
||||
_activeMember = -1;
|
||||
}
|
||||
${constructors}
|
||||
${getters}
|
||||
${hash_code}
|
||||
${equals}
|
||||
${to_string}
|
||||
}
|
||||
""")
|
||||
|
||||
|
||||
def _generate_constructors(union_name, fields):
|
||||
return "".join(
|
||||
_CONSTRUCTOR_TEMPLATE
|
||||
.substitute(union_name=union_name,
|
||||
field_type=f.type.java_name_fqn,
|
||||
field_name=f.java_name,
|
||||
field_index=i) for i, f in enumerate(fields))
|
||||
|
||||
_CONSTRUCTOR_TEMPLATE = Template("""
|
||||
public ${union_name}(${field_type} ${field_name}) {
|
||||
this.${field_name} = java.util.Objects.requireNonNull(${field_name}, "${field_name} should not be null");
|
||||
_activeMember = $field_index;
|
||||
}""")
|
||||
|
||||
|
||||
def _generate_getters(fields):
|
||||
return "".join(_GETTER_TEMPLATE.substitute(
|
||||
type=f.type.java_name_fqn,
|
||||
getter_name=f.java_name_upper,
|
||||
field_name=f.java_name
|
||||
) for f in fields)
|
||||
|
||||
_GETTER_TEMPLATE = Template("""
|
||||
public ${type} get${getter_name}() {
|
||||
return ${field_name};
|
||||
}""")
|
Reference in New Issue
Block a user