JSON-RPC Protocol: Difference between revisions

From KitwarePublic
Jump to navigationJump to search
No edit summary
 
Line 1: Line 1:
==JSON RPC==
=JSON RPC=
Refer to http://json-rpc.org/wiki/specification for details on how json-rpc
Refer to http://json-rpc.org/wiki/specification for details on how json-rpc
calls are made and how responses/errors are returned.
calls are made and how responses/errors are returned.
Line 22: Line 22:
</source>
</source>


==Communicating with the WebServer==
=Communicating with the WebServer=
Clients can only communicate with the web server. When communicating with the
Clients can only communicate with the web server. When communicating with the
ParaViewAdaptor, they still need to route the requests through the web-server.
ParaViewAdaptor, they still need to route the requests through the web-server.
Line 28: Line 28:
requests.
requests.


===Obtaining list of available RMIs===
==Obtaining list of available RMIs==
Call "system.listMethods" with no parameters to obtain a list available RMIs.
Call "system.listMethods" with no parameters to obtain a list available RMIs.


Line 57: Line 57:
Next we will see each of these methods and how and when to use them.
Next we will see each of these methods and how and when to use them.


===Creating a new visualization session i.e. start a new ParaViewAdaptor===
==Creating a new visualization session i.e. start a new ParaViewAdaptor==


Visualization is done by ParaViewAdaptor which is ParaView-based application.
Visualization is done by ParaViewAdaptor which is ParaView-based application.
Line 91: Line 91:
communication affecting this session.
communication affecting this session.


===Terminating a session===
==Terminating a session==
To gracefully close (or abort if close fails) a ParaViewAdaptor instance use the
To gracefully close (or abort if close fails) a ParaViewAdaptor instance use the
following request:
following request:
Line 114: Line 114:
Note that this call never returns a jsonrpc error.
Note that this call never returns a jsonrpc error.


===Communicating with a ParaViewAdaptor instance===
==Communicating with a ParaViewAdaptor instance==
For all other interesting communications, one needs to talk with
For all other interesting communications, one needs to talk with
ParaViewAdaptor. These include requests to create visualization pipeline
ParaViewAdaptor. These include requests to create visualization pipeline
Line 151: Line 151:
</source>
</source>


==Communicating with ParaViewAdaptor==
=Communicating with ParaViewAdaptor=


ParaViewAdaptor handles all JSON messages sent to it by forwarding them to  the
ParaViewAdaptor handles all JSON messages sent to it by forwarding them to  the
Line 163: Line 163:
message as explained in the previous section.
message as explained in the previous section.


===Plugins===
==Plugins==


====Getting the list of plugins available====
===Getting the list of plugins available===


Plugins are python scripts that are placed in a directory specified by the
Plugins are python scripts that are placed in a directory specified by the
Line 189: Line 189:
</source>
</source>


====Getting list of functions available in a plugin====
===Getting list of functions available in a plugin===


Once one knows the list of plugins, to know what functions are available in a
Once one knows the list of plugins, to know what functions are available in a
Line 217: Line 217:
</source>
</source>


====Calling a function in a plugin====
===Calling a function in a plugin===


