info.sswap.api.servlet
Class AbstractSSWAPServlet

java.lang.Object
  extended by javax.servlet.GenericServlet
      extended by javax.servlet.http.HttpServlet
          extended by info.sswap.api.servlet.AbstractSSWAPServlet
All Implemented Interfaces:
java.io.Serializable, javax.servlet.Servlet, javax.servlet.ServletConfig
Direct Known Subclasses:
ExecImpl, LegacyServiceWrapperServlet, SimpleSSWAPServlet

public abstract class AbstractSSWAPServlet
extends javax.servlet.http.HttpServlet

Handles HTTP GETs and POSTs to a SSWAP service point. This class is a bridge between handling a HTTP request and the SSWAP Java API that allows on-demand, transaction-time reasoning to satisfy the request.

Note: A simple way to implement a service without the constraints and subtleties of servlet programming is to use a servlet launcher to launch a regular Java class. For most developers this is the recommended way; see SimpleSSWAPServlet and MapsTo

To use, extend this abstract class and override the handleRequest method. When an Resource Invocation Graph ( RIG) is sent to the servlet, handleRequest will allow action on the RIG to create a Resource Response Graph ( RRG) to be returned back to the client. The RIG supports a translate method to allow semantic mapping of the RIG into the vocabulary and concepts of the service's Resource Description Graph (RDG).

Upon return from handleRequest, this class generates an RRG which is serialized back to the client.

The servlet responds to HTTP GETs and POSTs in the following manner:

