org.szegedi.spring.web.jsflow
Class FlowController

java.lang.Object
  extended by org.springframework.context.support.ApplicationObjectSupport
      extended by org.springframework.web.context.support.WebApplicationObjectSupport
          extended by org.springframework.web.servlet.support.WebContentGenerator
              extended by org.springframework.web.servlet.mvc.AbstractController
                  extended by org.szegedi.spring.web.jsflow.FlowController
All Implemented Interfaces:
org.springframework.beans.factory.InitializingBean, org.springframework.context.ApplicationContextAware, org.springframework.web.context.ServletContextAware, org.springframework.web.servlet.mvc.Controller

public class FlowController
extends org.springframework.web.servlet.mvc.AbstractController
implements org.springframework.beans.factory.InitializingBean

A Spring MVC Controller that uses Rhino ECMAScript engine to implement flows. A controller requires a FlowStateStorage, a ScriptStorage, and a ScriptSelectionStrategy to operate properly. It can be either wired (manually or autowired) by a bean factory to them, or it can discover them by itself in the application context. As a last resort, if it can not find these objects, it will create its own instances of them (it will use a HttpSessionFlowStateStorage and a UrlScriptSelectionStrategy). A single instance of controller can encapsulate a single webflow represented by a single script, or it can handle several flows represented by several scripts, depending on the script selection strategy used. The operation of the controller can be cusomized by installing various interceptors into it.

Version:
$Id: FlowController.java 104 2009-12-01 18:44:14Z szegedia $
Author:
Attila Szegedi

Field Summary
static java.lang.String HOST_PROPERTY
           
static java.lang.String SCRIPT_DIR_PROPERTY
           
 
Fields inherited from class org.springframework.web.servlet.support.WebContentGenerator
METHOD_GET, METHOD_HEAD, METHOD_POST
 
Fields inherited from class org.springframework.context.support.ApplicationObjectSupport
logger
 
Constructor Summary
FlowController()
           
 
Method Summary
 void afterPropertiesSet()
           
static ScriptStorage createDefaultScriptStorage(org.springframework.context.ApplicationContext ctx)
           
