com.isomorphic.rpc
Class RPCManager

com.isomorphic.rpc.RPCManager

public class RPCManager

Provides the ability to decode RPCRequests and DSRequests sent by the browser into Java Objects, and send back Java Object as responses.

This class has a client-side counterpart that is also called RPCManager. The client-side RPCManager enables you to send one or more RPCRequests to an arbitrary URL. In the Java logic at those URLs, you'll need to instantiate this RPCManager to process and respond to the requests.

Note that a single RPC transaction can contain more than one RPC request. See the discussion on queueing in the documentation for the client-side RPCManager on why this is useful.

All RPC requests require a response. If your application needs nothing more than an ack of the successful completion of a given request, use the sendSuccess()/sendFailure() convenience methods on this class to ack the request. The RPCManager keeps track of request/response pairs and automatically streams all responses to the client as a batch once you've provided a response for each request.

Note that when you call any of the send() methods on this class, no data is actually sent back over the wire until you have responded to all requests.

See Also:
RPCRequest, RPCResponse, Init

Constructor Summary
RPCManager(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
          RPCManager constructor for use in Servlets or Filters.
RPCManager(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, java.io.Writer out)
          RPCManager constructor for use in JSPs.
 
Method Summary
 void applyEarlierResponseValues(DSRequest dsReq)
          Applies values from earlier responses in this RPCManager's current queue to the supplied DSRequest, in accordance with the and tags on the DSRequest's operationBinding.
 void doCustomResponse()
          If you're using Direct Method Invocation, you can call doCustomResponse() to suppress the normal RPCManager response so that you can send your own custom response via the servletResponse output stream.
 DSResponse findFirstResponse(java.lang.String dsName, java.lang.String opType)
          Returns the @link(com.isomorphic.datasource.DSResponse) for the first DSRequest where the DataSource and operation type match the parameter values (null parameters match any DataSource / operation type).
 DSResponse findLastResponse(java.lang.String dsName, java.lang.String opType)
          Returns the @link(com.isomorphic.datasource.DSResponse) for the DSRequest most immediately prior to the current DSRequest, where the DataSource and operation type match the parameter values.
 java.lang.Object getAttribute(java.lang.String key)
          Returns an Object that has previously been stored in this RPCManager's attribute map.
 java.lang.Boolean getAuthenticated()
          Returns true if we have an authenticated user for this request.
 java.lang.Object getData()
          Convenience method for getting the data of a single RPCRequest.
 DataSource getDataSource(java.lang.String dsName)
          Returns an instance of the DataSource named in the "dsName" parameter.
 DSRequest getDSRequest()
          Convenience method for getting a single DSRequest when you know this request only contains one DSRequest.
 RPCRequest getRequest()
          Convenience method for getting a single RPCRequest when you know this HTTP request only contains one RPCRequest.
 java.util.List getRequests()
          Returns a list of RPC requests sent in this HTTP transaction.
 DSResponse getResponse(DSRequest req)
          Returns the @link(com.isomorphic.datasource.DSResponse) associated with the parameter
 RPCResponse getResponse(RPCRequest req)
          Returns the @link(com.isomorphic.rpc.RPCResponse) associated with the parameter
 int getTransactionPolicy()
          Returns this RPCManager's transaction policy.
 java.lang.String getUserId()
          Returns the user ID associated with the queue of requests being managed by this RPCManager.
 java.util.List getUserRoles()
          Returns a list of the roles associated with the user who is authenticated for this request.
static boolean isRPC(javax.servlet.http.HttpServletRequest request)
           
static boolean isXmlHttp(javax.servlet.http.HttpServletRequest request)
           
static void processRequest(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
          Instantiates an RPCManager and calls RPCManager.processRPCTransaction() on it, which invokes execute() on each RPCRequest or DSRequest in the HTTP request.
 boolean queueHasFailures()
          Returns true if any request in the current queue failed.
 void registerCallback(RPCManagerCompletionCallback callback)
          Register an implementation of RPCManagerCompletionCallback with this RPCManager.
 void removeAttribute(java.lang.String key)
          Removes an Object that has previously been stored in this RPCManager's attribute map.
 int requestCount()
          Returns the number of RPC requests contained in the current HTTP request.
 void send(DSRequest dsRequest, DSResponse dsResponse)
          When responding to DataSource requests sent by the client, use this method.
 void send(DSRequest dsRequest, java.lang.Object data)
          Convenience method.
 void send(java.lang.Object data)
          Convenience method for sending some data back in response to a single RPCRequest.
 void send(RPCRequest rpcRequest, java.lang.Object data)
          Convenience method.
 void send(RPCRequest rpcRequest, RPCResponse rpcResponse)
          When responding to a set of RPC requests sent as part of one HTTP request (if you used startQueue() sendQueue() on the client) you need to pair the responses to the requests.
 void send(RPCResponse rpcResponse)
          Convenience method for sending some data back in response to a single RPCRequest.
 void sendFailure(java.lang.Object request, java.lang.String error)
          If the request processing failed for some reason, you can encode your own failure response in a standard response, or use this convenience method to send a failure notification on the client.

Unless your client-side request specified the willHandleError flag, whatever message you send back here will be alert()ed on the client.
 void sendFailure(java.lang.Object request, java.lang.Throwable t)
          Takes a Throwable, formats the stack trace and calls sendFailure(rpcRequst, error).
 void sendSuccess(RPCRequest rpcRequest)
          Every RPC request requires a response.
 void sendXMLString(DSRequest dsRequest, java.lang.String xml)
          Convenience method.
 void sendXMLString(RPCRequest rpcRequest, java.lang.String xml)
          Convenience method.
 void setAttribute(java.lang.String key, java.lang.Object value)
          Stores an object in this RPCManager's attribute map, associated with the passed key.
 void setAuthenticated(boolean authenticated)
          Pass true to this method to indicate that every request in the queue is associated with an authenticated user.
 void setResponseCharset(java.lang.String charset)
          Sets the charset of the response.
 void setTransactionPolicy(int tp)
          Set this RPCManager's transaction policy.
 void setUserId(java.lang.String userId)
          Set the user ID associated with the queue of requests being managed by this RPCManager.
 void setUserRoles(java.util.List rolesList)
          Accepts a List of roles associated with the user who is authenticated for this request.
 void setUserRoles(java.lang.String rolesString)
          Accepts a comma-separated String representing the list of roles associated with the user who is authenticated for this request.
 

Constructor Detail

RPCManager

public RPCManager(javax.servlet.http.HttpServletRequest request,
                  javax.servlet.http.HttpServletResponse response)
           throws java.lang.Exception
RPCManager constructor for use in Servlets or Filters.

Parameters:
request - The 'request' variable provided in the context of the JSP
response - The 'response' variable provided in the context of the JSP
Throws:
ClientMustResubmitException - if the client must resubmit the request.
java.lang.Exception - if the request is malformed.

RPCManager

public RPCManager(javax.servlet.http.HttpServletRequest request,
                  javax.servlet.http.HttpServletResponse response,
                  java.io.Writer out)
           throws java.lang.Exception
RPCManager constructor for use in JSPs. The RPC requires control of the output stream to send responses to the client. Since JSPs automatically call response.getOutputStream() to provide the 'out' variable in the context of the JSP and since it's further illegal to call getOutputStream() more than once, so you'll need to use this form of the RPCManager constructor when processing RPC requests in a JSP.

Parameters:
request - The 'request' variable provided in the context of the JSP
response - The 'response' variable provided in the context of the JSP
out - The 'out' variable provided in the context of the JSP
Throws:
ClientMustResubmitException - if the client must resubmit the request.
java.lang.Exception - if the request is malformed.
Method Detail

isRPC

public static boolean isRPC(javax.servlet.http.HttpServletRequest request)
Returns:
true if the passed HttpServletRequest contains a SmartClient RPC request, false otherwise.

isXmlHttp

public static boolean isXmlHttp(javax.servlet.http.HttpServletRequest request)
Returns:
true if the current RPC request was made using the xmlHttpRequest transport, false otherwise.

doCustomResponse

public void doCustomResponse()
If you're using Direct Method Invocation, you can call doCustomResponse() to suppress the normal RPCManager response so that you can send your own custom response via the servletResponse output stream.

This is useful for implementing file download functionality in response to an RPC request.

Note if you are not using DMI, but simply using the RPCManager, you can avoid the RPCManager response by simply not calling RPCManager.send().


setResponseCharset

public void setResponseCharset(java.lang.String charset)
Sets the charset of the response. Must be called before any send() methods are called.


getData

public java.lang.Object getData()
Convenience method for getting the data of a single RPCRequest. Calling this method is equivalent to calling getRequest.getData()


getDSRequest

public DSRequest getDSRequest()
Convenience method for getting a single DSRequest when you know this request only contains one DSRequest. If more than one DSRequest was actually sent by the client, this method returns the first one and logs a warning.

Returns:
DSRequest. Returns null if request is not instance of DSRequest.

getRequest

public RPCRequest getRequest()
Convenience method for getting a single RPCRequest when you know this HTTP request only contains one RPCRequest. If more than one RPC request was actually sent by the client, this method returns the first one and logs a warning.


getRequests

public java.util.List getRequests()
Returns a list of RPC requests sent in this HTTP transaction. The request objects in this list will be either of type RPCRequest (if you used RPCManager.send() on the client) or of type DSRequest if the request was generated by a databound component or datasource on the client or a mix of RPCRequest and DSRequest objects.


requestCount

public int requestCount()
Returns the number of RPC requests contained in the current HTTP request.

Returns:
number of RPC requests contained in the current HTTP request.

send

public void send(java.lang.Object data)
          throws java.lang.Exception
Convenience method for sending some data back in response to a single RPCRequest. Calling this method is equivalent to calling send(new RPCResponse(data))/

Parameters:
data - to send back
Throws:
java.lang.Exception - if there is an error sending the response

send

public void send(RPCResponse rpcResponse)
          throws java.lang.Exception
Convenience method for sending some data back in response to a single RPCRequest. If you're processing multiple RPC request sent as part of one HTTP request, you need to pair the responses to the requests by calling send(rpcRequest, rpcResponse) instead.

Parameters:
rpcResponse - containing the data to send back
Throws:
java.lang.Exception - if there is an error sending the response

send

public void send(RPCRequest rpcRequest,
                 RPCResponse rpcResponse)
          throws java.lang.Exception
When responding to a set of RPC requests sent as part of one HTTP request (if you used startQueue() sendQueue() on the client) you need to pair the responses to the requests.

Parameters:
rpcRequest - the request you're responding to
rpcResponse - your response
Throws:
java.lang.Exception - if there is an error sending the response

send

public void send(RPCRequest rpcRequest,
                 java.lang.Object data)
          throws java.lang.Exception
Convenience method. This method does the following:
 RPCResponse rpcResponse = new RPCResponse();
 rpcResponse.setData(data);
 rpcResponse.setStatus(RPCResponse.STATUS_SUCCESS);
 send(rpcRequest, rpcResponse);
 

Parameters:
rpcRequest - the request you're responding to
data - to send as the payload of the response
Throws:
java.lang.Exception - if there is an error sending the response

sendXMLString

public void sendXMLString(RPCRequest rpcRequest,
                          java.lang.String xml)
                   throws java.lang.Exception
Convenience method. Transforms the provided XML in a manner equivalent to the isomorphic:XML JSP tag (custom Isomorphic tag) and sets that as the payload of a new RPCResponse. Calling this method is equivalent to parsing the XML and passing the resulting top-level org.w3c.dom.Element object to RPCResponse.setData().

Throws:
java.lang.Exception - if there is an error sending the response

send

public void send(DSRequest dsRequest,
                 DSResponse dsResponse)
          throws java.lang.Exception
When responding to DataSource requests sent by the client, use this method.

Parameters:
dsRequest - the request you're responding to
dsResponse - your response
Throws:
java.lang.Exception - if there is an error sending the response

send

public void send(DSRequest dsRequest,
                 java.lang.Object data)
          throws java.lang.Exception
Convenience method. This method does the following:
 DSResponse dsResponse = new DSResponse();
 dsResponse.setData(data);
 dsResponse.setStatus(DSResponse.STATUS_SUCCESS);
 send(dsRequest, dsResponse);
 

Parameters:
dsRequest - the request you're responding to
data - to send as the payload of the response
Throws:
java.lang.Exception - if there is an error sending the response

sendXMLString

public void sendXMLString(DSRequest dsRequest,
                          java.lang.String xml)
                   throws java.lang.Exception
Convenience method. Transforms the provided XML in a manner equivalent to the isomorphic:XML JSP tag (custom Isomorphic tag) and sets that as the payload of a new DSResponse. Calling this method is equivalent to parsing the XML and passing the resulting top-level an org.w3c.dom.Element object to DSResponse.setData().

Throws:
java.lang.Exception - if there is an error sending the response

sendSuccess

public void sendSuccess(RPCRequest rpcRequest)
                 throws java.lang.Exception
Every RPC request requires a response. If your application does not require a response to a particular request, use this method to ack the successful completion of the request on the server.

Parameters:
rpcRequest - the request that completed successfully
Throws:
java.lang.Exception - if there is an error sending the response

sendFailure

public void sendFailure(java.lang.Object request,
                        java.lang.String error)
                 throws java.lang.Exception
If the request processing failed for some reason, you can encode your own failure response in a standard response, or use this convenience method to send a failure notification on the client.

Unless your client-side request specified the willHandleError flag, whatever message you send back here will be alert()ed on the client.

Parameters:
request - the request that failed
error - the error string to send to the client
Throws:
java.lang.Exception - if there is an error sending the response

sendFailure

public void sendFailure(java.lang.Object request,
                        java.lang.Throwable t)
                 throws java.lang.Exception
Takes a Throwable, formats the stack trace and calls sendFailure(rpcRequst, error).

Parameters:
request - the request that failed
t - the exception you wish to report to the client
Throws:
java.lang.Exception - if there is an error sending the response

queueHasFailures

public boolean queueHasFailures()
Returns true if any request in the current queue failed. This method can be used by user code in a DMI or custom DataSource execute method to avoid processing later operations if earlier ones have failed.


getResponse

public DSResponse getResponse(DSRequest req)
Returns the @link(com.isomorphic.datasource.DSResponse) associated with the parameter

Parameters:
request - the request for which to obtain the matching response
Returns:
the DSResponse matching the parameter request

findLastResponse

public DSResponse findLastResponse(java.lang.String dsName,
                                   java.lang.String opType)
Returns the @link(com.isomorphic.datasource.DSResponse) for the DSRequest most immediately prior to the current DSRequest, where the DataSource and operation type match the parameter values. For example:
   DSResponse resp = rpcManager.findLastResponse("customer", "update");
 
 would return the response to the most recent update request on the "customer" DataSource
 prior to the request currently being processed (ie, the first one in the queue with no
 response)
 

See the client-side documentation for DSRequestModifier - this method is the programmatic equivalent of the responseData variable.

Parameters:
dsName - The name of the DataSource to find a response for (null means any DataSource)
opType - The operation type to find a response for (null means any operation type)
request - the request marking the endpoint of the search (ie, we will not look at responses to any requests later in the queue than this one)
Returns:
the DSResponse matching the search criteria

findFirstResponse

public DSResponse findFirstResponse(java.lang.String dsName,
                                    java.lang.String opType)
Returns the @link(com.isomorphic.datasource.DSResponse) for the first DSRequest where the DataSource and operation type match the parameter values (null parameters match any DataSource / operation type). For example:
   DSResponse resp = rpcManager.findFirstResponse("customer", "update");
 
 would return the response to the first update request on the "customer" DataSource.
 

See the client-side documentation for DSRequestModifier - this method is the programmatic equivalent of the responseData variable.

Parameters:
dsName - The name of the DataSource to find a response for (null means any DataSource)
opType - The operation type to find a response for (null means any operation type)
Returns:
the DSResponse matching the search criteria

getResponse

public RPCResponse getResponse(RPCRequest req)
Returns the @link(com.isomorphic.rpc.RPCResponse) associated with the parameter

Parameters:
request - the request for which to obtain the matching response
Returns:
the RPCResponse matching the parameter request

processRequest

public static void processRequest(javax.servlet.http.HttpServletRequest request,
                                  javax.servlet.http.HttpServletResponse response)
                           throws javax.servlet.ServletException,
                                  java.io.IOException
Instantiates an RPCManager and calls RPCManager.processRPCTransaction() on it, which invokes execute() on each RPCRequest or DSRequest in the HTTP request.

Parameters:
request - The HttpServletRequest
response - The HttpServletResponse
Throws:
javax.servlet.ServletException - As per HttpServlet.service()
java.io.IOException - As per HttpServlet.service()

getDataSource

public DataSource getDataSource(java.lang.String dsName)
                         throws java.lang.Exception
Returns an instance of the DataSource named in the "dsName" parameter. This method borrows an object from the framework's DataSource pool, and ensures that it is freed at the end of the request cycle. It is the recommended way to obtain an arbitrary DataSource object in your own server-side code. Note that this method is intended for use if you need to obtain some arbitrary DataSource. If what you want is the DataSource associated with the current DSRequest (a common use case), use DSRequest.getDataSource() instead. Also, if you are trying to access some arbitrary DataSource purely because you need to run a DSRequest on it (another very common use case), consider just creating the DSRequest instead, using one of the constructors that accepts a DataSource name.

Parameters:
dsName - The name of the DataSource to return
Throws:
java.lang.Exception
See Also:
DSRequest.getDataSource(), DSRequest.DSRequest(String, String, RPCManager)

applyEarlierResponseValues

public void applyEarlierResponseValues(DSRequest dsReq)
                                throws java.lang.Exception
Applies values from earlier responses in this RPCManager's current queue to the supplied DSRequest, in accordance with the and tags on the DSRequest's operationBinding. We call this process "Transaction Chaining". See the client-side OperationBinding documentation for details.

Parameters:
dsRequest - The DSRequest to apply values to
Throws:
java.lang.Exception

setUserId

public void setUserId(java.lang.String userId)
Set the user ID associated with the queue of requests being managed by this RPCManager. This value will be used by the framework to populate fields of types "creator" and "modifier". This API is intended for use when you are a using some custom authentication scheme - it is unnecessary if you are using the Servlet API for authentication, because we will default to using the value returned by HttpServletRequest.getRemoteUser().

Calling this API automatically sets the authentication status of the RPCManager. If you pass a non-null value, the authentication status is set to true. If you pass null, the authentication status is also set to null.

Parameters:
userId - The user ID to associate with the queue of requests being managed by this RPCManager
See Also:
com.isomorphic.datasource.RPCManager#getUserId(), com.isomorphic.datasource.RPCManager#setAuthenticated(boolean)

getUserId

public java.lang.String getUserId()
Returns the user ID associated with the queue of requests being managed by this RPCManager. This value can be set by the RPCManager.setUserId(String); if that method has not been called, and we running in the context of the servlet API, we call the servlet API's getRemoteUser() method.

See Also:
com.isomorphic.datasource.RPCManager#setUserId(String)

getAuthenticated

public java.lang.Boolean getAuthenticated()
Returns true if we have an authenticated user for this request. Please see the client-side documentation for DataSource.requiresAuthentication/ for details of how the authentication system works

See Also:
com.isomorphic.rpc.RPCManager.setAuthenticated

setAuthenticated

public void setAuthenticated(boolean authenticated)
Pass true to this method to indicate that every request in the queue is associated with an authenticated user. You will need to do this if you wish to implement an authentication that is not based on the scheme built in to the servlet API. Please see the client-side documentation for DataSource.requiresAuthentication for details of how the authentication system works

Parameters:
authenticated - if true we have an authenticated user
See Also:
com.isomorphic.rpc.RPCManager.getAuthenticated, com.isomorphic.rpc.RPCManager.setUserRoles

getUserRoles

public java.util.List getUserRoles()
Returns a list of the roles associated with the user who is authenticated for this request. Note that this list must be manually populated by calling setUserRoles(); it is an alternative mechanism, in case you wish to implement a role-based security system other than the one built into the servlet API. Please see the client-side documentation for OperationBinding.requiresRole for details of how the authentication/security system works

See Also:
com.isomorphic.rpc.RPCManager.getAuthenticated, com.isomorphic.rpc.RPCManager.setUserRoles

setUserRoles

public void setUserRoles(java.lang.String rolesString)
Accepts a comma-separated String representing the list of roles associated with the user who is authenticated for this request. This method allows you to implement a role-based security system other than the one built in to the servlet API. Please see the client-side documentation for OperationBinding.requiresRole for details of how the authentication/security system works

Parameters:
rolesString - A comma-separated String representing the list of roles associated with the authenticated user
See Also:
com.isomorphic.rpc.RPCManager.setAuthenticated, com.isomorphic.rpc.RPCManager.getUserRoles

setUserRoles

public void setUserRoles(java.util.List rolesList)
Accepts a List of roles associated with the user who is authenticated for this request. This method allows you to implement a role-based security system other than the one built in to the servlet API. Please see the client-side documentation for OperationBinding.requiresRole for details of how the authentication/security system works

Parameters:
rolesList - The list of roles associated with the authenticated user
See Also:
com.isomorphic.rpc.RPCManager.setAuthenticated, com.isomorphic.rpc.RPCManager.getUserRoles

getAttribute

public java.lang.Object getAttribute(java.lang.String key)
Returns an Object that has previously been stored in this RPCManager's attribute map. This method intentionally mirrors the method of the same name available on HttpServletRequest, and is provided as an alternstive way to add objects to an RPCManager without introducing a dependency on the Servlet API.

Parameters:
key - The key of the object in the DSRequest's attribute map
See Also:
com.isomorphic.datasource.DSRequest.getAttribute

setAttribute

public void setAttribute(java.lang.String key,
                         java.lang.Object value)
Stores an object in this RPCManager's attribute map, associated with the passed key. This method intentionally mirrors the method of the same name available on HttpServletRequest, and is provided as an alternstive way to add objects to an RPCManager without introducing a dependency on the Servlet API.

Parameters:
key - The key of the object in the DSRequest's attribute map
value - The object to store
See Also:
com.isomorphic.datasource.DSRequest.setAttribute

removeAttribute

public void removeAttribute(java.lang.String key)
Removes an Object that has previously been stored in this RPCManager's attribute map. This method intentionally mirrors the method of the same name available on HttpServletRequest. It is provided as an alternstive, to avoid introducing a dependency on the Servlet API.

Parameters:
key - The key of the object in the DSRequest's attribute map
See Also:
com.isomorphic.datasource.DSRequest.removeAttribute

registerCallback

public void registerCallback(RPCManagerCompletionCallback callback)
Register an implementation of RPCManagerCompletionCallback with this RPCManager. The callback object will have its onSuccess() or onFailure() method called when every request in the RPCManager's queue has completed. Note that the RPCManager is only considered successful - and hence onSuccess() will be called - if every request in the queue is successful; if any one fails, onFailure() will be called.

Parameters:
callback - An instance of RPCManagerCompletionCallback

getTransactionPolicy

public int getTransactionPolicy()
Returns this RPCManager's transaction policy. The transaction policy is in force for the entire lifecycle of the queue being managed by the RPCManager; it cannot be changed once queue processing has started. Transaction policy is one of the following TransactionPolicy constants:

Returns:
This RPCManager's transaction policy

setTransactionPolicy

public void setTransactionPolicy(int tp)
                          throws QueueAlreadyStartedException
Set this RPCManager's transaction policy. The transaction policy is in force for the entire lifecycle of the queue being managed by the RPCManager; it cannot be changed once queue processing has started. Therefore, this method will fail with an exception if you call it after the first request in its queue has started processing.

When you change transaction policy, you effectively override the global setting for autoJoinTransactions, for this request queue only. However, autoJoinTransactions settings specified at the DataSource or OperationBinding level will still be honored. If you need to override these finer-grained settings, you can do so with DSRequest method setJoinTransaction. For details of configuring autoJoinTransactions, scan the client documentation for that phrase.

Transaction policy is one of the following TransactionPolicy constants:

Throws:
QueueAlreadyStartedException - if the queue has already started processing