GET query string parameters (e.g., http://.../MyService?property=value&prefix:property=value2) are converted into service parameters according to the following rules:

By default, property=value assignments are matched against statements on the RDG's SSWAPSubjects. To instead force a match against the SSWAPResource properties, prepend a tilde (~) immediately before the prefix or property: e.g., ~property=value or ~prefix:property=value. The tilde (~) is a query string flag only: it is not part of the property name.

To use the servlet, create a typical mapping in your servlet container's web.xml file, such as:

 <servlet>
   <servlet-name>MyServlet</servlet-name>
 
     <servlet-class>org.mySite.sswap.MyServlet</servlet-class>
 
     <!-- if not defined, will be derived from <url-pattern>
     <init-param>
       <param-name>RDGPath</param-name>
       <param-value>/pathTo/MyRDG</param-value>
     </init-param>
     -->
 </servlet>
 
 <servlet-mapping>
   <servlet-name>MyServlet</servlet-name>
   <url-pattern>/MyService/*</url-pattern> <!-- always end in /* -->
 </servlet-mapping>
 
 
Replace and customize the values for <servlet-name>, <servlet-class>, <param-value>, and <url-pattern> per usual web.xml practices. All other values should be as above. In the above example, MyServlet extends AbstractSSWAPServlet and defines handleRequest. The use and definition of RDGPath is optional but recommended. If it is not defined, then the RDG must reside at the request URI; if it is defined, then its value must be the path to a valid RDG on the local web server.

Error handling:
If an error is due to a client misconfigured RIG, then an error message is returned to the client and set in the HTTP header. An RRG is not returned to the client. But if the RIG passes validation--both syntactically as OWL RDF/XML, and semantically as being complaint with the RDG--but yet an error occurs on the server-side, then the RIG is returned to the client without semantic modification (still, no RRG).

Author:
Damian Gessler
See Also:
handleRequest(info.sswap.api.model.RIG), SimpleSSWAPServlet, MapsTo, RDG, RIG, RRG, SSWAPResource, SSWAPSubject, Serialized Form

Field Summary
private  boolean initCompleted
          Flag to check if init has completed.
private static org.apache.log4j.Logger LOGGER
          Interface to Logging API
private  java.lang.String rdgFile
          Absolute, fully resolved path and file name of the RDG on the file system
private  java.lang.String rdgPath
          Real path to the RDG on the file system as specified in web.xml (may be a directory)
protected  java.net.URI remoteServiceURI
          URI to be called to pass on service invocation to a remote service.
private static java.lang.String resourceFlag
          Flag string appended to terms in the GET query string to identify them as pertaining to the SSWAPResouce
static java.lang.String RRG_RETRIEVAL_SUFFIX
          The suffix to the request string for RRG retrieval; that is, if a request ends with this suffix (attached to the regular service's URL), it indicates that the request is for retrieving a cached RRG, and not invoking the service.
private static long serialVersionUID
          Default
private  int suggestedPollingInterval
          Suggested polling interval read from web.xml (if defined) or a default value.
 
Constructor Summary
AbstractSSWAPServlet()
           
 
Method Summary
protected  void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
          An HTTP GET equates to returning an RDG or creating a just-in-time RIG from the query string and invoking this service.
protected  void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
          An HTTP POST equates to a request service invocation.
private  java.lang.String extractOutputURI(SSWAPModel model)
          Extracts sswap:outputURI from the sswap:Resource in this SSWAPModel.
private static java.lang.String getMajorMIMEType(java.lang.String mimeType)
          Returns the major type in a MIME type (everything up to the first '/'; if there is one)
private static java.lang.String getMinorMIMEType(java.lang.String mimeType)
          Returns the minor type in a MIME type (everything after the first '/'; if there is one)
private  RDG getRDG(java.lang.String rdgURIStr)
          Dereference the servlet's RDG and map any Exceptions to a general IOException.
private  java.lang.String getRRGToken()
          Generates an RRG token for an asynchronous invocation.
 int getTimeout()
          The servlet timeout value, in milliseconds.
protected abstract  void handleRequest(RIG rig)
          Override this method to convert an incoming Resource Invocation Graph RIG into an outgoing Resource Response Graph RRG.
 void init(javax.servlet.ServletConfig servletConfig)
          Override this method (or GenericServlet.init() for custom servlet initialization code.
private  void initializeRequest(javax.servlet.http.HttpServletRequest request)
          Initialization per request
private  RRG invokeRemoteService(java.net.URI remoteService)
          Invoke a HTTP GET; Wrapper to invokeRemoteService(URI remoteService,null)
private  RRG invokeRemoteService(java.net.URI remoteService, java.io.InputStream bodyStream)
          Invoke a HTTP GET or POST on 'remoteService'.
private  boolean isAsyncRIG(RIG asyncRIGCandidate)
          Verifies whether the submitted RIG is an asynchronous RIG.
private static boolean isMIMETypeAcceptable(javax.servlet.http.HttpServletRequest request, java.lang.String mimeType)
           
private static boolean isMIMETypeAcceptable(java.lang.String acceptHeaderValue, java.lang.String mimeType)
          Checks whether the given MIME type is acceptable according to the values for the accept header
private static boolean isMIMETypeMatch(java.lang.String pattern, java.lang.String mimeType)
          Checks whether a MIME type matches a MIME type pattern (i.e., a string that may contain '*" in the place of major type, minor type or both
private  java.util.Map<java.lang.String,java.lang.String[]> makeParameterMap(javax.servlet.http.HttpServletRequest request)
          Parse the HTTP servlet request into a "mutable" parameter:value map.
private static java.lang.String[] parseMIMETypeList(java.lang.String mimeTypeList)
          Parses a list of MIME types, as they occur in the Accept header; for example: text/xml, text/plain; q=0.8, text/html; q=0.7, text/ *; q=0.3, * /*; q=0.1
private  com.clarkparsia.utils.web.ParameterList partitionParameters(com.clarkparsia.utils.web.ParameterList parameterList)
          Partition the parameter list by removing (and returning a list of) those parameters that will apply to the only the SSWAPResource.
(package private)  void publishRRG(java.lang.String token, RRG rrg)
          Publishes an RRG (so that it can be retrieved by the caller in the asynchronous invocation protocol).
private  void resolveParameters(RIG rig, java.util.Map<java.lang.String,java.lang.String[]> queryStringParameterMap)
          Resolves query string parameters against name spaces to get absolute URIs.
private  void resolveProperties(RIG rig, SSWAPNode sswapNode, com.clarkparsia.utils.web.ParameterList resolvedQNameMap)
          Removes all properties from sswapNode and adds back only those properties (parameters) from resolvedQNameMap that are ObjectProperties or DatatypeProperties
private  com.clarkparsia.utils.web.ParameterList resolveQueryString(RIG rig, java.util.Map<java.lang.String,java.lang.String[]> queryStringParameterMap)
          Map query string parameters into fully qualified URLs or URNs.
private  void sendError(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, java.lang.String errMsg, int responseCode)
          Return an error message.
private  void serializeResponse(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, SSWAPModel model)
          Serialize the model back to the HTTP response.
private  void setNamespaces(RIG rig, java.util.Map<java.lang.String,java.lang.String[]> queryStringParameterMap)
          Parse the GET query string parameter map for prefixes (namespace assignments) and set the namespaces in the rig's NsPrefixMap.
 void setTimeout(int timeout_ms)
          Set servlet timeout value, in milliseconds.
 
Methods inherited from class javax.servlet.http.HttpServlet
doDelete, doHead, doOptions, doPut, doTrace, getLastModified, service, service
 
Methods inherited from class javax.servlet.GenericServlet
destroy, getInitParameter, getInitParameterNames, getServletConfig, getServletContext, getServletInfo, getServletName, init, log, log
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

serialVersionUID

private static final long serialVersionUID
Default

See Also:
Constant Field Values

LOGGER

private static final org.apache.log4j.Logger LOGGER
Interface to Logging API


RRG_RETRIEVAL_SUFFIX

public static final java.lang.String RRG_RETRIEVAL_SUFFIX
The suffix to the request string for RRG retrieval; that is, if a request ends with this suffix (attached to the regular service's URL), it indicates that the request is for retrieving a cached RRG, and not invoking the service.

See Also:
Constant Field Values

rdgPath

private java.lang.String rdgPath
Real path to the RDG on the file system as specified in web.xml (may be a directory)


rdgFile

private java.lang.String rdgFile
Absolute, fully resolved path and file name of the RDG on the file system


resourceFlag

private static final java.lang.String resourceFlag
Flag string appended to terms in the GET query string to identify them as pertaining to the SSWAPResouce

See Also:
Constant Field Values

remoteServiceURI

protected java.net.URI remoteServiceURI
URI to be called to pass on service invocation to a remote service. Only used when this servlet is extended, as by SSWAPProxyServlet, which sets the value to non-null.


suggestedPollingInterval

private int suggestedPollingInterval
Suggested polling interval read from web.xml (if defined) or a default value. This field contains an interval (in milliseconds) that will be returned as an advice to callers that invoke this service in an asynchronous way. (During asynchronous invocation, this servlet immediately returns an asynchronous RRG, even though the service has not computed its result; later the caller is supposed to poll (inquiry) at this interval to verify whether the actual result is ready for retrieval.)


initCompleted

private boolean initCompleted
Flag to check if init has completed.

Constructor Detail

AbstractSSWAPServlet

public AbstractSSWAPServlet()
Method Detail

init

public void init(javax.servlet.ServletConfig servletConfig)
          throws javax.servlet.ServletException
Override this method (or GenericServlet.init() for custom servlet initialization code. If overriding this method, overriding method MUST call super.init(servletConfig) as the first line of code. This method is called once at the end of all internal initialization and before any requests are serviced.

The method is passed the Servlet Configuration and may throw a ServletException. Thrown errors are not caught and will terminate servlet initialization.

Uses for this method are to set the servlet timeout (see setTimeout(int)), effect changes to URI caching (see SSWAP.getCache()), and so forth.

Specified by:
init in interface javax.servlet.Servlet
Overrides:
init in class javax.servlet.GenericServlet
Parameters:
servletConfig - the ServletConfig object of the servlet
Throws:
javax.servlet.ServletException - on a servlet configuration error
See Also:
SSWAP, ServletConfig

getTimeout

public int getTimeout()
The servlet timeout value, in milliseconds.

Returns:
the timeout value, or -1 on any error that precludes retrieving a value

setTimeout

public void setTimeout(int timeout_ms)
Set servlet timeout value, in milliseconds. Increase this value if the web service needs additional time to complete.

Timeout values less than 1000 (1 sec) are silently ignored.


initializeRequest

private void initializeRequest(javax.servlet.http.HttpServletRequest request)
                        throws javax.servlet.ServletException
Initialization per request

Throws:
javax.servlet.ServletException - if servlet init() method is not called

doGet

protected final void doGet(javax.servlet.http.HttpServletRequest request,
                           javax.servlet.http.HttpServletResponse response)
                    throws javax.servlet.ServletException
An HTTP GET equates to returning an RDG or creating a just-in-time RIG from the query string and invoking this service.

This method is marked protected solely for package access purposes. It should not be called directly and cannot be overridden. The servlet handler will call this method automatically on an HTTP GET. To handle the request, override the method handleRequest().

An HTTP GET with no (extra) path info and no query string equates to a request for the RDG (Resource Description Graph).

An HTTP GET with a query string equates to an invocation, with measures taken to semantically resolve the query string parameters in terms of this RDG's semantics. A RIG is automatically generated from the query string and this service is invoked.

Overrides:
doGet in class javax.servlet.http.HttpServlet
Parameters:
request - HTTP Servlet request
response - HTTP Servlet response
Throws:
javax.servlet.ServletException - as thrown by the servlet container
See Also:
handleRequest(RIG rig), RDG, RIG, RRG

doPost

protected final void doPost(javax.servlet.http.HttpServletRequest request,
                            javax.servlet.http.HttpServletResponse response)
                     throws javax.servlet.ServletException
An HTTP POST equates to a request service invocation.

This method is marked protected solely for package access purposes. It should not be called directly and cannot be overridden. The servlet handler will call this method automatically on an HTTP POST. To handle the request, override the method handleRequest().

Overrides:
doPost in class javax.servlet.http.HttpServlet
Parameters:
request - HTTP Servlet request
response - HTTP Servlet response
Throws:
javax.servlet.ServletException - as thrown by the servlet container
See Also:
handleRequest(RIG rig)

isAsyncRIG

private boolean isAsyncRIG(RIG asyncRIGCandidate)
Verifies whether the submitted RIG is an asynchronous RIG. The determination is done based on analyzing sswap:Subject's types -- if subject is typed with a marker class async:RRG, then it is an asynchronous RIG.

Parameters:
asyncRIGCandidate - a RIG to be checked
Returns:
true if the RIG is an asynchronous RIG, false otherwise

sendError

private void sendError(javax.servlet.http.HttpServletRequest request,
                       javax.servlet.http.HttpServletResponse response,
                       java.lang.String errMsg,
                       int responseCode)
                throws java.io.IOException
Return an error message. Generate error message response as a JSON object, if possible. If the request Accept header is "text/html", then this is overridden and HttpServletResponse.sendError() is called with its consequent formatted HTML response.

Throws:
java.io.IOException

handleRequest

protected abstract void handleRequest(RIG rig)
Override this method to convert an incoming Resource Invocation Graph RIG into an outgoing Resource Response Graph RRG. Edits to the RIG will be the foundation of the RRG returned from this service call. Sample code:
 public void handleRequest(RIG rig) {
 
 // if we need to check service parameters we could do it here
 //SSWAPResource translatedResource = rig.getTranslatedResource();
 
 // loop over every subject, across all matching graphs
 for ( SSWAPSubject translatedSubject : rig.getTranslatedSubjects() ) {
 
 	// "translation" maps types and properties in the RIG
 	// into the vocabulary we understand in the RDG.
 
 	// for all objects for which the current subject is already stating a mapping
 	for ( SSWAPObject sswapObject : translatedSubject.getObjects() ) {
 		// do something:
 		// edit object based on the type(s) and property values of the subject
 	}
 
 	// if and as necessary, add additional object mappings to subject
 	SSWAPObject sswapObject;
 	try {	// if and as appropriate
 		sswapObject = rig.createObject(new URI("http://mySite.org/someData"));
 	} catch ( Exception e ) {
 		sswapObject = rig.createObject();	// a "blank node"
 	}
 
 	// do something:
 	// edit object based on the type(s) and property values of the subject
 
 	// add it to the subject
 	translatedSubject.addObject(sswapObject);
 }
 
 // done
 
 // for testing, you may call getRRG()
 // if it throws a validation exception, the RRG will not be returned to the caller;
 // on error, the caller will get the original RIG returned unchanged
 boolean debugging = false;
 if ( debugging ) {
 	  try {
 		rig.getRRG();	// expensive
 	  } catch ( Exception e ) {
 		System.err.println("Failed to create a valid RRG:");
 		rig.serialize(System.err);
 	  }
  }
 
 }
 
 
Providers should do their best to satisfy the request of the RIG, but they are not required to be exhaustive. For example, SSWAPObjects should informatively satisfy the contract of the mapping from a SSWAPSubject, but they do not need themselves to extend a deep graph of relations. The decision on how much data to return is left to the provider. Regardless, what data is returned must satisfy the logical contract of the RDG.

If a request is larger than the provider wishes to satisfy (e.g., hundreds or thousands of SSWAPSubjects each requiring database calls), the provider may satisfy none, a few, or all at its choosing. If the provider wants to satisfy none--i.e., it handles requests on an all-or-none basis--and it wants the current state returned as an error to the client, it may return an HTTP 413 Request Entity Too Large response code by throwing the runtime exception RequestEntityTooLargeException. In this case no content (neither RIG nor RRG) is be returned to the client.

If the provider is unable to access data, it should fail silently and allow the RIG to be returned. If the problem is due to a client error, for example, a missing URL, then the provider may throw a ClientException to return an error to the client.

Parameters:
rig - RIG invoking the service. This RIG should be edited and will become the basis for the RRG returned by the service. Best practice is to leave most of the RIG untouched, modifying only the SSWAPObject subgraphs.
See Also:
RIG, RRG, RequestEntityTooLargeException, ClientException

getRDG

private RDG getRDG(java.lang.String rdgURIStr)
            throws java.io.IOException
Dereference the servlet's RDG and map any Exceptions to a general IOException. Will catch and throw on rdgURIStr null or empty errors.

Throws:
java.io.IOException

invokeRemoteService

private RRG invokeRemoteService(java.net.URI remoteService)
                         throws java.io.IOException,
                                ValidationException
Invoke a HTTP GET; Wrapper to invokeRemoteService(URI remoteService,null)

Throws:
java.io.IOException
ValidationException

invokeRemoteService

private RRG invokeRemoteService(java.net.URI remoteService,
                                java.io.InputStream bodyStream)
                         throws java.io.IOException,
                                ValidationException
Invoke a HTTP GET or POST on 'remoteService'. 'bodyStream' is the content of the POST, or may equal null to invoke a GET. Return the response as a validated RRG, or throw on any error

Throws:
java.io.IOException
ValidationException

makeParameterMap

private java.util.Map<java.lang.String,java.lang.String[]> makeParameterMap(javax.servlet.http.HttpServletRequest request)
Parse the HTTP servlet request into a "mutable" parameter:value map. URLDecodes both parameters and their values before storing in the map.

Parameters:
request - HTTP servlet request with possible parameters
Returns:
a mutable map of parameter:value mappings

resolveParameters

private void resolveParameters(RIG rig,
                               java.util.Map<java.lang.String,java.lang.String[]> queryStringParameterMap)
                        throws java.lang.IllegalArgumentException
Resolves query string parameters against name spaces to get absolute URIs. Then resolves these URIs against SSWAPProperties (using reasoning), to merges (add or replace) SSWAPProperties with the appropriate semantic mappings based on reasoning over the RIG.

Throws:
java.lang.IllegalArgumentException

setNamespaces

private void setNamespaces(RIG rig,
                           java.util.Map<java.lang.String,java.lang.String[]> queryStringParameterMap)
Parse the GET query string parameter map for prefixes (namespace assignments) and set the namespaces in the rig's NsPrefixMap. Prefixes that are IANA schemes are passed through--not set as prefixes. Thus, for example, "urn:=http://someSite.org/" cannot be (re)defined as a namespace prefix.

Parameters:
rig - document (model) to set new namespaces
queryStringParameterMap - source parameter:value mapping

resolveQueryString

private com.clarkparsia.utils.web.ParameterList resolveQueryString(RIG rig,
                                                                   java.util.Map<java.lang.String,java.lang.String[]> queryStringParameterMap)
Map query string parameters into fully qualified URLs or URNs. Examples: Query string Parameter mapping
------------ -----------------

Parameters:
rig - The RIG with a prefix map
queryStringParameterMap - parameter map of parameters and vales, as from request.getParameterMap()
Returns:
a mapping of resolved URLs or URNs and a string array of values for each entry

partitionParameters

private com.clarkparsia.utils.web.ParameterList partitionParameters(com.clarkparsia.utils.web.ParameterList parameterList)
Partition the parameter list by removing (and returning a list of) those parameters that will apply to the only the SSWAPResource.

Parameters:
parameterList - original list of parameters for both SSWAPSubject and SSWAPResource
Returns:
param parameterList of those only for SSWAPResource. These are removed from the original parameter list.

resolveProperties

private void resolveProperties(RIG rig,
                               SSWAPNode sswapNode,
                               com.clarkparsia.utils.web.ParameterList resolvedQNameMap)
                        throws java.lang.IllegalArgumentException
Removes all properties from sswapNode and adds back only those properties (parameters) from resolvedQNameMap that are ObjectProperties or DatatypeProperties

Throws:
java.lang.IllegalArgumentException

getRRGToken

private java.lang.String getRRGToken()
Generates an RRG token for an asynchronous invocation.

Returns:
an RRG token

publishRRG

void publishRRG(java.lang.String token,
                RRG rrg)
Publishes an RRG (so that it can be retrieved by the caller in the asynchronous invocation protocol).

Parameters:
token - token under which the RRG should be published
rrg - RRG to be published

extractOutputURI

private java.lang.String extractOutputURI(SSWAPModel model)
Extracts sswap:outputURI from the sswap:Resource in this SSWAPModel.

Parameters:
model - the model from which the sswap:outputURI should be extracted
Returns:
a string containing the outputURI or null

serializeResponse

private void serializeResponse(javax.servlet.http.HttpServletRequest request,
                               javax.servlet.http.HttpServletResponse response,
                               SSWAPModel model)
                        throws java.io.IOException
Serialize the model back to the HTTP response.

Throws:
java.io.IOException

parseMIMETypeList

private static java.lang.String[] parseMIMETypeList(java.lang.String mimeTypeList)
Parses a list of MIME types, as they occur in the Accept header; for example: text/xml, text/plain; q=0.8, text/html; q=0.7, text/ *; q=0.3, * /*; q=0.1

Parameters:
mimeTypeList - string containing a mime type list
Returns:
an array of mime types (without q values)

getMajorMIMEType

private static java.lang.String getMajorMIMEType(java.lang.String mimeType)
Returns the major type in a MIME type (everything up to the first '/'; if there is one)

Parameters:
mimeType - the MIME type
Returns:
the major type in a MIME type

getMinorMIMEType

private static java.lang.String getMinorMIMEType(java.lang.String mimeType)
Returns the minor type in a MIME type (everything after the first '/'; if there is one)

Parameters:
mimeType - the MIME type
Returns:
the minor type in a MIME type (or empty string if there is none)

isMIMETypeMatch

private static boolean isMIMETypeMatch(java.lang.String pattern,
                                       java.lang.String mimeType)
Checks whether a MIME type matches a MIME type pattern (i.e., a string that may contain '*" in the place of major type, minor type or both

Parameters:
pattern - the pattern
mimeType - the MIME type
Returns:
true, if the pattern matches

isMIMETypeAcceptable

private static boolean isMIMETypeAcceptable(java.lang.String acceptHeaderValue,
                                            java.lang.String mimeType)
Checks whether the given MIME type is acceptable according to the values for the accept header

Parameters:
acceptHeaderValue - the value of the accept header
mimeType - MIME type to be checked
Returns:
true if the MIME type is a valid value given the value of the accept header

isMIMETypeAcceptable

private static boolean isMIMETypeAcceptable(javax.servlet.http.HttpServletRequest request,
                                            java.lang.String mimeType)


Copyright (c) 2011, iPlant Collaborative, University of Arizona, Cold Spring Harbor Laboratories, University of Texas at Austin.