This document is for informational purposes only and is subject to change at any time without notice. The information in this document is proprietary to Actian and no part of this document may be reproduced, copied, or transmitted in any form or for any purpose without the express prior written permission of Actian.
This document is not intended to be binding upon Actian to any particular course of business, pricing, product strategy, and/or development. Actian assumes no responsibility for errors or omissions in this document. Actian shall have no liability for damages of any kind including without limitation direct, special, indirect, or consequential damages that may result from the use of these materials. Actian does not warrant the accuracy or completeness of the information, text, graphics, links, or other items contained within this material. This document is provided without a warranty of any kind, either express or implied, including but not limited to the implied warranties of merchantability, fitness for a particular purpose, or non-infringement.
Disclaimer
Actian Hybrid DataConference2018 London
ActianHybrid DataConference2018 London
Bodo Bergmann
Implementing Applications with OpenROAD JSON-RPC
Cristian Ianculovici
Principal EngineerSupport
Principal Software Engineer
@crisianculovici
Agenda
JSON FeaturesJSON-RPC SupportJSON-RPC ConfigurationExamples, Tips & TricksDemo
JSON Features
JSON Features
▪Available in OR 6.2.0 with patch > 15261–Use later patches containing problem fixes
▪Generic JSON support classes▪JSON-RPC support for OpenROAD Server access
6 © 2018 Actian Corporation
JSON Support
▪JSON = JavaScript Object Notation– compact, text-based data format for data exchange• Data objects consisting of name-value pairs for attributes
– Language-independent• Directly usable in JavaScript• JSON support for many other languages (e.g. Java, C#, Python, etc.)
– Most common data format used for browser/server communication– http://json.org
© 2018 Actian Corporation7
{"aint" : 1,"afloat" : 123.456,"astring" : "Abc\tDef\nGhi\u20ac","isbig" : true,"isold" : false,"obj1" : null,"obj2" : {},"obj2" : {"attr1" : "x", },"arr1" : [123, true, null, "Blabla", 5.6e10, [],{"o":false}],"arr2" : [],"arr3" : null}
"string"
number
{object}
[array]
false
true
null
Generic JSON Support Classes
© 2018 Actian Corporation8
JsonValueabstract superclass
JsonNullJSON: null
JsonBooleanJSON: true/false
JsonNumberJSON: number
JsonStringJSON: string
JsonObjectJSON: object
JsonArrayJSON:
array
JsonHandler
JSONdocument
OpenROAD objects
Classes to represent JSON types– JsonValue and subclasses
– Provide conversion between JsonObjectand OpenROAD objects (both directions)
– Parse JSON from StringObject or file into JsonValue subclass objects
– Write JSON from JsonValue subclass objects into StringObject or file
JsonHandler class
JsonValue →OpenROAD Type Mappings
© 2018 Actian Corporation9
JsonValue subclass OpenROAD types
JsonNumber float (any precision), integer (any size), decimal, money
JsonString varchar, nvarchar, dateIn JsonString absolute dates are specified in ISO8601 format:"yyyy-mm-ddThh:mi:ssZ"
JsonBoolean any numeric type (values: true=1, false=0).There is no boolean type in OpenROAD (yet).
JsonNull NULL (for both nullable scalar types and references)
JsonObject Object
JsonArray Rows of an ArrayObject.The items of the JsonArray must be JsonObject instances.
Handling Multiple and Circular References
▪Object referenced multiple times gets "$id" member in addition to members for the attributes▪References to same object: Object with the "$ref" member only
© 2018 Actian Corporation10
// with circular referenceperson1.name = 'Joseph';person2.name = 'Mary';person1.spouse =person2;person2.spouse =person1;
{"$id" : "1","name" : "Joseph""spouse" : {
"name" : "Mary","spouse" : { "$ref" : "1"
}}
}
JSON representation:OpenROAD 4GL code:
JSON-RPC Support
JSON-RPC Support
▪JSON-RPC is a JSON based Remote Procedure Call protocol standard– http://www.jsonrpc.org/specification
© 2018 Actian Corporation12
Request:{"jsonrpc": "2.0", "method": "foobar", "id": "1"}
Response - error:{"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "1"}
Request:{"jsonrpc": "2.0", "method": "subtract", "params": {"subtrahend": 23, "minuend": 42},"id": 3}
Response - result:{"jsonrpc": "2.0", "result": 19, "id": 3}
JSON-RPC Support for OpenROAD
▪JSON-RPC 2.0 interface for calling 4GL procedures contained in OpenROAD Server applications– The "params" member within an JSON-RPC request has to be a JSON
object containing members for the named parameters• Reason: Parameters to 4GL procedures are always passed by name (never by
position)
▪Makes the OpenROAD procedures available to many client applications/architectures– Via HTTP(S)– Can even use "curl" command line utility▪Removes existing limitations for OpenROAD server procedure calls (Call4GL/Callproc methods)
© 2018 Actian Corporation13
Calling OpenROAD 4GL Procedures from the "outside world"
© 2018 Actian Corporation14
OpenROAD ServerHttpServer w/
OpenROADJSONRPC servlet OpenROA
D Server application
s
JavaScript
curl
C#
...
C:\temp> curl -d "{\"jsonrpc\":\"2.0\", \"id\":1,
\"method\":\"subtract\",
\"params\":{\"subtrahend\":23.4,\"minuend\":42.8},}"
--header "Content-Type: application/json"
http://somehost:8080/orjsonrpc/myapp
{"result":19.4, "id":1, "jsonrpc":"2.0"}
procedure subtract(minuend = FLOAT NOT
NULL,subtrahend = FLOAT NOT
NULL)={
return minuend-subtrahend;}
HTTP(S) POST request
w/ JSON data
Calling OpenROAD 4GL Procedures from the "outside world"
© 2018 Actian Corporation15
OpenROAD Server
OpenROADJSONRPC servlet in HttpServer
OpenROAD Server
applications
Java
HTTP(S) client(Python, curl, JavaScript, ...)
C# (.NET)
HTTP(S) POST request
(data: JSON-RPC request)
OpenROAD
(D)COM client(VBA, VBScript,
...)
RemoteServer.JsonRpcReque
st()
(D)COM connection
"http-jsonrpc" routing
JSON-RPC Features
▪Subclass objects/arrays can be passed to parameters of a defined class/array– Avoids SCP proliferation
▪Objects and arrays of system classes can be passed▪Language independent
– Like the existing XML interface, but without its limitations
▪4GL procedures can have a return value– Will be represented in the "result" of the response message– No need to wrap procedure by an SCP with ByRef parameter
▪Different ways to return values to the caller– Return value and/or ByRef parameters
▪Multiple and circular references are preserved in objects passed as parameters and returned.– Represented using "$id" and "$ref" meta properties.
© 2018 Actian Corporation16
JSON-RPC Features (cont.)
▪A batch of requests is possible to be passed to the server with one call– JSON array containing request objects– Response will contain an array of response objects
▪New RemoteServer class method to serve all server procedure calls:response = JsonRpcRequest(request);
– Strings for request and response (OpenROAD:StringObject, COM:BSTR, C#:string, Java:String)
– The actual procedure to be executed will be passed in the "method" parameter of the "request" string.
– No need for ParameterData objects
▪OpenROADJSONRPC servlet– Java servlet to be used in a Servlet container or Web Server like
Tomcat– Extracts the JSON payload from a HTTP POST message– Invokes the JsonRpcRequest() method with this payload as request• Uses a RemoteServer object from a pool of connected objects
– Returns JSON response as response payload of the HTTP message.© 2018 Actian Corporation17
JSON-RPC Configuration
JSON-RPC config File
© 2018 Actian Corporation19
{"registeredprocs" : {"rows":[
{"name":"subtract","params":{"rows":[{"name":"minuend"},{"name":"subtrahend"}
]}},{"name":"helloworld",
"params":{"rows":[{"name":"hellostring", "byref_use":true},{"name":"counter", "byref_use":true}
]}}}
}
▪Names of 4GL Procedures available for JSON-RPC requests and their parameters are configured via file– Use of BYREF for a parameter can also be determined
▪Filename ApplicationName.json▪Location specified by environment variable
II_W4GL_JSON_CONFIG– Default: "orjsonconfig" subdirectory of %II_CONFIG%
(%II_SYSTEM%\ingres\files)
JSON-RPC Support for OpenROAD - Examples
▪Using batch of requests
© 2018 Actian Corporation20
Request:[{"jsonrpc": "2.0", "method": "subtract", "params": {"subtrahend": 23, "minuend": 42},"id": 1},{"jsonrpc": "2.0", "method": "xyz"},{"jsonrpc": "2.0", "method": "dummy", "id": 2},{"jsonrpc": "2.0", "method": "subtract", "params": {" minuend": 3, "subtrahend": 1}, "id":3}]
Response:[
{"jsonrpc": "2.0", "result": 19, "id": 1},{"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": 2},{"jsonrpc": "2.0", "result": 2, "id": 3}
]
JSON-RPC Support for OpenROAD - Examples
▪Using BYREF parameters - defined by pseudo-parameter "$byref_params"
© 2018 Actian Corporation21
JSON-RPC request:
JSON-RPC response:
// 4GL Procedure in OpenROAD Server application:procedure helloworld(hellostring = VARCHAR(100) NOT NULL, counter = INTEGER NOTNULL)= {…}
{"jsonrpc": "2.0","method": "helloworld","params": {"hellostring": "HELLO","counter": 0,"$byref_params":
"hellostring,counter"},"id": 2
}
{"result": {"result": null,"byref_results": {"hellostring": "Well \"HELLO\" to you
too.","counter": 1
}},"id": 2,"jsonrpc": "2.0"
}
Examples, Tips & Tricks
Examples, tips & tricks
▪Userclass Object Serialization/Deserialization
▪OpenROAD Server: Single procedure interface for userclass method invocations▪Access OpenROAD server without any client installation requirements
© 2018 Actian Corporation23
Userclass Object Serialization/Deserialization
▪No need to add special methods to each user class
▪Same approach can be used to write/read userclass objects to/from file or StringObject
© 2018 Actian Corporation24
jh = JsonHandler;jsonString = Stringobjectjv = JsonValue DEFAULT NULL;myobject = myClass;…// Serializejv = jh.Object2JsonValue(object = myobject);jh.WriteFile(value =jv, filename = filename); // to filejh.Write(value = jv, json = jsonString); // to StringObject
// Deserializemyobject = myClass.Create(); // new instancejv = jh.ParseFile(filename = filename); // from filejv = jh.Parse(json = jsonString); // from StringObjectjh.JsonObject2Object(jsonobj = jv, existing_obj = myobject);
OpenROAD Server: Single procedure interface for userclass method invocations
▪Task: Pass userclass object to OpenROAD Server and invoke method– Subclasses define same methods, which they override (polymorphism)– Example: Superclass Model with methods like GetObject() and SaveObject(),
which are redefined in all (hundreds of) subclasses
▪Before:– For each userclass you had to define (or generate) 4GL Procedures (SCPs)
wrapping the method invocation on the object of the specific class.• Could not pass subclass objects
– Proliferation of SCPs: Often one SCP per method (e.g. called "userclassname_methodname").
▪Now:– Can specify one generic 4GL procedure for all subclasses to serve all
methods with same signature.
© 2018 Actian Corporation25
OpenROAD Server: Single procedure interface for userclass method invocations▪4GL Procedures for invoking GetObject() and SaveObject() methods:
© 2018 Actian Corporation26
PROCEDURE SaveObject( obj = Model )= // obj can be any Model subclass object{
RETURN obj.SaveObject(); // returns status - 0=ER_OK}
Request:{"jsonrpc": "2.0", "id": 2, "method": "SaveObject", "params": {"obj": {"classname": "airline", "al_name":"Air Canada","al_ccode":"CA","al_icaocode":"ACA","al_iatacode":"AC"}}}Response:{"result": 0, "id":2,"jsonrpc":"2.0"}
PROCEDURE GetObject( obj = Model )= // obj can be any Model subclass object{
IF obj.GetObject()=ER_OK THENRETURN obj;
ELSERETURN NULL;
ENDIF;}
Request:{"jsonrpc": "2.0", "id": 1, "method": "GetObject", "params": {"obj": {"classname": "airline", "al_icaocode":"ACA"}}}Response:{"result":{"al_id":"357","classname":"airline","al_name":"Air Canada","al_ccode":"CA","al_icaocode":"ACA","al_iatacode":"AC"},"id":1,"jsonrpc":"2.0"}
Access OpenROAD server without any client installation requirements
▪Use HTTP request object - available in almost every programming environment– Send HTTP POST request with JSON-RPC as data
▪Example - VBA (e.g. Excel):
© 2018 Actian Corporation27
Dim httpReq As ObjectDim jsonrpcReq As StringDim strResponse As String
jsonrpcReq = "{""jsonrpc"": ""2.0"", ""id"": 1, ""method"": ""subtract"" , _""params"": {""subtrahend"": 23.4, ""minuend"": 42.8}}"
Set httpReq = CreateObject("MSXML2.ServerXMLHTTP")httpReq.Open "POST", "http://yourwebserver:8080/openroad/jsonrpcservertest", FalsehttpReq.Send jsonrpcReqstrResponse = httpReq.responseText
'ToDo: Parse the JSON in strResponse and populate cells with the resultMsgBox strResponse
Examples on GitHub
▪ JSON-RPC– https://github.com/ActianCorp/OpenROAD_json
© 2018 Actian Corporation28
Demo
Legacy OpenROAD Server Call
GK_URL = config.protocol + '://' + config.server_name + ':' + config.port +
'/openroad/gatekeeper';
CurRemoteServer = REMOTESERVER.CREATE();
i_status = CurRemoteServer.Initiate(
Image = AKAname,
Type = RP_SHARED,
Location = GK_URL,
Routing = 'http'
);
. . .
status = CurRemoteServer.Call4GL('set_token_owner',
token = v_group_info[my_group_id].token_owner,
group_id=v_group_info[my_group_id].group_id
login_user=user,
issue='assigned'
);
Calling JSON-RPC from OpenROAD
‘request’ is– A StringObject– A JSON string
declare
JRemoteServer = RemoteServer;. . .
JRemoteServer = REMOTESERVER.CREATE();JSON_URL = config.protocol + '://' + config.server_name + ':' +
config.port + '/openroad/' + AKAName ;
i_status = JRemoteServer.Initiate(Image = AKAname,Type = ConnectionType,Location = JSON_URL,Routing = 'http-jsonrpc');
. . .response = JRemoteServer.JsonRpcRequest(request=request);
Building the JSON String
32 © 2018 Actian Corporation
▪Request:
{"jsonrpc": "2.0", "method": "subtract", "params": {"subtrahend": 23, "minuend": 42}, "id":3}
• We can build the string as:request = ‘{“‘ + … + ‘”}’
Building the JSON String
▪Or we can do
…
declare
paramsJson = JsonObject,
enddeclare
…paramsJson.newMember('token', v_group_info[my_group_id].token_owner);
paramsJson.newMember('group_id', v_group_info[my_group_id].group_id);
paramsJson.newMember('login_user', user);
paramsJson.newMember('issue', 'assigned');
Or
paramsJson.parse(‘”token”:” + …);
33 © 2018 Actian Corporation
Building the JSON String
▪Call a JSON generator 4GL procedure
34 © 2018 Actian Corporation
procedure createJsonRequest(outputType = integer not null default 0,id = integer,methodName = varchar(128),params = JsonObject,
)=declare
result = JsonObject,resultString = StringObject,
enddeclare
Building the JSON String
{
result.newMember(name='jsonrpc', value='2.0');
result.newMember(name='id', value=id);
result.newMember(name='method', value=methodName);
result.addMember(name='params', value=params);
if outputType = 0 then
return result;
else
CurSession.JsonHandler.Write(
value = result,
json = resultString);
return resultString;
endif;
}
35 © 2018 Actian Corporation
Demo
Thank you!