To call a function in a plugin, use the following form.
To call a function in a plugin, use the following form.
Line 258: Line 258:
pwsimple as a special plugin available by default to all session and having a
pwsimple as a special plugin available by default to all session and having a
slightly different API to access it.
slightly different API to access it.
===Getting the list of functions available===
Use get_module() to obtain the list of functions.
Request:
<source lang="javascript">
{
  "id": <num>,
  "method": "get_module",
  "params": []
}
</source>
Response:
<source lang="javascript">
{
  "id": <num>,
  "result": [ "func1", "func2" ...],
  "error" : null
}
</source>
===Invoke a function in pwsimple===
We use execute_command for that. The return value can be object representing a
proxy. We will see how proxies are defined in the following section.
Request:
<source lang="javascript">
{
  "id": <num1>,
  "method": "execute_command",
  "params": {
            "id": <num2>,
            "method": "<function_name>",
            "params": [<params to function>]
            }
}
</source>
Response:
<source lang="javascript">
{
  "id": <num1>,
  "result": {
            "id": <num2>,
            "result": <return value from function>,
            "error": null
            },
  "error" : null
}
</source>
==Dealing with Proxies==
When it comes to creating/updating visualization pipelines, one cannot but run
into proxies. Proxies are objects that represent various components in the
visualization pipelines including views, representations, sources, filters,
readers. pwsimple as well as plugins can export functions that return proxies.
The JSON api gracefully handles returning of the proxies to the client so that
the client can use them when constructing future requests.
A JSON object for a proxy is of the following structure:
<source lang="javascript">
{
  "__jsonclass__": "Proxy",
  "__selfid__": "85",
  "__methods__": ["ListProperties"],
  "__properties__": ["GUISize", .., "ViewSize"],
}
</source>
The __jsonclass__ helps us identify that the object is a proxy. When such a
object is passed in as an parameter to pwsimple or a plugin as described
earlier, then it automatically gets replaced by the actual Proxy object before
evaluation.
__selfid__ is a unique identifier for the proxy. Every proxy gets a __selfid__
once it's created. One should never change this. This is critical to ensure that
the right Proxy is identified.
__methods__ is the list of methods available on the Proxy object itself. One
can use execute_command_on in pwservice to call such methods.
__properties__ is the list of properties or parameters on the proxy object. One
can update these by using the handle_property function in pwservice.
===Calling a Proxy method===
To call one of the methods defined on the proxy, use the following message:
Request:
<source lang="javascript">
{
  "id": <num1>,
  "method": "execute_command_on",
  "params": {
            "id": <num2>,
            "method": "<proxy.__selfid__>",
            "params": {
                      "id": <num3>,
                      "method": "method-name",
                      "params": [<arguments>]
                      }
            }
}
</source>
Response:
<source lang="javascript">
{
  "id": num1,
  "result": {
            "id": <num2>,
            "result": <return value>,
            "error": null
            },
  "error": null
}
</source>
===Setting a Property value on a Proxy===
Request:
<source lang="javascript">
{
  "id": <num1>,
  "method": "handle_property",
  "params": {
            "id":<num2>,
            "method": "proxy.__selfid__",
            "params": {
                      "id": <num3>,
                      "method" : "set<PropertyName>",
                      "params" : <arguments>
                      }
            }
}
</source>
Response:
<source lang="javascript">
{
  "id": <num1>,
  "result": {
            "id": <num2>,
            "result": <return value>,
            "error": null
            },
  "error": null
}
</source>
===Getting a Property value on a Proxy===
Request:
<source lang="javascript">
{
  "id": <num1>,
  "method": "handle_property",
  "params": {
            "id":<num2>,
            "method": "proxy.__selfid__",
            "params": {
                      "id": <num3>,
                      "method" : "get<PropertyName>",
                      "params" : []
                      }
            }
}
</source>
Response:
<source lang="javascript">
{
  "id": <num1>,
  "result": {
            "id": <num2>,
            "result": <return value>,
            "error": null
            },
  "error": null
}
</source>

Latest revision as of 15:07, 15 September 2010

JSON RPC

Refer to http://json-rpc.org/wiki/specification for details on how json-rpc calls are made and how responses/errors are returned.

In summary: A JSONRPC call is of the following structure: <source lang="javascript"> {

 "id": <number>,
 "method": <string identifying the method to call>,
 "params": [list of parameters]

} </source>

A response is of the following form: <source lang="javascript"> {

 "id" : <number>,
 "result" : <reply>,
 "error" : null or error message/object or missing if no error.

} </source>

Communicating with the WebServer

Clients can only communicate with the web server. When communicating with the ParaViewAdaptor, they still need to route the requests through the web-server. <context-root>/PWService/json is the URL for the servlet that accepts JSON requests.

Obtaining list of available RMIs

Call "system.listMethods" with no parameters to obtain a list available RMIs.

Request: <source lang="javascript"> {

 "id": <num>,
 "method" : "system.listMethods",
 "params" : []

} </source>

Response: <source lang="javascript"> {

 "id": <num>,
 "result" : ["methodname1", "methodname2", ...]

} </source>

The methods exposed are defined in: <ParaViewWebSource>/WebServer/PWService/src/java/org/paraview/ParaViewVisualizationService.java

To invoke any of the methods returned, one simply creates a JSONRPC message with the "method" string referring to the method to call, and params matching the params expected on the servlet (defined in ParaViewVisualizationService.java)

