VPP-205: jvpp plugin support.
Splits jvpp into two jars jvpp-registry.jar - base jvpp functionality jvpp-core.jar - Java wrapper for vpe.api Plugins can be generated the same way jvpp-core.jar is. Example (nsh): https://gerrit.fd.io/r/#/c/2118/ Change-Id: I2254f90b2c3e423563bb91bf70877979f1e90a7d Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
This commit is contained in:

committed by
Dave Wallace

parent
f4691cd7be
commit
66ea26b1bc
@ -1,201 +0,0 @@
|
||||
= JVpp
|
||||
|
||||
JVpp is JNI based Java API for VPP.
|
||||
|
||||
== Features
|
||||
It is:
|
||||
|
||||
* Asynchronous
|
||||
* Fully generated
|
||||
* Lightweight
|
||||
|
||||
== Architecture
|
||||
JVpp and JNI
|
||||
|
||||
|
||||
JVpp Java
|
||||
|
||||
/----------\ /--------\ /------------\ /------\
|
||||
| VppConn* | | JVpp | | Callbacks | | DTOs |
|
||||
\----+-----/ \----+---/ \------+-----/ \------/
|
||||
^ ^ ^
|
||||
| implements | implements | implements
|
||||
/----+---------\ /----+-------\ /------+-----------\
|
||||
| VppConnImpl* +<--------+ JVppImpl | | GlobalCallback |
|
||||
\--------------/ uses \---+--------/ \-------+----------/
|
||||
| ^
|
||||
| uses | calls back
|
||||
| |
|
||||
-------------------------------|-----------------------|---------------------
|
||||
| |
|
||||
| +---------------+
|
||||
C JNI | |
|
||||
v | /------------\
|
||||
/---+-------+--\ +---->+ jvpp.h* |
|
||||
| +-----+ \------------/
|
||||
| jvpp.c* |
|
||||
| +-----+ /------------\
|
||||
\--------------/ +---->+ jvpp_gen.h |
|
||||
\------------/
|
||||
|
||||
* Components marked with an asterisk contain manually crafted Java code, which in addition
|
||||
to generated classes form jvpp. Exception applies to Callbacks and DTOs, since there are
|
||||
manually crafted marker interfaces in callback and dto package (dto/JVppRequest, dto/JVppReply,
|
||||
dto/JVppDump, dto/JVppReplyDump, callback/JVppCallback)
|
||||
|
||||
Note: jvpp.c calls back the GlobalCallback instance with every response. An instance of the
|
||||
GlobalCallback is provided to jvpp.c by VppConnImpl while connecting to VPP.
|
||||
|
||||
Part of the JVpp is also Future facade. It is asynchronous API returning Future objects
|
||||
on top of low level JVpp.
|
||||
|
||||
|
||||
Future facade
|
||||
|
||||
/-------------\ /--------------------\
|
||||
| FutureJVpp* | +-->+ FutureJVppRegistry |
|
||||
\-----+-------/ | \----------+---------/
|
||||
^ | ^
|
||||
| implements | uses | uses
|
||||
| | |
|
||||
/--------+----------\ | /----------+---------\
|
||||
| FutureJVppFacade* +----+ | FutureJVppCallback |
|
||||
\---------+---------/ \----------+---------/
|
||||
| |
|
||||
---------------|-----------------------------|-------------------------------
|
||||
| uses | implements
|
||||
JVpp Java | |
|
||||
| |
|
||||
/---------\ | |
|
||||
| JVpp +<--+ |
|
||||
\----+----/ |
|
||||
^ |
|
||||
| implements v
|
||||
/----+-------\ /----------+-------\
|
||||
| JVppImpl | | GlobalCallback |
|
||||
\------------/ \------------------/
|
||||
|
||||
|
||||
|
||||
Another useful utility of the JVpp is Callback facade. It is asynchronous API
|
||||
capable of calling specific callback instance (provided when performing a call)
|
||||
per call.
|
||||
|
||||
|
||||
Callback facade
|
||||
|
||||
/--------------\ /----------------------\
|
||||
| CallbackJVpp | +-->+ CallbackJVppRegistry |
|
||||
\-----+--------/ | \----------+-----------/
|
||||
^ | ^
|
||||
| implements | uses | uses
|
||||
| | |
|
||||
/--------+-----------\ | /----------+-----------\
|
||||
| CallbackJVppFacade +-----+ | CallbackJVppCallback |
|
||||
\---------+----------/ \----------+-----------/
|
||||
| |
|
||||
---------------|-----------------------------|-------------------------------
|
||||
| uses | implements
|
||||
JVpp Java | |
|
||||
| |
|
||||
/---------\ | |
|
||||
| JVpp +<--+ |
|
||||
\----+----/ |
|
||||
^ |
|
||||
| implements v
|
||||
/----+-------\ /----------+-------\
|
||||
| JVppImpl | | GlobalCallback |
|
||||
\------------/ \------------------/
|
||||
|
||||
|
||||
|
||||
== Package structure
|
||||
|
||||
* *org.openvpp.jvpp* - top level package for generated JVpp interface+ implementation and hand-crafted
|
||||
VppConnection interface + implementation
|
||||
|
||||
** *dto* - package for DTOs generated from VPP API structures + base/marker hand-crafted interfaces
|
||||
** *callback* - package for low-level JVpp callbacks and a global callback interface implementing each of the low-level JVppcallbacks
|
||||
** *future* - package for future based facade on top of JVpp and callbacks
|
||||
** *callfacade* - package for callback based facade on top of JVpp and callbacks. Allowing
|
||||
users to provide callback per request
|
||||
** *test* - package for JVpp standalone tests. Can also serve as samples for JVpp.
|
||||
|
||||
C code is structured into 3 files:
|
||||
|
||||
* *jvpp.c* - includes jvpp.h and jvpp_gen.h + contains hand crafted code for:
|
||||
|
||||
** VPP connection open/close
|
||||
** Rx thread to java thread attach
|
||||
** Callback instance store
|
||||
* *jvpp.h* - contains hand-crafted macros and structures used by jvpp.c
|
||||
* *jvpp_gen.h* - contains JNI compatible handlers for each VPP request and reply
|
||||
|
||||
== Code generators
|
||||
All of the required code except the base/marker interfaces is generated using
|
||||
simple python2 code generators. The generators use __defs_vpp_papi.py__ input
|
||||
file produced by __vppapigen__ from vpe.api file.
|
||||
|
||||
=== JNI compatible C code
|
||||
Produces __jvpp_gen.h__ file containing JNI compatible handlers for each VPP
|
||||
request and reply.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Source: jvpp_c_gen.py
|
||||
====
|
||||
|
||||
=== Request/Reply DTOs
|
||||
For all the structures in __defs_vpp_papi.py__ a POJO DTO is produced. Logically,
|
||||
there are 4 types of DTOs:
|
||||
|
||||
* Request - requests that can be sent to VPP and only a single response is expected
|
||||
* DumpRequest - requests that can be sent to VPP and a stream of responses is expected
|
||||
* Reply - reply to a simple request or a single response from dump triggered response stream
|
||||
* ReplyDump - collection of replies from a single dump request
|
||||
* Notifications/Events - Not implemented yet
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Source: dto_gen.py
|
||||
====
|
||||
|
||||
=== JVpp
|
||||
Produces __JVpp.java__ and __JVppImpl.java__. This is the layer right above JNI compatible C
|
||||
code.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Source: jvpp_impl_gen.py
|
||||
====
|
||||
|
||||
=== Callbacks
|
||||
Produces callback interface for each VPP reply + a global callback interface called
|
||||
__JVppGlobalCallback.java__ aggregating all of the callback interfaces. The JNI
|
||||
compatible C code expects only a single instance of this global callback and calls
|
||||
it with every reply.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Source: callback_gen.py
|
||||
====
|
||||
|
||||
=== Future facade
|
||||
Produces an asynchronous facade on top of JVpp and callbacks, which returns a Future that provides
|
||||
matching reply once VPP invocation finishes. Sources produced:
|
||||
__FutureJVpp.java, FutureJVppFacade.java and FutureJVppCallback.java__
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Source: jvpp_future_facade_gen.py
|
||||
====
|
||||
|
||||
=== Callback facade
|
||||
Similar to future facade, only this facade takes callback objects as part of the invocation
|
||||
and the callback is called with result once VPP invocation finishes. Sources produced:
|
||||
__CallbackJVpp.java, CallbackJVppFacade.java and CallbackJVppCallback.java__
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Source: jvpp_callback_facade_gen.py
|
||||
====
|
@ -41,7 +41,8 @@ from jvppgen.util import vpp_2_jni_type_mapping
|
||||
|
||||
parser = argparse.ArgumentParser(description='VPP Java API generator')
|
||||
parser.add_argument('-i', action="store", dest="inputfile")
|
||||
parser.add_argument('--base_package', action="store", dest="base_package", default='org.openvpp.jvpp')
|
||||
parser.add_argument('--plugin_name', action="store", dest="plugin_name")
|
||||
parser.add_argument('--control_ping_class', action="store", dest="control_ping_class", default="ControlPing")
|
||||
args = parser.parse_args()
|
||||
|
||||
sys.path.append(".")
|
||||
@ -52,7 +53,10 @@ print "importdir %s" % importdir
|
||||
inputfile = os.path.basename(args.inputfile)
|
||||
inputfile = inputfile.replace('.py', '')
|
||||
print "inputfile %s" % inputfile
|
||||
base_package = args.base_package
|
||||
plugin_name = args.plugin_name
|
||||
print "plugin_name %s" % plugin_name
|
||||
control_ping_class = args.control_ping_class
|
||||
print "control_ping_class %s" % control_ping_class
|
||||
sys.path.append(importdir)
|
||||
cfg = importlib.import_module(inputfile, package=None)
|
||||
|
||||
@ -133,17 +137,20 @@ def get_definitions():
|
||||
|
||||
func_list, func_name = get_definitions()
|
||||
|
||||
base_package = 'org.openvpp.jvpp'
|
||||
plugin_package = base_package + '.' + plugin_name
|
||||
dto_package = 'dto'
|
||||
callback_package = 'callback'
|
||||
notification_package = 'notification'
|
||||
future_package = 'future'
|
||||
# TODO find better package name
|
||||
callback_facade_package = 'callfacade'
|
||||
control_ping_class_fqn = "%s.%s.%s" % (plugin_package, dto_package, control_ping_class)
|
||||
|
||||
dto_gen.generate_dtos(func_list, base_package, dto_package, args.inputfile)
|
||||
jvpp_impl_gen.generate_jvpp(func_list, base_package, dto_package, args.inputfile)
|
||||
callback_gen.generate_callbacks(func_list, base_package, callback_package, dto_package, args.inputfile)
|
||||
notification_gen.generate_notification_registry(func_list, base_package, notification_package, callback_package, dto_package, args.inputfile)
|
||||
jvpp_c_gen.generate_jvpp(func_list, args.inputfile)
|
||||
jvpp_future_facade_gen.generate_jvpp(func_list, base_package, dto_package, callback_package, notification_package, future_package, args.inputfile)
|
||||
jvpp_callback_facade_gen.generate_jvpp(func_list, base_package, dto_package, callback_package, notification_package, callback_facade_package, args.inputfile)
|
||||
dto_gen.generate_dtos(func_list, base_package, plugin_package, plugin_name.title(), dto_package, args.inputfile)
|
||||
jvpp_impl_gen.generate_jvpp(func_list, base_package, plugin_package, plugin_name, control_ping_class_fqn, dto_package, args.inputfile)
|
||||
callback_gen.generate_callbacks(func_list, base_package, plugin_package, plugin_name.title(), callback_package, dto_package, args.inputfile)
|
||||
notification_gen.generate_notification_registry(func_list, base_package, plugin_package, plugin_name.title(), notification_package, callback_package, dto_package, args.inputfile)
|
||||
jvpp_c_gen.generate_jvpp(func_list, plugin_name, args.inputfile)
|
||||
jvpp_future_facade_gen.generate_jvpp(func_list, base_package, plugin_package, plugin_name.title(), dto_package, callback_package, notification_package, future_package, args.inputfile)
|
||||
jvpp_callback_facade_gen.generate_jvpp(func_list, base_package, plugin_package, plugin_name.title(), dto_package, callback_package, notification_package, callback_facade_package, args.inputfile)
|
||||
|
@ -22,10 +22,10 @@ from util import remove_suffix
|
||||
callback_suffix = "Callback"
|
||||
|
||||
callback_template = Template("""
|
||||
package $base_package.$callback_package;
|
||||
package $plugin_package.$callback_package;
|
||||
|
||||
/**
|
||||
* <p>Represents callback for vpe.api message.
|
||||
* <p>Represents callback for plugin's api file message.
|
||||
* <br>It was generated by callback_gen.py based on $inputfile preparsed data:
|
||||
* <pre>
|
||||
$docs
|
||||
@ -39,19 +39,19 @@ public interface $cls_name extends $base_package.$callback_package.$callback_typ
|
||||
""")
|
||||
|
||||
global_callback_template = Template("""
|
||||
package $base_package.$callback_package;
|
||||
package $plugin_package.$callback_package;
|
||||
|
||||
/**
|
||||
* <p>Global aggregated callback interface.
|
||||
* <br>It was generated by callback_gen.py based on $inputfile
|
||||
* <br>(python representation of vpe.api generated by vppapigen).
|
||||
* <br>(python representation of api file generated by vppapigen).
|
||||
*/
|
||||
public interface JVppGlobalCallback extends $callbacks {
|
||||
public interface JVpp${plugin_name}GlobalCallback extends $base_package.$callback_package.ControlPingCallback, $callbacks {
|
||||
}
|
||||
""")
|
||||
|
||||
|
||||
def generate_callbacks(func_list, base_package, callback_package, dto_package, inputfile):
|
||||
def generate_callbacks(func_list, base_package, plugin_package, plugin_name, callback_package, dto_package, inputfile):
|
||||
""" Generates callback interfaces """
|
||||
print "Generating Callback interfaces"
|
||||
|
||||
@ -61,10 +61,10 @@ def generate_callbacks(func_list, base_package, callback_package, dto_package, i
|
||||
callbacks = []
|
||||
for func in func_list:
|
||||
|
||||
if util.is_ignored(func['name']):
|
||||
continue
|
||||
|
||||
camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name'])
|
||||
|
||||
if util.is_ignored(func['name']) or util.is_control_ping(camel_case_name_with_suffix):
|
||||
continue
|
||||
if not util.is_reply(camel_case_name_with_suffix) and not util.is_notification(func['name']):
|
||||
continue
|
||||
|
||||
@ -76,11 +76,11 @@ def generate_callbacks(func_list, base_package, callback_package, dto_package, i
|
||||
camel_case_name = camel_case_name_with_suffix
|
||||
callback_type = "JVppNotificationCallback"
|
||||
|
||||
callbacks.append("{0}.{1}.{2}".format(base_package, callback_package, camel_case_name + callback_suffix))
|
||||
callbacks.append("{0}.{1}.{2}".format(plugin_package, callback_package, camel_case_name + callback_suffix))
|
||||
callback_path = os.path.join(callback_package, camel_case_name + callback_suffix + ".java")
|
||||
callback_file = open(callback_path, 'w')
|
||||
|
||||
reply_type = "%s.%s.%s" % (base_package, dto_package, camel_case_name_with_suffix)
|
||||
reply_type = "%s.%s.%s" % (plugin_package, dto_package, camel_case_name_with_suffix)
|
||||
method = "void on{0}({1} reply);".format(camel_case_name_with_suffix, reply_type)
|
||||
callback_file.write(
|
||||
callback_template.substitute(inputfile=inputfile,
|
||||
@ -88,15 +88,18 @@ def generate_callbacks(func_list, base_package, callback_package, dto_package, i
|
||||
cls_name=camel_case_name + callback_suffix,
|
||||
callback_method=method,
|
||||
base_package=base_package,
|
||||
plugin_package=plugin_package,
|
||||
callback_package=callback_package,
|
||||
callback_type=callback_type))
|
||||
callback_file.flush()
|
||||
callback_file.close()
|
||||
|
||||
callback_file = open(os.path.join(callback_package, "JVppGlobalCallback.java"), 'w')
|
||||
callback_file = open(os.path.join(callback_package, "JVpp%sGlobalCallback.java" % plugin_name), 'w')
|
||||
callback_file.write(global_callback_template.substitute(inputfile=inputfile,
|
||||
callbacks=", ".join(callbacks),
|
||||
base_package=base_package,
|
||||
plugin_package=plugin_package,
|
||||
plugin_name=plugin_name,
|
||||
callback_package=callback_package))
|
||||
callback_file.flush()
|
||||
callback_file.close()
|
||||
|
@ -19,7 +19,7 @@ from string import Template
|
||||
import util
|
||||
|
||||
dto_template = Template("""
|
||||
package $base_package.$dto_package;
|
||||
package $plugin_package.$dto_package;
|
||||
|
||||
/**
|
||||
* <p>This class represents $description.
|
||||
@ -39,11 +39,11 @@ field_template = Template(""" public $type $name;\n""")
|
||||
|
||||
send_template = Template(""" @Override
|
||||
public int send(final $base_package.JVpp jvpp) throws org.openvpp.jvpp.VppInvocationException {
|
||||
return jvpp.$method_name($args);
|
||||
return (($plugin_package.JVpp${plugin_name})jvpp).$method_name($args);
|
||||
}\n""")
|
||||
|
||||
|
||||
def generate_dtos(func_list, base_package, dto_package, inputfile):
|
||||
def generate_dtos(func_list, base_package, plugin_package, plugin_name, dto_package, inputfile):
|
||||
""" Generates dto objects in a dedicated package """
|
||||
print "Generating DTOs"
|
||||
|
||||
@ -55,7 +55,7 @@ def generate_dtos(func_list, base_package, dto_package, inputfile):
|
||||
camel_case_method_name = util.underscore_to_camelcase(func['name'])
|
||||
dto_path = os.path.join(dto_package, camel_case_dto_name + ".java")
|
||||
|
||||
if util.is_ignored(func['name']):
|
||||
if util.is_ignored(func['name']) or util.is_control_ping(camel_case_dto_name):
|
||||
continue
|
||||
|
||||
fields = ""
|
||||
@ -72,44 +72,46 @@ def generate_dtos(func_list, base_package, dto_package, inputfile):
|
||||
# Generate request/reply or dump/dumpReply even if structure can be used as notification
|
||||
if not util.is_just_notification(func["name"]):
|
||||
if util.is_reply(camel_case_dto_name):
|
||||
description = "vpe.api reply DTO"
|
||||
description = "reply DTO"
|
||||
request_dto_name = get_request_name(camel_case_dto_name, func['name'])
|
||||
if util.is_details(camel_case_dto_name):
|
||||
# FIXME assumption that dump calls end with "Dump" suffix. Not enforced in vpe.api
|
||||
base_type += "JVppReply<%s.%s.%s>" % (base_package, dto_package, request_dto_name + "Dump")
|
||||
generate_dump_reply_dto(request_dto_name, base_package, dto_package, camel_case_dto_name,
|
||||
base_type += "JVppReply<%s.%s.%s>" % (plugin_package, dto_package, request_dto_name + "Dump")
|
||||
generate_dump_reply_dto(request_dto_name, base_package, plugin_package, dto_package, camel_case_dto_name,
|
||||
camel_case_method_name, func)
|
||||
else:
|
||||
base_type += "JVppReply<%s.%s.%s>" % (base_package, dto_package, request_dto_name)
|
||||
base_type += "JVppReply<%s.%s.%s>" % (plugin_package, dto_package, request_dto_name)
|
||||
else:
|
||||
args = "" if fields is "" else "this"
|
||||
methods = send_template.substitute(method_name=camel_case_method_name,
|
||||
base_package=base_package,
|
||||
plugin_package=plugin_package,
|
||||
plugin_name=plugin_name,
|
||||
args=args)
|
||||
if util.is_dump(camel_case_dto_name):
|
||||
base_type += "JVppDump"
|
||||
description = "vpe.api dump request DTO"
|
||||
description = "dump request DTO"
|
||||
else:
|
||||
base_type += "JVppRequest"
|
||||
description = "vpe.api request DTO"
|
||||
description = "request DTO"
|
||||
|
||||
write_dto_file(base_package, base_type, camel_case_dto_name, description, dto_package, dto_path, fields, func,
|
||||
write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, description, dto_package, dto_path, fields, func,
|
||||
inputfile, methods)
|
||||
|
||||
# for structures that are also used as notifications, generate dedicated notification DTO
|
||||
if util.is_notification(func["name"]):
|
||||
base_type = "JVppNotification"
|
||||
description = "vpe.api notification DTO"
|
||||
description = "notification DTO"
|
||||
camel_case_dto_name = util.add_notification_suffix(camel_case_dto_name)
|
||||
methods = ""
|
||||
dto_path = os.path.join(dto_package, camel_case_dto_name + ".java")
|
||||
write_dto_file(base_package, base_type, camel_case_dto_name, description, dto_package, dto_path, fields, func,
|
||||
write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, description, dto_package, dto_path, fields, func,
|
||||
inputfile, methods)
|
||||
|
||||
flush_dump_reply_dtos(inputfile)
|
||||
|
||||
|
||||
def write_dto_file(base_package, base_type, camel_case_dto_name, description, dto_package, dto_path, fields, func,
|
||||
def write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, description, dto_package, dto_path, fields, func,
|
||||
inputfile, methods):
|
||||
dto_file = open(dto_path, 'w')
|
||||
dto_file.write(dto_template.substitute(inputfile=inputfile,
|
||||
@ -119,6 +121,7 @@ def write_dto_file(base_package, base_type, camel_case_dto_name, description, dt
|
||||
fields=fields,
|
||||
methods=methods,
|
||||
base_package=base_package,
|
||||
plugin_package=plugin_package,
|
||||
base_type=base_type,
|
||||
dto_package=dto_package))
|
||||
dto_file.flush()
|
||||
@ -141,11 +144,12 @@ def flush_dump_reply_dtos(inputfile):
|
||||
dump_reply_artificial_dto['cls_name'] + ".java")
|
||||
dto_file = open(dto_path, 'w')
|
||||
dto_file.write(dto_template.substitute(inputfile=inputfile,
|
||||
description="vpe.api dump reply wrapper",
|
||||
description="dump reply wrapper",
|
||||
docs=dump_reply_artificial_dto['docs'],
|
||||
cls_name=dump_reply_artificial_dto['cls_name'],
|
||||
fields=dump_reply_artificial_dto['fields'],
|
||||
methods=dump_reply_artificial_dto['methods'],
|
||||
plugin_package=dump_reply_artificial_dto['plugin_package'],
|
||||
base_package=dump_reply_artificial_dto['base_package'],
|
||||
base_type=dump_reply_artificial_dto['base_type'],
|
||||
dto_package=dump_reply_artificial_dto['dto_package']))
|
||||
@ -153,11 +157,11 @@ def flush_dump_reply_dtos(inputfile):
|
||||
dto_file.close()
|
||||
|
||||
|
||||
def generate_dump_reply_dto(request_dto_name, base_package, dto_package, camel_case_dto_name, camel_case_method_name,
|
||||
def generate_dump_reply_dto(request_dto_name, base_package, plugin_package, dto_package, camel_case_dto_name, camel_case_method_name,
|
||||
func):
|
||||
base_type = "JVppReplyDump<%s.%s.%s, %s.%s.%s>" % (
|
||||
base_package, dto_package, util.remove_reply_suffix(camel_case_dto_name) + "Dump",
|
||||
base_package, dto_package, camel_case_dto_name)
|
||||
plugin_package, dto_package, util.remove_reply_suffix(camel_case_dto_name) + "Dump",
|
||||
plugin_package, dto_package, camel_case_dto_name)
|
||||
fields = " public java.util.List<%s> %s = new java.util.ArrayList<>();" % (camel_case_dto_name, camel_case_method_name)
|
||||
cls_name = camel_case_dto_name + dump_dto_suffix
|
||||
|
||||
@ -171,6 +175,7 @@ def generate_dump_reply_dto(request_dto_name, base_package, dto_package, camel_c
|
||||
'cls_name': cls_name,
|
||||
'fields': fields,
|
||||
'methods': "",
|
||||
'plugin_package': plugin_package,
|
||||
'base_package': base_package,
|
||||
'base_type': base_type,
|
||||
'dto_package': dto_package,
|
||||
|
@ -17,7 +17,7 @@
|
||||
import os, util
|
||||
from string import Template
|
||||
|
||||
def is_manually_generated(f_name):
|
||||
def is_manually_generated(f_name, plugin_name):
|
||||
return f_name in {'control_ping_reply'}
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ class_reference_template = Template("""jclass ${ref_name}Class;
|
||||
""")
|
||||
|
||||
find_class_invocation_template = Template("""
|
||||
${ref_name}Class = (jclass)(*env)->NewGlobalRef(env, (*env)->FindClass(env, "org/openvpp/jvpp/dto/${class_name}"));
|
||||
${ref_name}Class = (jclass)(*env)->NewGlobalRef(env, (*env)->FindClass(env, "org/openvpp/jvpp/${plugin_name}/dto/${class_name}"));
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
(*env)->ExceptionDescribe(env);
|
||||
return JNI_ERR;
|
||||
@ -38,53 +38,71 @@ find_class_template = Template("""
|
||||
return JNI_ERR;
|
||||
}""")
|
||||
|
||||
delete_class_invocation_template = Template("""
|
||||
if (${ref_name}Class) {
|
||||
(*env)->DeleteGlobalRef(env, ${ref_name}Class);
|
||||
}""")
|
||||
|
||||
class_cache_template = Template("""
|
||||
$class_references
|
||||
static int cache_class_references(JNIEnv* env) {
|
||||
$find_class_invocations
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void delete_class_references(JNIEnv* env) {
|
||||
$delete_class_invocations
|
||||
}""")
|
||||
|
||||
def generate_class_cache(func_list):
|
||||
def generate_class_cache(func_list, plugin_name):
|
||||
class_references = []
|
||||
find_class_invocations = []
|
||||
delete_class_invocations = []
|
||||
for f in func_list:
|
||||
c_name = f['name']
|
||||
class_name = util.underscore_to_camelcase_upper(c_name)
|
||||
ref_name = util.underscore_to_camelcase(c_name)
|
||||
|
||||
if util.is_ignored(c_name):
|
||||
if util.is_ignored(c_name) or util.is_control_ping(class_name):
|
||||
continue
|
||||
|
||||
if util.is_reply(class_name):
|
||||
class_references.append(class_reference_template.substitute(
|
||||
ref_name=ref_name))
|
||||
find_class_invocations.append(find_class_invocation_template.substitute(
|
||||
plugin_name=plugin_name,
|
||||
ref_name=ref_name,
|
||||
class_name=class_name))
|
||||
delete_class_invocations.append(delete_class_invocation_template.substitute(ref_name=ref_name))
|
||||
elif util.is_notification(c_name):
|
||||
class_references.append(class_reference_template.substitute(
|
||||
ref_name=util.add_notification_suffix(ref_name)))
|
||||
find_class_invocations.append(find_class_invocation_template.substitute(
|
||||
plugin_name=plugin_name,
|
||||
ref_name=util.add_notification_suffix(ref_name),
|
||||
class_name=util.add_notification_suffix(class_name)))
|
||||
delete_class_invocations.append(delete_class_invocation_template.substitute(
|
||||
ref_name=util.add_notification_suffix(ref_name)))
|
||||
|
||||
# add exception class to class cache
|
||||
ref_name = 'callbackException'
|
||||
class_name = 'org/openvpp/jvpp/VppCallbackException'
|
||||
class_references.append(class_reference_template.substitute(
|
||||
ref_name=ref_name))
|
||||
ref_name=ref_name))
|
||||
find_class_invocations.append(find_class_template.substitute(
|
||||
ref_name=ref_name,
|
||||
class_name=class_name))
|
||||
delete_class_invocations.append(delete_class_invocation_template.substitute(ref_name=ref_name))
|
||||
|
||||
return class_cache_template.substitute(
|
||||
class_references="".join(class_references), find_class_invocations="".join(find_class_invocations))
|
||||
class_references="".join(class_references), find_class_invocations="".join(find_class_invocations),
|
||||
delete_class_invocations="".join(delete_class_invocations))
|
||||
|
||||
|
||||
# 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, "org/openvpp/jvpp/dto/${java_name_upper}");""")
|
||||
jclass requestClass = (*env)->FindClass(env, "org/openvpp/jvpp/${plugin_name}/dto/${java_name_upper}");""")
|
||||
|
||||
request_field_identifier_template = Template("""
|
||||
jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, requestClass, "${java_name}", "${jni_signature}");
|
||||
@ -178,37 +196,40 @@ struct_setter_templates = {'u8': u8_struct_setter_template,
|
||||
|
||||
jni_impl_template = Template("""
|
||||
/**
|
||||
* JNI binding for sending ${c_name} vpe.api message.
|
||||
* JNI binding for sending ${c_name} message.
|
||||
* Generated based on $inputfile preparsed data:
|
||||
$api_data
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_openvpp_jvpp_JVppImpl_${java_name}0
|
||||
JNIEXPORT jint JNICALL Java_org_openvpp_jvpp_${plugin_name}_JVpp${java_plugin_name}Impl_${java_name}0
|
||||
(JNIEnv * env, jclass clazz$args) {
|
||||
vppjni_main_t *jm = &vppjni_main;
|
||||
${plugin_name}_main_t *plugin_main = &${plugin_name}_main;
|
||||
vl_api_${c_name}_t * mp;
|
||||
u32 my_context_id;
|
||||
int rv;
|
||||
rv = vppjni_sanity_check (jm);
|
||||
if (rv) return rv;
|
||||
my_context_id = vppjni_get_context_id (jm);
|
||||
u32 my_context_id = vppjni_get_context_id (&jvpp_main);
|
||||
$request_class
|
||||
$field_identifiers
|
||||
M(${c_name_uppercase}, ${c_name});
|
||||
|
||||
// create message:
|
||||
mp = vl_msg_api_alloc(sizeof(*mp));
|
||||
memset (mp, 0, sizeof (*mp));
|
||||
mp->_vl_msg_id = ntohs (VL_API_${c_name_uppercase} + plugin_main->msg_id_base);
|
||||
mp->client_index = plugin_main->my_client_index;
|
||||
mp->context = clib_host_to_net_u32 (my_context_id);
|
||||
|
||||
$struct_setters
|
||||
S;
|
||||
// send message:
|
||||
vl_msg_api_send_shmem (plugin_main->vl_input_queue, (u8 *)&mp);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
return my_context_id;
|
||||
}""")
|
||||
|
||||
def generate_jni_impl(func_list, inputfile):
|
||||
def generate_jni_impl(func_list, plugin_name, inputfile):
|
||||
jni_impl = []
|
||||
for f in func_list:
|
||||
f_name = f['name']
|
||||
camel_case_function_name = util.underscore_to_camelcase(f_name)
|
||||
if is_manually_generated(f_name) or util.is_reply(camel_case_function_name) \
|
||||
if is_manually_generated(f_name, plugin_name) or util.is_reply(camel_case_function_name) \
|
||||
or util.is_ignored(f_name) or util.is_just_notification(f_name):
|
||||
continue
|
||||
|
||||
@ -222,7 +243,9 @@ def generate_jni_impl(func_list, inputfile):
|
||||
arguments = ', jobject request'
|
||||
camel_case_function_name_upper = util.underscore_to_camelcase_upper(f_name)
|
||||
|
||||
request_class = request_class_template.substitute(java_name_upper=camel_case_function_name_upper)
|
||||
request_class = request_class_template.substitute(
|
||||
java_name_upper=camel_case_function_name_upper,
|
||||
plugin_name=plugin_name)
|
||||
|
||||
# field identifiers
|
||||
for t in zip(f['types'], f['args']):
|
||||
@ -261,6 +284,8 @@ def generate_jni_impl(func_list, inputfile):
|
||||
java_name=camel_case_function_name,
|
||||
c_name_uppercase=f_name_uppercase,
|
||||
c_name=f_name,
|
||||
plugin_name=plugin_name,
|
||||
java_plugin_name=plugin_name.title(),
|
||||
request_class=request_class,
|
||||
field_identifiers=field_identifiers,
|
||||
struct_setters=struct_setters,
|
||||
@ -357,7 +382,7 @@ dto_field_setter_templates = {'u8': default_dto_field_setter_template,
|
||||
callback_err_handler_template = Template("""
|
||||
// for negative result don't send callback message but send error callback
|
||||
if (mp->retval<0) {
|
||||
CallOnError("${handler_name}",mp->context,mp->retval);
|
||||
call_on_error("${handler_name}", mp->context, mp->retval, plugin_main->callbackClass, plugin_main->callbackObject, callbackExceptionClass);
|
||||
return;
|
||||
}
|
||||
if (mp->retval == VNET_API_ERROR_IN_PROGRESS) {
|
||||
@ -368,32 +393,34 @@ callback_err_handler_template = Template("""
|
||||
|
||||
msg_handler_template = Template("""
|
||||
/**
|
||||
* Handler for ${handler_name} vpe.api message.
|
||||
* Handler for ${handler_name} message.
|
||||
* Generated based on $inputfile preparsed data:
|
||||
$api_data
|
||||
*/
|
||||
static void vl_api_${handler_name}_t_handler (vl_api_${handler_name}_t * mp)
|
||||
{
|
||||
vppjni_main_t * jm = &vppjni_main;
|
||||
JNIEnv *env = jm->jenv;
|
||||
${plugin_name}_main_t *plugin_main = &${plugin_name}_main;
|
||||
JNIEnv *env = jvpp_main.jenv;
|
||||
|
||||
$err_handler
|
||||
|
||||
jmethodID constructor = (*env)->GetMethodID(env, ${class_ref_name}Class, "<init>", "()V");
|
||||
jmethodID callbackMethod = (*env)->GetMethodID(env, jm->callbackClass, "on${dto_name}", "(Lorg/openvpp/jvpp/dto/${dto_name};)V");
|
||||
jmethodID callbackMethod = (*env)->GetMethodID(env, plugin_main->callbackClass, "on${dto_name}", "(Lorg/openvpp/jvpp/${plugin_name}/dto/${dto_name};)V");
|
||||
|
||||
jobject dto = (*env)->NewObject(env, ${class_ref_name}Class, constructor);
|
||||
$dto_setters
|
||||
(*env)->CallVoidMethod(env, jm->callback, callbackMethod, dto);
|
||||
|
||||
(*env)->CallVoidMethod(env, plugin_main->callbackObject, callbackMethod, dto);
|
||||
}""")
|
||||
|
||||
def generate_msg_handlers(func_list, inputfile):
|
||||
def generate_msg_handlers(func_list, plugin_name, inputfile):
|
||||
handlers = []
|
||||
for f in func_list:
|
||||
handler_name = f['name']
|
||||
dto_name = util.underscore_to_camelcase_upper(handler_name)
|
||||
ref_name = util.underscore_to_camelcase(handler_name)
|
||||
|
||||
if is_manually_generated(handler_name) or util.is_ignored(handler_name):
|
||||
if is_manually_generated(handler_name, plugin_name) or util.is_ignored(handler_name):
|
||||
continue
|
||||
|
||||
if not util.is_reply(dto_name) and not util.is_notification(handler_name):
|
||||
@ -455,6 +482,7 @@ def generate_msg_handlers(func_list, inputfile):
|
||||
inputfile=inputfile,
|
||||
api_data=util.api_message_to_javadoc(f),
|
||||
handler_name=handler_name,
|
||||
plugin_name=plugin_name,
|
||||
dto_name=dto_name,
|
||||
class_ref_name=ref_name,
|
||||
dto_setters=dto_setters,
|
||||
@ -468,12 +496,13 @@ handler_registration_template = Template("""_(${upercase_name}, ${name}) \\
|
||||
|
||||
|
||||
def generate_handler_registration(func_list):
|
||||
handler_registration = ["#define foreach_vpe_api_msg \\\n"]
|
||||
handler_registration = ["#define foreach_api_reply_handler \\\n"]
|
||||
for f in func_list:
|
||||
name = f['name']
|
||||
camelcase_name = util.underscore_to_camelcase(f['name'])
|
||||
|
||||
if (not util.is_reply(camelcase_name) and not util.is_notification(name)) or util.is_ignored(name):
|
||||
if (not util.is_reply(camelcase_name) and not util.is_notification(name)) or util.is_ignored(name) \
|
||||
or util.is_control_ping(camelcase_name):
|
||||
continue
|
||||
|
||||
handler_registration.append(handler_registration_template.substitute(
|
||||
@ -486,11 +515,9 @@ def generate_handler_registration(func_list):
|
||||
jvpp_c_template = Template("""/**
|
||||
* This file contains JNI bindings for jvpp Java API.
|
||||
* It was generated by jvpp_c_gen.py based on $inputfile
|
||||
* (python representation of vpe.api generated by vppapigen).
|
||||
* (python representation of api file generated by vppapigen).
|
||||
*/
|
||||
|
||||
void CallOnError(const char* call, int context, int retval);
|
||||
|
||||
// JAVA class reference cache
|
||||
$class_cache
|
||||
|
||||
@ -504,16 +531,16 @@ $msg_handlers
|
||||
$handler_registration
|
||||
""")
|
||||
|
||||
def generate_jvpp(func_list, inputfile):
|
||||
def generate_jvpp(func_list, plugin_name, inputfile):
|
||||
""" Generates jvpp C file """
|
||||
print "Generating jvpp C"
|
||||
|
||||
class_cache = generate_class_cache(func_list)
|
||||
jni_impl = generate_jni_impl(func_list, inputfile)
|
||||
msg_handlers = generate_msg_handlers(func_list, inputfile)
|
||||
class_cache = generate_class_cache(func_list, plugin_name)
|
||||
jni_impl = generate_jni_impl(func_list, plugin_name, inputfile)
|
||||
msg_handlers = generate_msg_handlers(func_list, plugin_name, inputfile)
|
||||
handler_registration = generate_handler_registration(func_list)
|
||||
|
||||
jvpp_c_file = open("jvpp_gen.h", 'w')
|
||||
jvpp_c_file = open("jvpp_%s_gen.h" % plugin_name, 'w')
|
||||
jvpp_c_file.write(jvpp_c_template.substitute(
|
||||
inputfile=inputfile,
|
||||
class_cache=class_cache,
|
||||
|
@ -20,17 +20,14 @@ import callback_gen
|
||||
import dto_gen
|
||||
|
||||
jvpp_ifc_template = Template("""
|
||||
package $base_package.$callback_facade_package;
|
||||
package $plugin_package.$callback_facade_package;
|
||||
|
||||
/**
|
||||
* <p>Callback Java API representation of vpe.api.
|
||||
* <p>Callback Java API representation of $plugin_package plugin.
|
||||
* <br>It was generated by jvpp_callback_facade_gen.py based on $inputfile
|
||||
* <br>(python representation of vpe.api generated by vppapigen).
|
||||
* <br>(python representation of api file generated by vppapigen).
|
||||
*/
|
||||
public interface CallbackJVpp extends $base_package.$notification_package.NotificationRegistryProvider, java.lang.AutoCloseable {
|
||||
|
||||
@Override
|
||||
void close();
|
||||
public interface CallbackJVpp${plugin_name} extends $base_package.$notification_package.NotificationRegistryProvider, java.lang.AutoCloseable {
|
||||
|
||||
// TODO add send
|
||||
|
||||
@ -39,20 +36,20 @@ $methods
|
||||
""")
|
||||
|
||||
jvpp_impl_template = Template("""
|
||||
package $base_package.$callback_facade_package;
|
||||
package $plugin_package.$callback_facade_package;
|
||||
|
||||
/**
|
||||
* <p>Default implementation of CallbackJVpp interface.
|
||||
* <p>Default implementation of Callback${plugin_name}JVpp interface.
|
||||
* <br>It was generated by jvpp_callback_facade_gen.py based on $inputfile
|
||||
* <br>(python representation of vpe.api generated by vppapigen).
|
||||
* <br>(python representation of api file generated by vppapigen).
|
||||
*/
|
||||
public final class CallbackJVppFacade extends $base_package.$notification_package.NotificationRegistryProviderContext implements $base_package.$callback_facade_package.CallbackJVpp {
|
||||
public final class CallbackJVpp${plugin_name}Facade implements CallbackJVpp${plugin_name} {
|
||||
|
||||
private final $base_package.JVpp jvpp;
|
||||
private final $plugin_package.JVpp${plugin_name} jvpp;
|
||||
private final java.util.Map<Integer, $base_package.$callback_package.JVppCallback> callbacks;
|
||||
|
||||
private final $plugin_package.$notification_package.${plugin_name}NotificationRegistryImpl notificationRegistry = new $plugin_package.$notification_package.${plugin_name}NotificationRegistryImpl();
|
||||
/**
|
||||
* <p>Create CallbackJVppFacade object for provided JVpp instance.
|
||||
* <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
|
||||
*
|
||||
@ -60,14 +57,21 @@ public final class CallbackJVppFacade extends $base_package.$notification_packag
|
||||
*
|
||||
* @throws java.io.IOException in case instance cannot connect to JVPP
|
||||
*/
|
||||
public CallbackJVppFacade(final $base_package.JVpp jvpp) throws java.io.IOException {
|
||||
public CallbackJVpp${plugin_name}Facade(final $base_package.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<>();
|
||||
this.jvpp.connect(new CallbackJVppFacadeCallback(this.callbacks, getNotificationCallback()));
|
||||
java.util.Objects.requireNonNull(registry, "JVppRegistry should not be null");
|
||||
registry.register(jvpp, new CallbackJVpp${plugin_name}FacadeCallback(this.callbacks, notificationRegistry));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
public $plugin_package.$notification_package.${plugin_name}NotificationRegistry getNotificationRegistry() {
|
||||
return notificationRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
jvpp.close();
|
||||
}
|
||||
|
||||
// TODO add send()
|
||||
@ -77,17 +81,17 @@ $methods
|
||||
""")
|
||||
|
||||
method_template = Template(
|
||||
""" void $name($base_package.$dto_package.$request request, $base_package.$callback_package.$callback callback) throws org.openvpp.jvpp.VppInvocationException;""")
|
||||
""" void $name($plugin_package.$dto_package.$request request, $plugin_package.$callback_package.$callback callback) throws $base_package.VppInvocationException;""")
|
||||
|
||||
method_impl_template = Template(""" public final void $name($base_package.$dto_package.$request request, $base_package.$callback_package.$callback callback) throws org.openvpp.jvpp.VppInvocationException {
|
||||
method_impl_template = Template(""" public final void $name($plugin_package.$dto_package.$request request, $plugin_package.$callback_package.$callback callback) throws $base_package.VppInvocationException {
|
||||
synchronized (callbacks) {
|
||||
callbacks.put(jvpp.$name(request), callback);
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
||||
no_arg_method_template = Template(""" void $name($base_package.$callback_package.$callback callback) throws org.openvpp.jvpp.VppInvocationException;""")
|
||||
no_arg_method_impl_template = Template(""" public final void $name($base_package.$callback_package.$callback callback) throws org.openvpp.jvpp.VppInvocationException {
|
||||
no_arg_method_template = Template(""" void $name($plugin_package.$callback_package.$callback callback) throws $base_package.VppInvocationException;""")
|
||||
no_arg_method_impl_template = Template(""" public final void $name($plugin_package.$callback_package.$callback callback) throws $base_package.VppInvocationException {
|
||||
synchronized (callbacks) {
|
||||
callbacks.put(jvpp.$name(), callback);
|
||||
}
|
||||
@ -95,7 +99,7 @@ no_arg_method_impl_template = Template(""" public final void $name($base_pack
|
||||
""")
|
||||
|
||||
|
||||
def generate_jvpp(func_list, base_package, dto_package, callback_package, notification_package, callback_facade_package, inputfile):
|
||||
def generate_jvpp(func_list, base_package, plugin_package, plugin_name, dto_package, callback_package, notification_package, callback_facade_package, inputfile):
|
||||
""" Generates callback facade """
|
||||
print "Generating JVpp callback facade"
|
||||
|
||||
@ -109,12 +113,11 @@ def generate_jvpp(func_list, base_package, dto_package, callback_package, notifi
|
||||
for func in func_list:
|
||||
|
||||
if util.is_notification(func['name']) or util.is_ignored(func['name']):
|
||||
# TODO handle notifications
|
||||
continue
|
||||
|
||||
camel_case_name = util.underscore_to_camelcase(func['name'])
|
||||
camel_case_name_upper = util.underscore_to_camelcase_upper(func['name'])
|
||||
if util.is_reply(camel_case_name):
|
||||
if util.is_reply(camel_case_name) or util.is_control_ping(camel_case_name):
|
||||
continue
|
||||
|
||||
# Strip suffix for dump calls
|
||||
@ -123,11 +126,13 @@ def generate_jvpp(func_list, base_package, dto_package, callback_package, notifi
|
||||
if len(func['args']) == 0:
|
||||
methods.append(no_arg_method_template.substitute(name=camel_case_name,
|
||||
base_package=base_package,
|
||||
plugin_package=plugin_package,
|
||||
dto_package=dto_package,
|
||||
callback_package=callback_package,
|
||||
callback=callback_type))
|
||||
methods_impl.append(no_arg_method_impl_template.substitute(name=camel_case_name,
|
||||
base_package=base_package,
|
||||
plugin_package=plugin_package,
|
||||
dto_package=dto_package,
|
||||
callback_package=callback_package,
|
||||
callback=callback_type))
|
||||
@ -135,32 +140,38 @@ def generate_jvpp(func_list, base_package, dto_package, callback_package, notifi
|
||||
methods.append(method_template.substitute(name=camel_case_name,
|
||||
request=camel_case_name_upper,
|
||||
base_package=base_package,
|
||||
plugin_package=plugin_package,
|
||||
dto_package=dto_package,
|
||||
callback_package=callback_package,
|
||||
callback=callback_type))
|
||||
methods_impl.append(method_impl_template.substitute(name=camel_case_name,
|
||||
request=camel_case_name_upper,
|
||||
base_package=base_package,
|
||||
plugin_package=plugin_package,
|
||||
dto_package=dto_package,
|
||||
callback_package=callback_package,
|
||||
callback=callback_type))
|
||||
|
||||
join = os.path.join(callback_facade_package, "CallbackJVpp.java")
|
||||
join = os.path.join(callback_facade_package, "CallbackJVpp%s.java" % plugin_name)
|
||||
jvpp_file = open(join, 'w')
|
||||
jvpp_file.write(
|
||||
jvpp_ifc_template.substitute(inputfile=inputfile,
|
||||
methods="\n".join(methods),
|
||||
base_package=base_package,
|
||||
plugin_package=plugin_package,
|
||||
plugin_name=plugin_name,
|
||||
dto_package=dto_package,
|
||||
notification_package=notification_package,
|
||||
callback_facade_package=callback_facade_package))
|
||||
jvpp_file.flush()
|
||||
jvpp_file.close()
|
||||
|
||||
jvpp_file = open(os.path.join(callback_facade_package, "CallbackJVppFacade.java"), 'w')
|
||||
jvpp_file = open(os.path.join(callback_facade_package, "CallbackJVpp%sFacade.java" % plugin_name), 'w')
|
||||
jvpp_file.write(jvpp_impl_template.substitute(inputfile=inputfile,
|
||||
methods="\n".join(methods_impl),
|
||||
base_package=base_package,
|
||||
plugin_package=plugin_package,
|
||||
plugin_name=plugin_name,
|
||||
dto_package=dto_package,
|
||||
notification_package=notification_package,
|
||||
callback_package=callback_package,
|
||||
@ -168,31 +179,31 @@ def generate_jvpp(func_list, base_package, dto_package, callback_package, notifi
|
||||
jvpp_file.flush()
|
||||
jvpp_file.close()
|
||||
|
||||
generate_callback(func_list, base_package, dto_package, callback_package, notification_package, callback_facade_package, inputfile)
|
||||
generate_callback(func_list, base_package, plugin_package, plugin_name, dto_package, callback_package, notification_package, callback_facade_package, inputfile)
|
||||
|
||||
|
||||
jvpp_facade_callback_template = Template("""
|
||||
package $base_package.$callback_facade_package;
|
||||
package $plugin_package.$callback_facade_package;
|
||||
|
||||
/**
|
||||
* <p>Implementation of JVppGlobalCallback interface for Java Callback API.
|
||||
* <br>It was generated by jvpp_callback_facade_gen.py based on $inputfile
|
||||
* <br>(python representation of vpe.api generated by vppapigen).
|
||||
* <br>(python representation of api file generated by vppapigen).
|
||||
*/
|
||||
public final class CallbackJVppFacadeCallback implements $base_package.$callback_package.JVppGlobalCallback {
|
||||
public final class CallbackJVpp${plugin_name}FacadeCallback implements $plugin_package.$callback_package.JVpp${plugin_name}GlobalCallback {
|
||||
|
||||
private final java.util.Map<Integer, $base_package.$callback_package.JVppCallback> requests;
|
||||
private final $base_package.$notification_package.GlobalNotificationCallback notificationCallback;
|
||||
private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(CallbackJVppFacadeCallback.class.getName());
|
||||
private final $plugin_package.$notification_package.Global${plugin_name}NotificationCallback notificationCallback;
|
||||
private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(CallbackJVpp${plugin_name}FacadeCallback.class.getName());
|
||||
|
||||
public CallbackJVppFacadeCallback(final java.util.Map<Integer, $base_package.$callback_package.JVppCallback> requestMap,
|
||||
final $base_package.$notification_package.GlobalNotificationCallback notificationCallback) {
|
||||
public CallbackJVpp${plugin_name}FacadeCallback(final java.util.Map<Integer, $base_package.$callback_package.JVppCallback> requestMap,
|
||||
final $plugin_package.$notification_package.Global${plugin_name}NotificationCallback notificationCallback) {
|
||||
this.requests = requestMap;
|
||||
this.notificationCallback = notificationCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(org.openvpp.jvpp.VppCallbackException reply) {
|
||||
public void onError($base_package.VppCallbackException reply) {
|
||||
|
||||
$base_package.$callback_package.JVppCallback failedCall;
|
||||
synchronized(requests) {
|
||||
@ -209,6 +220,20 @@ public final class CallbackJVppFacadeCallback implements $base_package.$callback
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void onControlPingReply($base_package.$dto_package.ControlPingReply reply) {
|
||||
|
||||
$base_package.$callback_package.ControlPingCallback callback;
|
||||
synchronized(requests) {
|
||||
callback = ($base_package.$callback_package.ControlPingCallback) requests.remove(reply.context);
|
||||
}
|
||||
|
||||
if(callback != null) {
|
||||
callback.onControlPingReply(reply);
|
||||
}
|
||||
}
|
||||
|
||||
$methods
|
||||
}
|
||||
""")
|
||||
@ -216,11 +241,11 @@ $methods
|
||||
jvpp_facade_callback_method_template = Template("""
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void on$callback_dto($base_package.$dto_package.$callback_dto reply) {
|
||||
public void on$callback_dto($plugin_package.$dto_package.$callback_dto reply) {
|
||||
|
||||
$base_package.$callback_package.$callback callback;
|
||||
$plugin_package.$callback_package.$callback callback;
|
||||
synchronized(requests) {
|
||||
callback = ($base_package.$callback_package.$callback) requests.remove(reply.context);
|
||||
callback = ($plugin_package.$callback_package.$callback) requests.remove(reply.context);
|
||||
}
|
||||
|
||||
if(callback != null) {
|
||||
@ -232,23 +257,23 @@ jvpp_facade_callback_method_template = Template("""
|
||||
jvpp_facade_callback_notification_method_template = Template("""
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void on$callback_dto($base_package.$dto_package.$callback_dto notification) {
|
||||
public void on$callback_dto($plugin_package.$dto_package.$callback_dto notification) {
|
||||
notificationCallback.on$callback_dto(notification);
|
||||
}
|
||||
""")
|
||||
|
||||
|
||||
def generate_callback(func_list, base_package, dto_package, callback_package, notification_package, callback_facade_package, inputfile):
|
||||
def generate_callback(func_list, base_package, plugin_package, plugin_name, dto_package, callback_package, notification_package, callback_facade_package, inputfile):
|
||||
callbacks = []
|
||||
for func in func_list:
|
||||
|
||||
if util.is_ignored(func['name']):
|
||||
continue
|
||||
|
||||
camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name'])
|
||||
|
||||
if util.is_ignored(func['name']) or util.is_control_ping(camel_case_name_with_suffix):
|
||||
continue
|
||||
|
||||
if util.is_reply(camel_case_name_with_suffix):
|
||||
callbacks.append(jvpp_facade_callback_method_template.substitute(base_package=base_package,
|
||||
callbacks.append(jvpp_facade_callback_method_template.substitute(plugin_package=plugin_package,
|
||||
dto_package=dto_package,
|
||||
callback_package=callback_package,
|
||||
callback=util.remove_reply_suffix(camel_case_name_with_suffix) + callback_gen.callback_suffix,
|
||||
@ -256,15 +281,17 @@ def generate_callback(func_list, base_package, dto_package, callback_package, no
|
||||
|
||||
if util.is_notification(func["name"]):
|
||||
with_notification_suffix = util.add_notification_suffix(camel_case_name_with_suffix)
|
||||
callbacks.append(jvpp_facade_callback_notification_method_template.substitute(base_package=base_package,
|
||||
callbacks.append(jvpp_facade_callback_notification_method_template.substitute(plugin_package=plugin_package,
|
||||
dto_package=dto_package,
|
||||
callback_package=callback_package,
|
||||
callback=with_notification_suffix + callback_gen.callback_suffix,
|
||||
callback_dto=with_notification_suffix))
|
||||
|
||||
jvpp_file = open(os.path.join(callback_facade_package, "CallbackJVppFacadeCallback.java"), 'w')
|
||||
jvpp_file = open(os.path.join(callback_facade_package, "CallbackJVpp%sFacadeCallback.java" % plugin_name), 'w')
|
||||
jvpp_file.write(jvpp_facade_callback_template.substitute(inputfile=inputfile,
|
||||
base_package=base_package,
|
||||
plugin_package=plugin_package,
|
||||
plugin_name=plugin_name,
|
||||
dto_package=dto_package,
|
||||
notification_package=notification_package,
|
||||
callback_package=callback_package,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -17,25 +17,14 @@ import os, util
|
||||
from string import Template
|
||||
|
||||
jvpp_ifc_template = Template("""
|
||||
package $base_package;
|
||||
|
||||
package $plugin_package;
|
||||
|
||||
/**
|
||||
* <p>Java representation of vpe.api.
|
||||
* <p>Java representation of plugin's api file.
|
||||
* <br>It was generated by jvpp_impl_gen.py based on $inputfile
|
||||
* <br>(python representation of vpe.api generated by vppapigen).
|
||||
* <br>(python representation of api file generated by vppapigen).
|
||||
*/
|
||||
public interface JVpp extends java.lang.AutoCloseable {
|
||||
|
||||
/**
|
||||
* Generic connect with $base_package.callback.JVppCallback callback handler
|
||||
* providing connecting to VPP
|
||||
*
|
||||
* @param callback JVppCallback instance providing callback handling
|
||||
*
|
||||
* @throws java.io.IOException if connection cannot be initiated
|
||||
*/
|
||||
void connect($base_package.callback.JVppCallback callback) throws java.io.IOException;
|
||||
public interface JVpp${plugin_name} extends $base_package.JVpp {
|
||||
|
||||
/**
|
||||
* Generic dispatch method for sending requests to VPP
|
||||
@ -44,52 +33,110 @@ public interface JVpp extends java.lang.AutoCloseable {
|
||||
*/
|
||||
int send($base_package.$dto_package.JVppRequest request) throws org.openvpp.jvpp.VppInvocationException;
|
||||
|
||||
@Override
|
||||
void close();
|
||||
|
||||
$methods
|
||||
}
|
||||
""")
|
||||
|
||||
jvpp_impl_template = Template("""
|
||||
package $base_package;
|
||||
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 $base_package.callback.JVppCallback;
|
||||
import $base_package.VppConnection;
|
||||
import $base_package.JVppRegistry;
|
||||
|
||||
/**
|
||||
* <p>Default implementation of JVpp interface.
|
||||
* <br>It was generated by jvpp_impl_gen.py based on $inputfile
|
||||
* <br>(python representation of vpe.api generated by vppapigen).
|
||||
* <br>(python representation of api file generated by vppapigen).
|
||||
*/
|
||||
public final class JVppImpl implements $base_package.JVpp {
|
||||
public final class JVpp${plugin_name}Impl implements $plugin_package.JVpp${plugin_name} {
|
||||
|
||||
private final $base_package.VppConnection connection;
|
||||
private final static Logger LOG = Logger.getLogger(JVpp${plugin_name}Impl.class.getName());
|
||||
private static final String LIBNAME = "libjvpp_${plugin_name_underscore}.so.0.0.0";
|
||||
|
||||
public JVppImpl(final $base_package.VppConnection connection) {
|
||||
this.connection = java.util.Objects.requireNonNull(connection,"Connection is null");
|
||||
// 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 connect($base_package.callback.JVppCallback callback) throws java.io.IOException {
|
||||
connection.connect(callback);
|
||||
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() {
|
||||
connection.close();
|
||||
close0();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int send($base_package.$dto_package.JVppRequest request) throws org.openvpp.jvpp.VppInvocationException {
|
||||
public int send($base_package.$dto_package.JVppRequest request) throws org.openvpp.jvpp.VppInvocationException {
|
||||
return request.send(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int controlPing(final org.openvpp.jvpp.dto.ControlPing controlPing) throws org.openvpp.jvpp.VppInvocationException {
|
||||
return registry.controlPing(JVpp${plugin_name}Impl.class);
|
||||
}
|
||||
|
||||
$methods
|
||||
}
|
||||
""")
|
||||
|
||||
method_template = Template(""" int $name($base_package.$dto_package.$request request) throws org.openvpp.jvpp.VppInvocationException;""")
|
||||
method_template = Template(""" int $name($plugin_package.$dto_package.$request request) throws org.openvpp.jvpp.VppInvocationException;""")
|
||||
method_native_template = Template(
|
||||
""" private static native int ${name}0($base_package.$dto_package.$request request);""")
|
||||
method_impl_template = Template(""" public final int $name($base_package.$dto_package.$request request) throws org.openvpp.jvpp.VppInvocationException {
|
||||
""" private static native int ${name}0($plugin_package.$dto_package.$request request);""")
|
||||
method_impl_template = Template(""" public final int $name($plugin_package.$dto_package.$request request) throws org.openvpp.jvpp.VppInvocationException {
|
||||
java.util.Objects.requireNonNull(request,"Null request object");
|
||||
connection.checkActive();
|
||||
int result=${name}0(request);
|
||||
@ -113,9 +160,10 @@ no_arg_method_impl_template = Template(""" public final int $name() throws or
|
||||
""")
|
||||
|
||||
|
||||
def generate_jvpp(func_list, base_package, dto_package, inputfile):
|
||||
def generate_jvpp(func_list, base_package, plugin_package, plugin_name_underscore, control_ping_class, dto_package, inputfile):
|
||||
""" Generates JVpp interface and JNI implementation """
|
||||
print "Generating JVpp"
|
||||
plugin_name = util.underscore_to_camelcase_upper(plugin_name_underscore)
|
||||
|
||||
methods = []
|
||||
methods_impl = []
|
||||
@ -131,43 +179,42 @@ def generate_jvpp(func_list, base_package, dto_package, inputfile):
|
||||
continue
|
||||
|
||||
if len(func['args']) == 0:
|
||||
methods.append(no_arg_method_template.substitute(name=camel_case_name,
|
||||
base_package=base_package,
|
||||
dto_package=dto_package))
|
||||
methods_impl.append(
|
||||
no_arg_method_native_template.substitute(name=camel_case_name,
|
||||
base_package=base_package,
|
||||
dto_package=dto_package))
|
||||
methods_impl.append(no_arg_method_impl_template.substitute(name=camel_case_name,
|
||||
base_package=base_package,
|
||||
dto_package=dto_package))
|
||||
methods.append(no_arg_method_template.substitute(name=camel_case_name))
|
||||
methods_impl.append(no_arg_method_native_template.substitute(name=camel_case_name))
|
||||
methods_impl.append(no_arg_method_impl_template.substitute(name=camel_case_name))
|
||||
else:
|
||||
methods.append(method_template.substitute(name=camel_case_name,
|
||||
request=camel_case_name_upper,
|
||||
base_package=base_package,
|
||||
plugin_package=plugin_package,
|
||||
dto_package=dto_package))
|
||||
methods_impl.append(method_native_template.substitute(name=camel_case_name,
|
||||
request=camel_case_name_upper,
|
||||
base_package=base_package,
|
||||
plugin_package=plugin_package,
|
||||
dto_package=dto_package))
|
||||
methods_impl.append(method_impl_template.substitute(name=camel_case_name,
|
||||
request=camel_case_name_upper,
|
||||
base_package=base_package,
|
||||
plugin_package=plugin_package,
|
||||
dto_package=dto_package))
|
||||
|
||||
jvpp_file = open("JVpp.java", 'w')
|
||||
jvpp_file = open("JVpp%s.java" % plugin_name, 'w')
|
||||
jvpp_file.write(
|
||||
jvpp_ifc_template.substitute(inputfile=inputfile,
|
||||
methods="\n".join(methods),
|
||||
base_package=base_package,
|
||||
plugin_package=plugin_package,
|
||||
plugin_name=plugin_name,
|
||||
dto_package=dto_package))
|
||||
jvpp_file.flush()
|
||||
jvpp_file.close()
|
||||
|
||||
jvpp_file = open("JVppImpl.java", 'w')
|
||||
jvpp_file = open("JVpp%sImpl.java" % plugin_name, 'w')
|
||||
jvpp_file.write(jvpp_impl_template.substitute(inputfile=inputfile,
|
||||
methods="\n".join(methods_impl),
|
||||
base_package=base_package,
|
||||
dto_package=dto_package))
|
||||
plugin_package=plugin_package,
|
||||
plugin_name=plugin_name,
|
||||
plugin_name_underscore=plugin_name_underscore,
|
||||
dto_package=dto_package,
|
||||
control_ping_class=control_ping_class))
|
||||
jvpp_file.flush()
|
||||
jvpp_file.close()
|
||||
|
@ -19,17 +19,15 @@ import callback_gen
|
||||
import util
|
||||
from string import Template
|
||||
|
||||
from util import remove_suffix
|
||||
|
||||
notification_registry_template = Template("""
|
||||
package $base_package.$notification_package;
|
||||
package $plugin_package.$notification_package;
|
||||
|
||||
/**
|
||||
* <p>Registry for notification callbacks.
|
||||
* <p>Registry for notification callbacks defined in ${plugin_name}.
|
||||
* <br>It was generated by notification_gen.py based on $inputfile
|
||||
* <br>(python representation of vpe.api generated by vppapigen).
|
||||
* <br>(python representation of api file generated by vppapigen).
|
||||
*/
|
||||
public interface NotificationRegistry extends java.lang.AutoCloseable {
|
||||
public interface ${plugin_name}NotificationRegistry extends $base_package.$notification_package.NotificationRegistry {
|
||||
|
||||
$register_callback_methods
|
||||
|
||||
@ -39,27 +37,27 @@ public interface NotificationRegistry extends java.lang.AutoCloseable {
|
||||
""")
|
||||
|
||||
global_notification_callback_template = Template("""
|
||||
package $base_package.$notification_package;
|
||||
package $plugin_package.$notification_package;
|
||||
|
||||
/**
|
||||
* <p>Aggregated callback interface for notifications only.
|
||||
* <br>It was generated by notification_gen.py based on $inputfile
|
||||
* <br>(python representation of vpe.api generated by vppapigen).
|
||||
* <br>(python representation of api file generated by vppapigen).
|
||||
*/
|
||||
public interface GlobalNotificationCallback extends $callbacks {
|
||||
public interface Global${plugin_name}NotificationCallback$callbacks {
|
||||
|
||||
}
|
||||
""")
|
||||
|
||||
notification_registry_impl_template = Template("""
|
||||
package $base_package.$notification_package;
|
||||
package $plugin_package.$notification_package;
|
||||
|
||||
/**
|
||||
* <p>Notification registry delegating notification processing to registered callbacks.
|
||||
* <br>It was generated by notification_gen.py based on $inputfile
|
||||
* <br>(python representation of vpe.api generated by vppapigen).
|
||||
* <br>(python representation of api file generated by vppapigen).
|
||||
*/
|
||||
public final class NotificationRegistryImpl implements NotificationRegistry, GlobalNotificationCallback {
|
||||
public final class ${plugin_name}NotificationRegistryImpl implements ${plugin_name}NotificationRegistry, Global${plugin_name}NotificationCallback {
|
||||
|
||||
// TODO add a special NotificationCallback interface and only allow those to be registered
|
||||
private final java.util.concurrent.ConcurrentMap<Class<? extends $base_package.$dto_package.JVppNotification>, $base_package.$callback_package.JVppNotificationCallback> registeredCallbacks =
|
||||
@ -76,30 +74,45 @@ public final class NotificationRegistryImpl implements NotificationRegistry, Glo
|
||||
""")
|
||||
|
||||
register_callback_impl_template = Template("""
|
||||
public java.lang.AutoCloseable register$callback(final $base_package.$callback_package.$callback callback){
|
||||
if(null != registeredCallbacks.putIfAbsent($base_package.$dto_package.$notification.class, callback)){
|
||||
throw new IllegalArgumentException("Callback for " + $base_package.$dto_package.$notification.class +
|
||||
public java.lang.AutoCloseable register$callback(final $plugin_package.$callback_package.$callback callback){
|
||||
if(null != registeredCallbacks.putIfAbsent($plugin_package.$dto_package.$notification.class, callback)){
|
||||
throw new IllegalArgumentException("Callback for " + $plugin_package.$dto_package.$notification.class +
|
||||
"notification already registered");
|
||||
}
|
||||
return () -> registeredCallbacks.remove($base_package.$dto_package.$notification.class);
|
||||
return () -> registeredCallbacks.remove($plugin_package.$dto_package.$notification.class);
|
||||
}
|
||||
""")
|
||||
|
||||
handler_impl_template = Template("""
|
||||
@Override
|
||||
public void on$notification(
|
||||
final $base_package.$dto_package.$notification notification) {
|
||||
final $base_package.$callback_package.JVppNotificationCallback JVppNotificationCallback = registeredCallbacks.get($base_package.$dto_package.$notification.class);
|
||||
if (null != JVppNotificationCallback) {
|
||||
(($base_package.$callback_package.$callback) registeredCallbacks
|
||||
.get($base_package.$dto_package.$notification.class))
|
||||
final $plugin_package.$dto_package.$notification notification) {
|
||||
final $base_package.$callback_package.JVppNotificationCallback jVppNotificationCallback = registeredCallbacks.get($plugin_package.$dto_package.$notification.class);
|
||||
if (null != jVppNotificationCallback) {
|
||||
(($plugin_package.$callback_package.$callback) registeredCallbacks
|
||||
.get($plugin_package.$dto_package.$notification.class))
|
||||
.on$notification(notification);
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
||||
notification_provider_template = Template("""
|
||||
package $plugin_package.$notification_package;
|
||||
|
||||
def generate_notification_registry(func_list, base_package, notification_package, callback_package, dto_package, inputfile):
|
||||
/**
|
||||
* Provides ${plugin_name}NotificationRegistry.
|
||||
* <br>The file was generated by notification_gen.py based on $inputfile
|
||||
* <br>(python representation of api file generated by vppapigen).
|
||||
*/
|
||||
public interface ${plugin_name}NotificationRegistryProvider extends $base_package.$notification_package.NotificationRegistryProvider {
|
||||
|
||||
@Override
|
||||
public ${plugin_name}NotificationRegistry getNotificationRegistry();
|
||||
}
|
||||
""")
|
||||
|
||||
|
||||
def generate_notification_registry(func_list, base_package, plugin_package, plugin_name, notification_package, callback_package, dto_package, inputfile):
|
||||
""" Generates notification registry interface and implementation """
|
||||
print "Generating Notification interfaces and implementation"
|
||||
|
||||
@ -118,47 +131,69 @@ def generate_notification_registry(func_list, base_package, notification_package
|
||||
camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name'])
|
||||
notification_dto = util.add_notification_suffix(camel_case_name_with_suffix)
|
||||
callback_ifc = notification_dto + callback_gen.callback_suffix
|
||||
fully_qualified_callback_ifc = "{0}.{1}.{2}".format(base_package, callback_package, callback_ifc)
|
||||
fully_qualified_callback_ifc = "{0}.{1}.{2}".format(plugin_package, callback_package, callback_ifc)
|
||||
callbacks.append(fully_qualified_callback_ifc)
|
||||
|
||||
# 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{0}({1} callback);"
|
||||
.format(callback_ifc, fully_qualified_callback_ifc))
|
||||
register_callback_methods_impl.append(register_callback_impl_template.substitute(base_package=base_package,
|
||||
register_callback_methods_impl.append(register_callback_impl_template.substitute(plugin_package=plugin_package,
|
||||
callback_package=callback_package,
|
||||
dto_package=dto_package,
|
||||
notification=notification_dto,
|
||||
callback=callback_ifc))
|
||||
handler_methods.append(handler_impl_template.substitute(base_package=base_package,
|
||||
plugin_package=plugin_package,
|
||||
callback_package=callback_package,
|
||||
dto_package=dto_package,
|
||||
notification=notification_dto,
|
||||
callback=callback_ifc))
|
||||
if(callbacks):
|
||||
callback_file = open(os.path.join(notification_package, "NotificationRegistry.java"), 'w')
|
||||
callback_file.write(notification_registry_template.substitute(inputfile=inputfile,
|
||||
register_callback_methods="\n ".join(register_callback_methods),
|
||||
base_package=base_package,
|
||||
notification_package=notification_package))
|
||||
callback_file.flush()
|
||||
callback_file.close()
|
||||
|
||||
callback_file = open(os.path.join(notification_package, "GlobalNotificationCallback.java"), 'w')
|
||||
callback_file.write(global_notification_callback_template.substitute(inputfile=inputfile,
|
||||
callbacks=", ".join(callbacks),
|
||||
base_package=base_package,
|
||||
notification_package=notification_package))
|
||||
callback_file.flush()
|
||||
callback_file.close()
|
||||
|
||||
callback_file = open(os.path.join(notification_package, "NotificationRegistryImpl.java"), 'w')
|
||||
callback_file.write(notification_registry_impl_template.substitute(inputfile=inputfile,
|
||||
callback_package=callback_package,
|
||||
dto_package=dto_package,
|
||||
register_callback_methods="".join(register_callback_methods_impl),
|
||||
handler_methods="".join(handler_methods),
|
||||
base_package=base_package,
|
||||
notification_package=notification_package))
|
||||
callback_file.flush()
|
||||
callback_file.close()
|
||||
callback_file = open(os.path.join(notification_package, "%sNotificationRegistry.java" % plugin_name), 'w')
|
||||
callback_file.write(notification_registry_template.substitute(inputfile=inputfile,
|
||||
register_callback_methods="\n ".join(register_callback_methods),
|
||||
base_package=base_package,
|
||||
plugin_package=plugin_package,
|
||||
plugin_name=plugin_name,
|
||||
notification_package=notification_package))
|
||||
callback_file.flush()
|
||||
callback_file.close()
|
||||
|
||||
callback_file = open(os.path.join(notification_package, "Global%sNotificationCallback.java" % plugin_name), 'w')
|
||||
|
||||
global_notification_callback_callbacks = ""
|
||||
if (callbacks):
|
||||
global_notification_callback_callbacks = " extends " + ", ".join(callbacks)
|
||||
|
||||
callback_file.write(global_notification_callback_template.substitute(inputfile=inputfile,
|
||||
callbacks=global_notification_callback_callbacks,
|
||||
plugin_package=plugin_package,
|
||||
plugin_name=plugin_name,
|
||||
notification_package=notification_package))
|
||||
callback_file.flush()
|
||||
callback_file.close()
|
||||
|
||||
callback_file = open(os.path.join(notification_package, "%sNotificationRegistryImpl.java" % plugin_name), 'w')
|
||||
callback_file.write(notification_registry_impl_template.substitute(inputfile=inputfile,
|
||||
callback_package=callback_package,
|
||||
dto_package=dto_package,
|
||||
register_callback_methods="".join(register_callback_methods_impl),
|
||||
handler_methods="".join(handler_methods),
|
||||
base_package=base_package,
|
||||
plugin_package=plugin_package,
|
||||
plugin_name=plugin_name,
|
||||
notification_package=notification_package))
|
||||
callback_file.flush()
|
||||
callback_file.close()
|
||||
|
||||
callback_file = open(os.path.join(notification_package, "%sNotificationRegistryProvider.java" % plugin_name), 'w')
|
||||
callback_file.write(notification_provider_template.substitute(inputfile=inputfile,
|
||||
base_package=base_package,
|
||||
plugin_package=plugin_package,
|
||||
plugin_name=plugin_name,
|
||||
notification_package=notification_package))
|
||||
callback_file.flush()
|
||||
callback_file.close()
|
||||
|
||||
|
@ -120,15 +120,18 @@ jni_field_accessors = {
|
||||
'jfloatArray': 'ObjectField'
|
||||
}
|
||||
|
||||
# TODO watch out for unsigned types
|
||||
# Mapping according to:
|
||||
# http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html
|
||||
vpp_2_jni_type_mapping = {'u8': 'jbyte', # fixme
|
||||
#
|
||||
# Unsigned types are converted to signed java types that have the same size.
|
||||
# It is the API user responsibility to interpret them correctly.
|
||||
vpp_2_jni_type_mapping = {'u8': 'jbyte',
|
||||
'i8': 'jbyte',
|
||||
'u16': 'jshort',
|
||||
'i16': 'jshort',
|
||||
'u32': 'jint', # fixme
|
||||
'u32': 'jint',
|
||||
'i32': 'jint',
|
||||
'u64': 'jlong', # fixme
|
||||
'u64': 'jlong',
|
||||
'i64': 'jlong',
|
||||
'f64': 'jdouble'
|
||||
}
|
||||
@ -179,7 +182,7 @@ def remove_suffix(camel_case_name_with_suffix, suffix):
|
||||
|
||||
|
||||
def is_control_ping(camel_case_name_with_suffix):
|
||||
return "controlping" in camel_case_name_with_suffix.lower()
|
||||
return camel_case_name_with_suffix.lower().startswith("controlping");
|
||||
|
||||
def api_message_to_javadoc(api_message):
|
||||
""" Converts vpe.api message description to javadoc """
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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.
|
||||
*/
|
||||
#ifndef __included_vppjni_h__
|
||||
#define __included_vppjni_h__
|
||||
|
||||
#include <vnet/vnet.h>
|
||||
#include <vnet/ip/ip.h>
|
||||
#include <vnet/api_errno.h>
|
||||
#include <vlibapi/api.h>
|
||||
#include <vlibmemory/api.h>
|
||||
#include <jni.h>
|
||||
|
||||
typedef struct {
|
||||
/* Unique identifier used for matching replays with requests */
|
||||
volatile u32 context_id;
|
||||
|
||||
/* Spinlock */
|
||||
volatile u32 lock;
|
||||
u32 tag;
|
||||
|
||||
/* Used for first control ping */
|
||||
// TODO better names?
|
||||
volatile u32 result_ready;
|
||||
volatile i32 retval;
|
||||
|
||||
/* JNI Native Method Interface pointer for message handlers */
|
||||
JNIEnv *jenv;
|
||||
|
||||
/* thread cleanup */
|
||||
pthread_key_t cleanup_rx_thread_key;
|
||||
|
||||
/* JNI Invoke Interface pointer for attachment of rx thread to java thread */
|
||||
JavaVM *jvm;
|
||||
|
||||
/* Callback object and class references enabling asynchronous Java calls */
|
||||
jobject callback;
|
||||
jclass callbackClass;
|
||||
|
||||
/* Connected indication */
|
||||
volatile u8 is_connected;
|
||||
|
||||
/* Convenience */
|
||||
unix_shared_memory_queue_t * vl_input_queue;
|
||||
u32 my_client_index;
|
||||
|
||||
} vppjni_main_t;
|
||||
|
||||
vppjni_main_t vppjni_main __attribute__((aligned (64)));
|
||||
|
||||
static inline u32 vppjni_get_context_id (vppjni_main_t * jm)
|
||||
{
|
||||
return __sync_add_and_fetch (&jm->context_id, 1);
|
||||
}
|
||||
|
||||
static inline void vppjni_lock (vppjni_main_t * jm, u32 tag)
|
||||
{
|
||||
while (__sync_lock_test_and_set (&jm->lock, 1))
|
||||
;
|
||||
jm->tag = tag;
|
||||
}
|
||||
|
||||
static inline void vppjni_unlock (vppjni_main_t * jm)
|
||||
{
|
||||
jm->tag = 0;
|
||||
CLIB_MEMORY_BARRIER();
|
||||
jm->lock = 0;
|
||||
}
|
||||
|
||||
static inline int vppjni_sanity_check (vppjni_main_t * jm)
|
||||
{
|
||||
if (!jm->is_connected)
|
||||
return VNET_API_ERROR_NOT_CONNECTED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO remove macros (code is now fully autogenerated)
|
||||
|
||||
/* M: construct, but don't yet send a message */
|
||||
#define M(T,t) \
|
||||
do { \
|
||||
jm->result_ready = 0; \
|
||||
mp = vl_msg_api_alloc(sizeof(*mp)); \
|
||||
memset (mp, 0, sizeof (*mp)); \
|
||||
mp->_vl_msg_id = ntohs (VL_API_##T); \
|
||||
mp->client_index = jm->my_client_index; \
|
||||
} while(0);
|
||||
|
||||
#define M2(T,t,n) \
|
||||
do { \
|
||||
jm->result_ready = 0; \
|
||||
mp = vl_msg_api_alloc(sizeof(*mp)+(n)); \
|
||||
memset (mp, 0, sizeof (*mp)); \
|
||||
mp->_vl_msg_id = ntohs (VL_API_##T); \
|
||||
mp->client_index = jm->my_client_index; \
|
||||
} while(0);
|
||||
|
||||
/* S: send a message */
|
||||
#define S (vl_msg_api_send_shmem (jm->vl_input_queue, (u8 *)&mp))
|
||||
|
||||
#endif /* __included_vppjni_h__ */
|
@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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.
|
||||
*/
|
||||
|
||||
package org.openvpp.jvpp;
|
||||
|
||||
/**
|
||||
* Base exception representing failed operation of JVpp request call
|
||||
*/
|
||||
public abstract class VppBaseCallException extends Exception {
|
||||
private final String methodName;
|
||||
private final int errorCode;
|
||||
|
||||
/**
|
||||
* Constructs an VppCallbackException with the specified api method name and error code.
|
||||
*
|
||||
* @param methodName name of a method, which invocation or execution failed
|
||||
* @param errorCode negative error code value associated with this failure
|
||||
* @throws NullPointerException if apiMethodName is null
|
||||
*/
|
||||
public VppBaseCallException(final String methodName, final int errorCode) {
|
||||
super(String.format("vppApi.%s failed with error code: %d", methodName, errorCode));
|
||||
this.methodName = java.util.Objects.requireNonNull(methodName, "apiMethodName is null!");
|
||||
this.errorCode = errorCode;
|
||||
if(errorCode >= 0) {
|
||||
throw new IllegalArgumentException("Error code must be < 0. Was " + errorCode +
|
||||
" for " + methodName );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns name of a method, which invocation failed.
|
||||
*
|
||||
* @return method name
|
||||
*/
|
||||
public String getMethodName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error code associated with this failure.
|
||||
*
|
||||
* @return a negative integer error code
|
||||
*/
|
||||
public int getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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.
|
||||
*/
|
||||
|
||||
package org.openvpp.jvpp;
|
||||
|
||||
/**
|
||||
* Callback Exception representing failed operation of JVpp request call
|
||||
*/
|
||||
public class VppCallbackException extends VppBaseCallException {
|
||||
private final int ctxId;
|
||||
|
||||
/**
|
||||
* Constructs an VppCallbackException with the specified api method name and error code.
|
||||
*
|
||||
* @param methodName name of a method, which invocation failed.
|
||||
* @param ctxId api request context identifier
|
||||
* @param errorCode negative error code value associated with this failure
|
||||
* @throws NullPointerException if apiMethodName is null
|
||||
*/
|
||||
public VppCallbackException(final String methodName, final int ctxId, final int errorCode ){
|
||||
super(methodName, errorCode);
|
||||
this.ctxId = ctxId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns api request context identifier.
|
||||
*
|
||||
* @return value of context identifier
|
||||
*/
|
||||
public int getCtxId() {
|
||||
return ctxId;
|
||||
}
|
||||
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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.
|
||||
*/
|
||||
|
||||
package org.openvpp.jvpp;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Representation of a management connection to VPP.
|
||||
* Connection is initiated when instance is created, closed with close().
|
||||
*/
|
||||
public interface VppConnection extends AutoCloseable {
|
||||
|
||||
/**
|
||||
* Open VppConnection for communication with VPP
|
||||
*
|
||||
* @param callback instance handling responses
|
||||
*
|
||||
* @throws IOException if connection is not established
|
||||
*/
|
||||
void connect(final org.openvpp.jvpp.callback.JVppCallback callback) throws IOException;
|
||||
|
||||
/**
|
||||
* Check if this instance connection is active.
|
||||
*
|
||||
* @throws IllegalStateException if this instance was disconnected.
|
||||
*/
|
||||
void checkActive();
|
||||
|
||||
/**
|
||||
* Closes Vpp connection.
|
||||
*/
|
||||
@Override
|
||||
void close();
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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.
|
||||
*/
|
||||
|
||||
package org.openvpp.jvpp;
|
||||
|
||||
/**
|
||||
* Exception thrown when Vpp jAPI method invocation failed.
|
||||
*/
|
||||
public class VppInvocationException extends VppBaseCallException {
|
||||
/**
|
||||
* Constructs an VppApiInvocationFailedException with the specified api method name and error code.
|
||||
*
|
||||
* @param methodName name of a method, which invocation failed.
|
||||
* @param errorCode negative error code value associated with this failure
|
||||
* @throws NullPointerException if apiMethodName is null
|
||||
*/
|
||||
public VppInvocationException(final String methodName, final int errorCode) {
|
||||
super(methodName, errorCode);
|
||||
}
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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.
|
||||
*/
|
||||
|
||||
package org.openvpp.jvpp;
|
||||
|
||||
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.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
import org.openvpp.jvpp.callback.JVppCallback;
|
||||
|
||||
/**
|
||||
* JNI based representation of a management connection to VPP
|
||||
*/
|
||||
public final class VppJNIConnection implements VppConnection {
|
||||
private final static Logger LOG = Logger.getLogger(VppJNIConnection.class.getName());
|
||||
private static final String LIBNAME = "libjvpp.so.0.0.0";
|
||||
|
||||
static {
|
||||
try {
|
||||
loadLibrary();
|
||||
} catch (Exception e) {
|
||||
LOG.severe("Can't find vpp 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 = VppJNIConnection.class.getResourceAsStream('/' + LIBNAME)) {
|
||||
if (is == null) {
|
||||
throw new IOException("Failed to open library resource " + LIBNAME);
|
||||
}
|
||||
loadStream(is);
|
||||
}
|
||||
}
|
||||
|
||||
private final String clientName;
|
||||
private volatile boolean disconnected = false;
|
||||
|
||||
/**
|
||||
* Create VPPJNIConnection instance for client connecting to VPP.
|
||||
*
|
||||
* @param clientName client name instance to be used for communication. Single connection per clientName is allowed.
|
||||
*/
|
||||
public VppJNIConnection(final String clientName) {
|
||||
this.clientName = Objects.requireNonNull(clientName,"Null clientName");
|
||||
}
|
||||
|
||||
/**
|
||||
* Guarded by VppJNIConnection.class
|
||||
*/
|
||||
private static final Map<String, VppJNIConnection> connections = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Initiate VPP connection for current instance
|
||||
*
|
||||
* Multiple instances are allowed since this class is not a singleton
|
||||
* (VPP allows multiple management connections).
|
||||
*
|
||||
* However only a single connection per clientName is allowed.
|
||||
*
|
||||
* @param callback global callback to receive response calls from vpp
|
||||
*
|
||||
* @throws IOException in case the connection could not be established
|
||||
*/
|
||||
public void connect(final JVppCallback callback) throws IOException {
|
||||
synchronized (VppJNIConnection.class) {
|
||||
if(connections.containsKey(clientName)) {
|
||||
throw new IOException("Client " + clientName + " already connected");
|
||||
}
|
||||
|
||||
final int ret = clientConnect(clientName, callback);
|
||||
if (ret != 0) {
|
||||
throw new IOException("Connection returned error " + ret);
|
||||
}
|
||||
connections.put(clientName, this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void checkActive() {
|
||||
if (disconnected) {
|
||||
throw new IllegalStateException("Disconnected client " + clientName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized final void close() {
|
||||
if (!disconnected) {
|
||||
disconnected = true;
|
||||
try {
|
||||
clientDisconnect();
|
||||
} finally {
|
||||
synchronized (VppJNIConnection.class) {
|
||||
connections.remove(clientName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static native int clientConnect(String clientName, JVppCallback callback);
|
||||
private static native void clientDisconnect();
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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.
|
||||
*/
|
||||
|
||||
package org.openvpp.jvpp.callback;
|
||||
import org.openvpp.jvpp.VppCallbackException;
|
||||
|
||||
/**
|
||||
* Base JVppCallback interface
|
||||
*/
|
||||
public interface JVppCallback {
|
||||
/**
|
||||
* onError callback handler used to report failing operation
|
||||
* @param ex VppCallbackException object containing details about failing operation
|
||||
*/
|
||||
void onError(VppCallbackException ex);
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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.
|
||||
*/
|
||||
|
||||
package org.openvpp.jvpp.callback;
|
||||
|
||||
/**
|
||||
* Notification callback
|
||||
*/
|
||||
public interface JVppNotificationCallback {
|
||||
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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.
|
||||
*/
|
||||
|
||||
package org.openvpp.jvpp.dto;
|
||||
|
||||
/**
|
||||
* Base interface for all dump requests
|
||||
*/
|
||||
public interface JVppDump extends JVppRequest {
|
||||
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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.
|
||||
*/
|
||||
|
||||
package org.openvpp.jvpp.dto;
|
||||
|
||||
/**
|
||||
* Base interface for all notification DTOs
|
||||
*/
|
||||
public interface JVppNotification {
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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.
|
||||
*/
|
||||
|
||||
package org.openvpp.jvpp.dto;
|
||||
|
||||
/**
|
||||
* Base interface for all reply DTOs
|
||||
*/
|
||||
public interface JVppReply<REQ extends JVppRequest> {
|
||||
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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.
|
||||
*/
|
||||
|
||||
package org.openvpp.jvpp.dto;
|
||||
|
||||
/**
|
||||
* Base interface for all dump replies
|
||||
*/
|
||||
public interface JVppReplyDump<REQ extends JVppRequest, RESP extends JVppReply<REQ>>
|
||||
extends JVppReply<REQ> {
|
||||
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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.
|
||||
*/
|
||||
|
||||
package org.openvpp.jvpp.dto;
|
||||
|
||||
import org.openvpp.jvpp.JVpp;
|
||||
import org.openvpp.jvpp.VppInvocationException;
|
||||
|
||||
/**
|
||||
* Base interface for all request DTOs
|
||||
*/
|
||||
public interface JVppRequest {
|
||||
|
||||
/**
|
||||
* Invoke current operation asynchronously on VPP
|
||||
*
|
||||
* @return context id of this request. Can be used to track incomming response
|
||||
*/
|
||||
int send(JVpp jvpp) throws VppInvocationException;
|
||||
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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.
|
||||
*/
|
||||
|
||||
package org.openvpp.jvpp.future;
|
||||
|
||||
|
||||
import org.openvpp.jvpp.dto.JVppReply;
|
||||
import org.openvpp.jvpp.dto.JVppRequest;
|
||||
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import org.openvpp.jvpp.notification.NotificationRegistryProvider;
|
||||
|
||||
/**
|
||||
* Future facade on top of JVpp
|
||||
*/
|
||||
public interface FutureJVppInvoker extends NotificationRegistryProvider, AutoCloseable {
|
||||
|
||||
/**
|
||||
* Invoke asynchronous operation on VPP
|
||||
*
|
||||
* @return CompletionStage with future result of an async VPP call
|
||||
* @throws org.openvpp.jvpp.VppInvocationException when send request failed with details
|
||||
*/
|
||||
<REQ extends JVppRequest, REPLY extends JVppReply<REQ>> CompletionStage<REPLY> send(REQ req);
|
||||
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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.
|
||||
*/
|
||||
|
||||
package org.openvpp.jvpp.future;
|
||||
|
||||
|
||||
import org.openvpp.jvpp.JVpp;
|
||||
import org.openvpp.jvpp.VppInvocationException;
|
||||
import org.openvpp.jvpp.dto.*;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import org.openvpp.jvpp.notification.NotificationRegistryProviderContext;
|
||||
|
||||
/**
|
||||
* Future facade on top of JVpp
|
||||
*/
|
||||
public class FutureJVppInvokerFacade extends NotificationRegistryProviderContext implements FutureJVppInvoker {
|
||||
|
||||
private final JVpp jvpp;
|
||||
|
||||
/**
|
||||
* Guarded by self
|
||||
*/
|
||||
private final Map<Integer, CompletableFuture<? extends JVppReply<?>>> requests;
|
||||
|
||||
public FutureJVppInvokerFacade(final JVpp jvpp,
|
||||
final Map<Integer, CompletableFuture<? extends JVppReply<?>>> requestMap) {
|
||||
this.jvpp = Objects.requireNonNull(jvpp, "Null jvpp");
|
||||
// Request map represents the shared state between this facade and it's callback
|
||||
// where facade puts futures in and callback completes + removes them
|
||||
// TODO what if the call never completes ?
|
||||
this.requests = Objects.requireNonNull(requestMap, "Null requestMap");
|
||||
}
|
||||
|
||||
protected final Map<Integer, CompletableFuture<? extends JVppReply<?>>> getRequests() {
|
||||
return this.requests;
|
||||
}
|
||||
|
||||
// TODO use Optional in Future, java8
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <REQ extends JVppRequest, REPLY extends JVppReply<REQ>> CompletionStage<REPLY> send(REQ req) {
|
||||
synchronized(requests) {
|
||||
try {
|
||||
final CompletableFuture<REPLY> replyCompletableFuture;
|
||||
final int contextId = jvpp.send(req);
|
||||
|
||||
if(req instanceof JVppDump) {
|
||||
replyCompletableFuture = (CompletableFuture<REPLY>) new CompletableDumpFuture<>(contextId);
|
||||
} else {
|
||||
replyCompletableFuture = new CompletableFuture<>();
|
||||
}
|
||||
|
||||
requests.put(contextId, replyCompletableFuture);
|
||||
if(req instanceof JVppDump) {
|
||||
requests.put(jvpp.send(new ControlPing()), replyCompletableFuture);
|
||||
}
|
||||
return replyCompletableFuture;
|
||||
} catch (VppInvocationException ex) {
|
||||
final CompletableFuture<REPLY> replyCompletableFuture = new CompletableFuture<>();
|
||||
replyCompletableFuture.completeExceptionally(ex);
|
||||
return replyCompletableFuture;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final class CompletableDumpFuture<T extends JVppReplyDump<?, ?>> extends CompletableFuture<T> {
|
||||
// The reason why this is not final is the instantiation of ReplyDump DTOs
|
||||
// Their instantiation must be generated, so currently the DTOs are created in callback and set when first dump reponses
|
||||
// is handled in the callback.
|
||||
private T replyDump;
|
||||
private final long contextId;
|
||||
|
||||
CompletableDumpFuture(final long contextId) {
|
||||
this.contextId = contextId;
|
||||
}
|
||||
|
||||
long getContextId() {
|
||||
return contextId;
|
||||
}
|
||||
|
||||
T getReplyDump() {
|
||||
return replyDump;
|
||||
}
|
||||
|
||||
void setReplyDump(final T replyDump) {
|
||||
this.replyDump = replyDump;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
// NOOP
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
package org.openvpp.jvpp.notification;
|
||||
|
||||
/**
|
||||
* Provides notification registry
|
||||
*/
|
||||
public interface NotificationRegistryProvider {
|
||||
|
||||
/**
|
||||
* Get current notification registry instance
|
||||
*/
|
||||
NotificationRegistry getNotificationRegistry();
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
package org.openvpp.jvpp.notification;
|
||||
|
||||
/**
|
||||
* Base class for notification aware JVpp facades
|
||||
*/
|
||||
public abstract class NotificationRegistryProviderContext implements NotificationRegistryProvider {
|
||||
|
||||
private final NotificationRegistryImpl notificationRegistry = new NotificationRegistryImpl();
|
||||
|
||||
public final NotificationRegistry getNotificationRegistry() {
|
||||
return notificationRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get instance of notification callback. Can be used to propagate notifications from JVpp facade
|
||||
*/
|
||||
protected final GlobalNotificationCallback getNotificationCallback() {
|
||||
return notificationRegistry;
|
||||
}
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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.
|
||||
*/
|
||||
|
||||
package org.openvpp.jvpp.test;
|
||||
|
||||
import org.openvpp.jvpp.JVpp;
|
||||
import org.openvpp.jvpp.JVppImpl;
|
||||
import org.openvpp.jvpp.VppCallbackException;
|
||||
import org.openvpp.jvpp.VppJNIConnection;
|
||||
import org.openvpp.jvpp.callback.GetNodeIndexCallback;
|
||||
import org.openvpp.jvpp.callback.ShowVersionCallback;
|
||||
import org.openvpp.jvpp.callback.SwInterfaceCallback;
|
||||
import org.openvpp.jvpp.dto.*;
|
||||
|
||||
public class CallbackApiTest {
|
||||
|
||||
private static class TestCallback implements GetNodeIndexCallback, ShowVersionCallback, SwInterfaceCallback {
|
||||
|
||||
@Override
|
||||
public void onGetNodeIndexReply(final GetNodeIndexReply msg) {
|
||||
System.out.printf("Received GetNodeIndexReply: context=%d, nodeIndex=%d\n",
|
||||
msg.context, msg.nodeIndex);
|
||||
}
|
||||
@Override
|
||||
public void onShowVersionReply(final ShowVersionReply msg) {
|
||||
System.out.printf("Received ShowVersionReply: context=%d, program=%s, version=%s, " +
|
||||
"buildDate=%s, buildDirectory=%s\n",
|
||||
msg.context, new String(msg.program), new String(msg.version),
|
||||
new String(msg.buildDate), new String(msg.buildDirectory));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwInterfaceDetails(final SwInterfaceDetails msg) {
|
||||
System.out.printf("Received SwInterfaceDetails: interfaceName=%s, l2AddressLength=%d, adminUpDown=%d, " +
|
||||
"linkUpDown=%d, linkSpeed=%d, linkMtu=%d\n",
|
||||
new String(msg.interfaceName), msg.l2AddressLength, msg.adminUpDown,
|
||||
msg.linkUpDown, msg.linkSpeed, (int)msg.linkMtu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(VppCallbackException ex) {
|
||||
System.out.printf("Received onError exception: call=%s, context=%d, retval=%d\n", ex.getMethodName(), ex.getCtxId(), ex.getErrorCode());
|
||||
}
|
||||
}
|
||||
|
||||
private static void testCallbackApi() throws Exception {
|
||||
System.out.println("Testing Java callback API");
|
||||
JVpp jvpp = new JVppImpl(new VppJNIConnection("CallbackApiTest"));
|
||||
jvpp.connect(new TestCallback());
|
||||
System.out.println("Successfully connected to VPP");
|
||||
|
||||
System.out.println("Sending ShowVersion request...");
|
||||
jvpp.send(new ShowVersion());
|
||||
|
||||
System.out.println("Sending GetNodeIndex request...");
|
||||
GetNodeIndex getNodeIndexRequest = new GetNodeIndex();
|
||||
getNodeIndexRequest.nodeName = "node0".getBytes();
|
||||
jvpp.send(getNodeIndexRequest);
|
||||
|
||||
System.out.println("Sending SwInterfaceDump request...");
|
||||
SwInterfaceDump swInterfaceDumpRequest = new SwInterfaceDump();
|
||||
swInterfaceDumpRequest.nameFilterValid = 0;
|
||||
swInterfaceDumpRequest.nameFilter = "".getBytes();
|
||||
jvpp.send(swInterfaceDumpRequest);
|
||||
|
||||
Thread.sleep(5000);
|
||||
|
||||
System.out.println("Disconnecting...");
|
||||
jvpp.close();
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
testCallbackApi();
|
||||
}
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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.
|
||||
*/
|
||||
|
||||
package org.openvpp.jvpp.test;
|
||||
|
||||
import org.openvpp.jvpp.JVpp;
|
||||
import org.openvpp.jvpp.JVppImpl;
|
||||
import org.openvpp.jvpp.VppCallbackException;
|
||||
import org.openvpp.jvpp.VppJNIConnection;
|
||||
import org.openvpp.jvpp.callback.WantInterfaceEventsCallback;
|
||||
import org.openvpp.jvpp.callfacade.CallbackJVppFacade;
|
||||
import org.openvpp.jvpp.dto.WantInterfaceEventsReply;
|
||||
|
||||
public class CallbackJVppFacadeNotificationTest {
|
||||
|
||||
private static void testCallbackFacade() throws Exception {
|
||||
System.out.println("Testing CallbackJVppFacade for notifications");
|
||||
|
||||
JVpp jvpp = new JVppImpl(new VppJNIConnection("CallbackApiTest"));
|
||||
|
||||
CallbackJVppFacade jvppCallbackFacade = new CallbackJVppFacade(jvpp);
|
||||
System.out.println("Successfully connected to VPP");
|
||||
|
||||
final AutoCloseable notificationListenerReg =
|
||||
jvppCallbackFacade.getNotificationRegistry().registerSwInterfaceSetFlagsNotificationCallback(
|
||||
NotificationUtils::printNotification
|
||||
);
|
||||
|
||||
jvppCallbackFacade.wantInterfaceEvents(NotificationUtils.getEnableInterfaceNotificationsReq(),
|
||||
new WantInterfaceEventsCallback() {
|
||||
@Override
|
||||
public void onWantInterfaceEventsReply(final WantInterfaceEventsReply reply) {
|
||||
System.out.println("Interface events started");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(final VppCallbackException ex) {
|
||||
System.out.printf("Received onError exception: call=%s, context=%d, retval=%d\n",
|
||||
ex.getMethodName(), ex.getCtxId(), ex.getErrorCode());
|
||||
}
|
||||
});
|
||||
|
||||
System.out.println("Changing interface configuration");
|
||||
NotificationUtils.getChangeInterfaceState().send(jvpp);
|
||||
|
||||
Thread.sleep(1000);
|
||||
|
||||
jvppCallbackFacade.wantInterfaceEvents(NotificationUtils.getDisableInterfaceNotificationsReq(),
|
||||
new WantInterfaceEventsCallback() {
|
||||
@Override
|
||||
public void onWantInterfaceEventsReply(final WantInterfaceEventsReply reply) {
|
||||
System.out.println("Interface events stopped");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(final VppCallbackException ex) {
|
||||
System.out.printf("Received onError exception: call=%s, context=%d, retval=%d\n",
|
||||
ex.getMethodName(), ex.getCtxId(), ex.getErrorCode());
|
||||
}
|
||||
});
|
||||
|
||||
notificationListenerReg.close();
|
||||
|
||||
Thread.sleep(2000);
|
||||
|
||||
System.out.println("Disconnecting...");
|
||||
jvpp.close();
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
testCallbackFacade();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user