The RESTful admin API Engine provides a REST implementation for the GET portion (i.e. no actions, no side effects) of the Admin API services.
The motivation for this project is to:
- Allow for non-java (e.g. scripting) clients to access the XAP Admin services
- Allow for Java clients to access XAP Admin without having to depend on XAP jars
- Allow client to overcome firewall barriers that may prevent direct Java calls
- Provide a POC for a larger planned project for providing RESTful API for the entire XAP services with
- When possible adhere to standard REST conventions , e.g. no client state stored on server, access objects
and services by URI, GET method having no side effects. Intrusive services which may have side effects - like deploy() or undeploy() may follow later by adding support to POST calls.
- Performance penalty should be "contained" while, as stated above, keeping adherence to REST
- Support SQL queries on all available spaces
- The original Admin API code must not be changed - not even by annotations
- Avoid local duplications of Admin API classes and interfaces by the RESTful engine
The RESTful API engine architecture is based on the following concepts and components:
- A central gateway which receives all of the incoming GET requests and to parse their URIs
- A reflective delegator is used to match the said URI elements against the Admin object's method list so to obtain the appropriate getter, and delegates control to the matched object and getter service. It is important to note that this is performed without the RESTful engine having to know or store a local representation of the Admin object.
- A simple SQL query uri notation is used to support space querying: <space-uri>/?<object-type>:<where-clause>, for example: http://myhost:8080/restful/admin/Spaces/SpaceInstances/0/?com.restful.test.pojo.Person:name=sam will return the Person object with name equals "sam". Note that the query support is currently limited to returning a single object.
- A local ID-getter cache is maintained to keep the performance impact contained when the engine needs to go over all of the object's public getters in look for a "get ID" service.
- A local space proxy cache is maintained to keep the performance impact contained when the engine needs to access the proxy in order to issue an sql query.
- A REST output module which stores a shorthand representation of the response objects in a generic document object containing keys and values. The document basically contains primitive fields and inner objects represented as URIs, and the values may possibly be documents themselves. Here too the RESTful engine does not have to know anything about the actual Admin
object used to construct the response document. Note that this document is self contained in the sense that all of the relevant data required to answer for the caller's request is packed inside it (data and URIs) so that the server does not have to store any user-specific state to answer future user's requests.
- This response document object is then serialized to a JSON object and transmitted back to the caller. Our solution relies on standard Spring capabilities for the JSON serialization and the overall client-server wiring.
Your good old web browser will do just fine!
We recommend using Firefox with https://addons.mozilla.org/en-US/firefox/addon/jsonview/ , but any web browser with good JSON will probably suffice.
Implementation Details - Class Description
A Spring MVC controller for the RESTful Admin API engine that uses a reflection-based implementation of dispatcher pattern
o Accepts a generic URI path which denotes a specific Admin request
o Parses and walks through the URI by activating getter methods to "dig into" the admin object hierarchy
o Results marshaled as a generic document serialized to a JSON object
Note that wiring and marshaling services are provided for this class by the Spring framework
Parsing of URI path is performed according to the following rules:
| URI Path Element
| Element Processing
|| (intermediate) resolve to arr[ind] and continue processing
|| (intermediate) resolve to map.get(key) and continue processing
|| (intermediate) resolve to list(index) and continue processing
|| (final) return obj fields (by public getters)
|| (final) return arr.length
|| (final) return list.size()
|| (final) return comma-separated list of map keys
Main dispatcher class for the output service. Delegates control to the appropriate typed-output classes.
Outputs an array object by returning its length so that the user may apply iteration to walk through all array elements using singular REST calls.
Action Item: replace with an implementation that outputs actual array elements
Outputs a list object by returning its length so that the user may apply iteration to walk through all array elements using singular REST calls
Action Item: replace with an implementation that outputs actual list elements
Outputs a map object by returning a comma-separated list of all of its keys so that the user may apply iteration to walk through all map elements using singular REST calls
Action Item: replace with an implementation that outputs actual map elements
Output a "simple" i.e. non-aggregate object: inner primitive members are outputted as-is by their public getters, inner objects are outputted by URI.
Provides reflection services for detecting and name-normalizing of valid getter functions.
Deals with special cases such as a details-object getter a boolean getter (boolean isXXXX())
Takes care for filtering out event-related getters so never sent to the user.
A getter handler that deals with the special case of an ID getter, i.e. a getter which returns an integer/string identifier of an admin object which is unique in a given scope (e.g. machine).
Go through all of object's getter methods and rates all id getter suspects it founds.
Sets the highest rated suspect to be the class's id getter e.g. getXxxPID() will be higher in list than getXxxID()
Maintains a non-persistent cache of id getters to lower impact on performance
Filters out suspicious but invalid getters such as getXXXByID, getXXXBackupID(), getPID()
Examples of valid id getters:
Looks for id-getter method in cache and , if not found, interrogates the object's class in look for such a getter.
If found - the getter is cached and then activated to obtain the object's id
Contains a blacklist of types that denotes a getter function as irrelevant to the REST API, e.g. Admin, Void