Next we will see each of these methods and how and when to use them.

Creating a new visualization session i.e. start a new ParaViewAdaptor

Visualization is done by ParaViewAdaptor which is ParaView-based application. For every visualization session, we need a new ParaViewAdaptor instance. This is referred to as a visualization session. To create a visualization session or launch an instance of ParaViewAdaptor, use the following request:

Request: <source lang="javascript"> {

 "id": <num>,
 "method": "VisualizationsManager.createVisualization",
 "params": ["session-name", "descriptive comments/text", "configuration"]

} </source>

Where the parameters are: "session-name" : is an arbitrary string used to humanly identify the session. It's merely used by the admin page when listing all sessions. "descriptive comments": arbitrary comments again used for listing on admin page. "configuration" : identifies the configuration in pw-config.properties file. Confuguration is essential to identify how to start ParaViewAdaptor as well as locations of plugin directories etc. e.g. "default"

Response: <source lang="javascript"> {

 "id": <num>,
 "result": "session-id"

} </source>

"session-id" is a unique identifier for the session. Use this for subsequent communication affecting this session.

Terminating a session

To gracefully close (or abort if close fails) a ParaViewAdaptor instance use the following request:

Request: <source lang="javascript"> {

 "id": <num>,
 "method": "VisualizationsManager.stopVisualization",
 "params": ["session-id"]

} </source>

Response: <source lang="javascript"> {

 "id": <num>,
 "result": "SUCCESS" or "ERROR <message>"

} </source>

Note that this call never returns a jsonrpc error.

Communicating with a ParaViewAdaptor instance

For all other interesting communications, one needs to talk with ParaViewAdaptor. These include requests to create visualization pipeline objects, update their parameters, get information about them etc. All these communications are made using the "invoke" request as follows:

Request: <source lang="javascript"> {

 "id": <num>,
 "method": "VisualizationsManager.invoke",
 "params":["session-id", "string message to forward to ParaViewAdaptor"]

} </source>

Response: <source lang="javascript"> {

 "id": <num>,
 "result": "string of response from ParaViewAdaptor"

} </source>

All messages sent to ParaViewAdaptor using this route themselves are JSONRPC messages (as are the responses).

The next sections explains the JSON messages that can be sent to ParaViewAdaptor. All the JSON-RPC objects created must be converted to a string and then set as the params for the invoke message e.g. <source lang="javascript"> {

 "id": <num>,
 "method" : "VisualizationsManager.invoke",
 "params" : ["session-id", "{\"id\": <num>, \"method\":\"get_module\", \"params\":[]}"]

} </source>

Communicating with ParaViewAdaptor

ParaViewAdaptor handles all JSON messages sent to it by forwarding them to the Python interpreter where they are processed. For WebServer, the ParaViewVisualizationService.java defines the exposed API similarly for ParaViewAdaptor, <ParaViewWebSource>/ParaViewAdapter/pwservice.py defines the RMI calls available.

Note that all these calls are typically routed through the WebServer in which case the requests as well as responses themselves are wrapped in another JSONRPC message as explained in the previous section.

Plugins

Getting the list of plugins available

Plugins are python scripts that are placed in a directory specified by the pw-config.properties file. To get a list of available plugins call get_plugins().

Request: <source lang="javascript"> {

 "id": <num>,
 "method": "get_plugins",
 "params": []

} </source>

Response: <source lang="javascript"> {

 "id": <num>,
 "result": ["plugin_name_1", "plugin_name_2"],
 "error" : null

} </source>

Getting list of functions available in a plugin

Once one knows the list of plugins, to know what functions are available in a particular plugin, use:

Request: <source lang="javascript"> {

 "id": <num>,
 "method": "get_plugin",
 "params": ["<plugin_name>"]

} </source>

