This is the second in my series of exploring EGL web service generation and runtime. (You can read the first installment Exploring Web service generation and runtime - an overview
.) This installment covers the generation and runtime for REST services and REST service invocations.
First the service. Back when we first started looking at implementing an EGL REST service, we had many design sessions and internally we spent a lot of time discussing different implementations. Based on those conversations and the fact that EGL service part is modeled after RPC, we started looking at JSON RPC. We discovered a couple of areas where JSON RPC didn't correlate with EGL: 1) EGL has multiple return parameters and JSON RPC has only a single return, and 2) EGL service functions throw a ServiceInvocationException which can contain more information than the JSON RPC simple error object. That's why you'll notice the EGL REST RPC service resembles a JSON RPC service, but is not JSON RPC.
EGL REST RPC services are only supported by Java generation. The EGL REST RPC service is exposed as an HTTP servlet. The servlet acts as the wrapper class to handle the data conversion and calling the generated EGL service. An EGL REST RPC service is only accessible using an HTTP POST where the HTTP body is a JSON-encoded RPC invocation and the HTTP response body contains the JSON encoded service response. The RBD information center contains more information describing the exact JSON format of the request and response.
The servlet needs to know what URI's correspond to what generated service. To provide this configuration information we generate a single XML file for each project. The XML file contains information for the servlet to map a valid URI to the EGL service to invoke. Generation or deployment does the following:
- Generates a -uri.xml file that contains a map of URI's to service classes. Each REST service in the egldd becomes an entry in this file.
the EGL RestServiceServlet servlet on the war, this configures the war to use the EGL RestServiceServlet for the base URI /restservices/ and for the servlet to load the -uri.xml
configuration on startup to determine URI mappings.
- The application server routes the HTTP request to the EGL RestServiceServlet.
- The EGL RestServiceServlet determines there is a URI with /restservices/service id issued.
- The EGL RestServiceServlet parses the URI to extract the service id key to look up the service to instantiate.
- The EGL RestServiceServlet gets the JSON encoded request from the HTTP request body.
- The EGL RestServiceServlet instantiates the EGL generated service.
- The EGL RestServiceServlet converts the JSON to EGL runtime data.
- The EGL RestServiceServlet calls the service function on the EGL generated service passing the EGL runtime data.
- The EGL generated service executes the coded logic and returns.
- The EGL RestServiceServlet converts the EGL runtime data to a JSON response (this could be a thrown exception or data).
- The EGL RestServiceServlet creates an HTTP response.
- The EGL RestServiceServlet puts the JSON response in the HTTP response body.
- The EGL RestServiceServlet returns the HTTP response to the application server.
It's worth mentioning the EGL RestServiceServlet is used as both the
servlet for a service and as the proxy for Rich UI client applications.
The reason is because it's really performing the same functions; it
receives a JSON request, decodes it and performs an action.
This block diagram shows at a high level the main components of a Java generation service invocation:
In the Java generation environment the only service invocation specific file is the -bnd.xml file. The service invocation code will be generated into the file where you wrote the invocation. The -bnd.xml file will contain all of the service bindings selected for generation in the egldd file. Each binding has a name which is used at runtime to look up the binding information. The purpose of the binding is to decouple the EGL invocation from the physical implementation. We also provide @RESTBinding which can be used to bind the service reference variable so the binding occurs at generation time instead of runtime.At runtime:
- The generated invocation instantiates the EGL Java runtime REST proxy.
There are 2 ways for the runtime to determine a REST invocation:
- @RESTBinding will be in the EGL code in this case the generated code will contain all of the proxy configuration information.
- From reading a REST binding from the xxx-bnd.xml. In this case the proxy configuration information is contained in the -bnd.xml file.
- The generated code constructs the URL used by information from the proxy configuration information and the data passed from generated code.
- The generated code calls the EGL Java runtime REST proxy using the invoke method passing the EGL runtime parameters and the URL.
- The EGL Java runtime REST proxy converts the EGL runtime parameter data based on the specified encoding on the interface.
- The EGL Java runtime REST proxy creates an HTTP request setting the request httpMethod to the method specified in the interface.
- The EGL Java runtime REST proxy puts the encoded data on the body of the HTTP request.
- The EGL Java runtime REST proxy sends the data to the service.
- The service returns an HTTP response.
- The EGL Java runtime REST proxy retrieves HTTP response.
- The EGL Java runtime REST proxy decodes the response body back to EGL runtime objects based on the encoding specified in the interface.
- The EGL Java runtime REST proxy returns the EGL runtime data to the calling code.
purpose and the -bnd.xml file generated for Java: the configuration
information for the service invocation and in this example an EGL REST proxy. The generated service invocation along
with the bnd file are used to create the service invocation HTTP
request. It is worth noting that the -bnd.js file is not assembled into
the application html file like other generated .js files, the -bnd.js file is loaded by the html file
when it is loaded. This provides a way to externalize service invocation
URL's from the application logic.
- The EGL proxy RestServiceServlet is registered on the war. This configures the war to understand the ___proxy URI.
- The EGL REST proxy determines a REST invocation by either @RestBinding or reading the service binding from the -bnd.js file.
- The EGL REST proxy converts the request parameters and binding into a service HTTP request URL and encodes the parameters into the service HTTP request body. The encoding and httpMethod are obtained from the interface.
- The EGL REST proxy creates the RestServiceServlet proxy HTTP request targeting the EGL proxy RestServiceServlet URL (___proxy) on the application server.
- The EGL REST proxy encodes the service HTTP request and puts it in the EGL proxy RestServiceServlet HTTP request body.
- The EGL REST proxy sends the request to the EGL proxy RestServiceServlet on the application server.
statement after the service invocation call statement.
- The EGL proxy RestServiceServlet creates an HTTP request and populates it from the browsers HTTP request body.
- The EGL proxy RestServiceServlet sends the request to the service.
- The EGL proxy RestServiceServlet waits for the service to respond.
- The EGL proxy RestServiceServlet receives the response from the service.
- The EGL proxy RestServiceServlet creates an HTTP response to send back to the browser.
In up-coming blogs, I'll discuss JAX-RPC SOAP for Java, Tomcat and
WebSphere, and JAX-WS SOAP for Java, Tomcat and
WebSphere. Let me know what service topics you'd like to hear about!