protected  org.springframework.web.servlet.ModelAndView handleRequestInternal(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
          First, the controller determines if there is a request parameter named "stateId" and if it contains a valid state ID.
 void setContextFactory(org.mozilla.javascript.ContextFactory contextFactory)
          Sets the Rhino context factory to use.
 void setFlowExecutionInterceptor(FlowExecutionInterceptor flowExecutionInterceptor)
          Sets the flow execution interceptor used to custom initialize an instance of a flow before it first executes, as well as perform any cleanup after an instance of a flow terminates.
 void setFlowStateStorage(FlowStateStorage flowStateStorage)
          Sets the flow state storage used to store flow states between a HTTP response and the next HTTP request.
 void setResourcePath(java.lang.String resourcePath)
          Deprecated. Use setScriptSelectionStrategy(ScriptSelectionStrategy) with a UrlScriptSelectionStrategy instead
 void setScriptSelectionStrategy(ScriptSelectionStrategy scriptSelector)
          Sets the script selector used to select scripts for initial HTTP requests.
 void setScriptStorage(ScriptStorage scriptStorage)
          Sets the script storage used to load scripts.
 void setStateExecutionInterceptor(StateExecutionInterceptor stateExecutionInterceptor)
          Sets the flow state interceptor used to provide "around" advice around each state execution of each flow.
 void setUsePathInfo(boolean usePathInfo)
          Deprecated. Use setScriptSelectionStrategy(ScriptSelectionStrategy) with a UrlScriptSelectionStrategy instead
 void setUseServletPath(boolean useServletPath)
          Deprecated. Use setScriptSelectionStrategy(ScriptSelectionStrategy) with a UrlScriptSelectionStrategy instead
 
Methods inherited from class org.springframework.web.servlet.mvc.AbstractController
handleRequest, isSynchronizeOnSession, setSynchronizeOnSession
 
Methods inherited from class org.springframework.web.servlet.support.WebContentGenerator
applyCacheSeconds, applyCacheSeconds, cacheForSeconds, cacheForSeconds, checkAndPrepare, checkAndPrepare, getCacheSeconds, getSupportedMethods, isRequireSession, isUseCacheControlHeader, isUseExpiresHeader, preventCaching, setCacheSeconds, setRequireSession, setSupportedMethods, setUseCacheControlHeader, setUseExpiresHeader
 
Methods inherited from class org.springframework.web.context.support.WebApplicationObjectSupport
getServletContext, getTempDir, getWebApplicationContext, isContextRequired, setServletContext
 
Methods inherited from class org.springframework.context.support.ApplicationObjectSupport
getApplicationContext, getMessageSourceAccessor, initApplicationContext, requiredContextClass, setApplicationContext
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

HOST_PROPERTY

public static final java.lang.String HOST_PROPERTY
See Also:
Constant Field Values

SCRIPT_DIR_PROPERTY

public static final java.lang.String SCRIPT_DIR_PROPERTY
See Also:
Constant Field Values
Constructor Detail

FlowController

public FlowController()
Method Detail

setFlowStateStorage

public void setFlowStateStorage(FlowStateStorage flowStateStorage)
Sets the flow state storage used to store flow states between a HTTP response and the next HTTP request. If not set, the controller will attempt to look up an instance of it by type in the application context during initialization. If none is found, the controller will create an internal default instance of HttpSessionFlowStateStorage.

Parameters:
flowStateStorage -

setScriptStorage

public void setScriptStorage(ScriptStorage scriptStorage)
Sets the script storage used to load scripts. If not set, the controller will attempt to look up an instance of it by type in the application context during initialization. If none is found, it will create an internal default instance.

Parameters:
scriptStorage -

setScriptSelectionStrategy

public void setScriptSelectionStrategy(ScriptSelectionStrategy scriptSelector)
Sets the script selector used to select scripts for initial HTTP requests. If not set, an instance of UrlScriptSelectionStrategy with UrlScriptSelectionStrategy.setUseServletPath(boolean) set to true will be used.

Parameters:
scriptSelector -

setContextFactory

public void setContextFactory(org.mozilla.javascript.ContextFactory contextFactory)
Sets the Rhino context factory to use. It will only be used when the flowscripts are executed outside of a OpenContextInViewInterceptor (otherwise the interceptor's is used). If not set, the global context factory returned by ContextFactory.getGlobal() will be used.

Parameters:
contextFactory -

setResourcePath

public void setResourcePath(java.lang.String resourcePath)
Deprecated. Use setScriptSelectionStrategy(ScriptSelectionStrategy) with a UrlScriptSelectionStrategy instead


setUsePathInfo

public void setUsePathInfo(boolean usePathInfo)
Deprecated. Use setScriptSelectionStrategy(ScriptSelectionStrategy) with a UrlScriptSelectionStrategy instead


setUseServletPath

public void setUseServletPath(boolean useServletPath)
Deprecated. Use setScriptSelectionStrategy(ScriptSelectionStrategy) with a UrlScriptSelectionStrategy instead


setFlowExecutionInterceptor

public void setFlowExecutionInterceptor(FlowExecutionInterceptor flowExecutionInterceptor)
Sets the flow execution interceptor used to custom initialize an instance of a flow before it first executes, as well as perform any cleanup after an instance of a flow terminates. If not set, the controller will attempt to look up an instance of it by type in the application context during initialization. If none is found, no custom flow initialization will be performed.

Parameters:
flowExecutionInterceptor -

setStateExecutionInterceptor

public void setStateExecutionInterceptor(StateExecutionInterceptor stateExecutionInterceptor)
Sets the flow state interceptor used to provide "around" advice around each state execution of each flow. If not set, the controller will attempt to look up an instance of it by type in the application context during initialization. If none is found, no custom state interception will be performed.

Parameters:
stateExecutionInterceptor - the state execution interceptor to use.

afterPropertiesSet

public void afterPropertiesSet()
                        throws java.lang.Exception
Specified by:
afterPropertiesSet in interface org.springframework.beans.factory.InitializingBean
Throws:
java.lang.Exception

createDefaultScriptStorage

public static ScriptStorage createDefaultScriptStorage(org.springframework.context.ApplicationContext ctx)
                                                throws java.lang.Exception
Throws:
java.lang.Exception

handleRequestInternal

protected org.springframework.web.servlet.ModelAndView handleRequestInternal(javax.servlet.http.HttpServletRequest request,
                                                                             javax.servlet.http.HttpServletResponse response)
                                                                      throws java.lang.Exception
First, the controller determines if there is a request parameter named "stateId" and if it contains a valid state ID. If so, it continues the execution of the associated flowscript at the point where it was waiting. If state ID is not present or not valid, the controller will look up a script to execute, by concatenating resourcePath with neither, one, or both of the servlet path and path info portions of the request URI, depending on the values of the usePathInfo and useServletPath properties. In case the servlet was invoked as a result of a RequestDispatcher.include(javax.servlet.ServletRequest, javax.servlet.ServletResponse) call, the controller will correctly use the request attributes javax.servlet.include.servlet_path and javax.servlet.include.path_info instead of the request's proper servlet path and path info. All flowscripts have access to the following built-in objects:

NameObject
requestthe HttpServletRequest object
responsethe HttpServletResponse object
servletContextthe ServletContext object
applicationContextthe ApplicationContext object

They also have access to following built-in functions:

FunctionPurpose
include(path)includes a script referenced with the specified path as if it was executed at the point of inclusion. You can use it to conveniently include reusable function modules. For absolute pathnames (relative to the root of the namespace of the resource loader configured in the associated script storage), start the path with /. Otherwise, the paths are interpreted as relative to the including script. In relative paths, you can use any number of ../ components at the start of the path to refer to parent directories. Relative paths were introduced in 1.1.1 release. For compatibility with older releases that only supported absolute paths, if a relative path can not be resolved to an existing script, the system will also try to resolve it as an old-format absolute path.
respond(viewName, model)respond to the actual HTTP request with the specified view name and the specified model. The view is resolved using the Spring's view resolution mechanism. The model can be any Rhino Scriptable instance (including this to pass all script variables to the model), the controller will take care of fitting a Map interface to it to conform to Spring model requirements. The actual sending of the response will not happen until the script either terminates, or calls the wait() function. Another invocation of the function before the actual sending of the reponse happens will overwrite a previous one. The script can pass null for the view name to indicate it handled the response completely on its own and no view needs to be invoked.
wait()send the response and then waits for the next HTTP request. The function will return when another HTTP request for that flow is made. Upon returning from this function, the variables request and response will have new values, therefore scripts should not store references to them across waits. When wait() is invoked, an additional variable named "stateId" is placed into the model. The view should pass this id to the client, who should specify it in a request parameter also named "stateId" in the next HTTP request to continue the flow.
respondAndWait(viewName, model) conveniently combines the respond() and wait() functions into a single function.
isGoingToWait() returns true if the script is about to go waiting as a result of a wait() call. All open finally blocks are executed in Rhino whenever wait() is called. This function can be used in finally blocks to distinguish between control flow exiting the block for the last time (really "finally") and control flow exiting the block because of wait. I.e. the typical use is:
 try
 {
     ...
     respondAndWait("confirm.html", data);
     ...
 }
 finally
 {
     if(!isGoingToWait())
     {
         // perform the "real finally" cleanup here
         ...
     }
 }
   

Specified by:
handleRequestInternal in class org.springframework.web.servlet.mvc.AbstractController
Throws:
java.lang.Exception