The result is a JSON object as follows: Response: <source lang="javascript"> {

 "id": <num>,
 "result": {
           "__jsonclass__" : "Plugin",
           "__selfid__"    : "<plugin_name>",
           "__methods__"   : ["func1", "func2", func3"]
           },
 "error" : null

} </source>

Calling a function in a plugin

To call a function in a plugin, use the following form.

Request: <source lang="javascript"> {

 "id": <num1>,
 "method": "execute_command_on_plugin",
 "params": {
           "id" : <num2>,
           "method" : "<plugin-name>",
           "params" : {
                      "id": <num3>,
                      "method": "<func_name>",
                      "params": [ <params to the function> ]
                      }
           }

} </source>

Response: <source lang="javascript"> {

 "id": <num1>,
 "result": {
           "id": <num2>,
           "result": <return value from <plugin_name>.<func_name> or null>,
           "error": null
           },
 "error" : null

} </source>

Using pwsimple.py

pwservice.py defines the RMI calls available, while pwsimple.py defines all visualization specific API. pwsimple.py is a extension of ParaView's simple.py and hence has all functions defined in simple.py plus a few more. One can think of pwsimple as a special plugin available by default to all session and having a slightly different API to access it.

Getting the list of functions available

Use get_module() to obtain the list of functions.

Request: <source lang="javascript"> {

 "id": <num>,
 "method": "get_module",
 "params": []

} </source>

Response: <source lang="javascript"> {

 "id": <num>,
 "result": [ "func1", "func2" ...],
 "error" : null

} </source>

Invoke a function in pwsimple

We use execute_command for that. The return value can be object representing a proxy. We will see how proxies are defined in the following section.

Request: <source lang="javascript"> {

 "id": <num1>,
 "method": "execute_command",
 "params": {
           "id": <num2>,
           "method": "<function_name>",
           "params": [<params to function>]
           }

} </source>

Response: <source lang="javascript"> {

 "id": <num1>,
 "result": {
           "id": <num2>,
           "result": <return value from function>,
           "error": null
           },
 "error" : null

} </source>

Dealing with Proxies

When it comes to creating/updating visualization pipelines, one cannot but run into proxies. Proxies are objects that represent various components in the visualization pipelines including views, representations, sources, filters, readers. pwsimple as well as plugins can export functions that return proxies. The JSON api gracefully handles returning of the proxies to the client so that the client can use them when constructing future requests.

A JSON object for a proxy is of the following structure:

<source lang="javascript"> {

 "__jsonclass__": "Proxy",
 "__selfid__": "85",
 "__methods__": ["ListProperties"],
 "__properties__": ["GUISize", .., "ViewSize"],

} </source>

The __jsonclass__ helps us identify that the object is a proxy. When such a object is passed in as an parameter to pwsimple or a plugin as described earlier, then it automatically gets replaced by the actual Proxy object before evaluation.

__selfid__ is a unique identifier for the proxy. Every proxy gets a __selfid__ once it's created. One should never change this. This is critical to ensure that the right Proxy is identified.

__methods__ is the list of methods available on the Proxy object itself. One can use execute_command_on in pwservice to call such methods.

__properties__ is the list of properties or parameters on the proxy object. One can update these by using the handle_property function in pwservice.

Calling a Proxy method

To call one of the methods defined on the proxy, use the following message:

Request: <source lang="javascript"> {

 "id": <num1>,
 "method": "execute_command_on",
 "params": {
           "id": <num2>,
           "method": "<proxy.__selfid__>",
           "params": {
                     "id": <num3>,
                     "method": "method-name",
                     "params": [<arguments>]
                     }
           }

} </source>

Response: <source lang="javascript"> {

 "id": num1,
 "result": {
           "id": <num2>,
           "result": <return value>,
           "error": null
           },
 "error": null

} </source>

Setting a Property value on a Proxy

Request: <source lang="javascript"> {

 "id": <num1>,
 "method": "handle_property",
 "params": {
           "id":<num2>,
           "method": "proxy.__selfid__",
           "params": {
                     "id": <num3>,
                     "method" : "set<PropertyName>",
                     "params" : <arguments>
                     }
           }

} </source>

Response: <source lang="javascript"> {

 "id": <num1>,
 "result": {
           "id": <num2>,
           "result": <return value>,
           "error": null
           },
 "error": null

} </source>

Getting a Property value on a Proxy

Request: <source lang="javascript"> {

 "id": <num1>,
 "method": "handle_property",
 "params": {
           "id":<num2>,
           "method": "proxy.__selfid__",
           "params": {
                     "id": <num3>,
                     "method" : "get<PropertyName>",
                     "params" : []
                     }
           }

} </source>

Response: <source lang="javascript"> {

 "id": <num1>,
 "result": {
           "id": <num2>,
           "result": <return value>,
           "error": null
           },
 "error": null

} </source>