Apache Struts 2 Documentation > Continuations
Added by Patrick Lightbody, last edited by Ted Husted on Feb 05, 2007  (view change)
Continuations are currently expiremental, and as such, we cannot recommend they be used for heavy-use production deployments at this time. We will continue to work with the community to stabilize and enhance this feature until we are confidant it can be used in the most extreme site traffic and use-cases.

Continuations are a feature borrowed from the RIFE project, that allow for extremely simple state management and wizard-like functionality.

Setting it Up

Setting up continuation support requires identifying the base package that your classes are in. This is done in struts.properties using the key struts.continuations.package. Typically, this can be the root package that your classes are found in, such as com.acme.

Once you've done this, the fraemework will analyze your classes and automatically apply continuation support for any class that uses the continuation features - specifically a class that extends ActionSupport that has an execute() method that calls a pause() method.

URL Concerns

Because continuations require the state of your flow be managed by the framework, it is up to you to make sure your application inform the framework what the flow's ID is. This is done via a continue parameter that provides a unique ID for every request in the flow. Assuming you are generating your URLs using the URL tag or the Form tag, this is handled for you automatically. If you are not using these tags, continuations will not work.

Interceptor Concerns

Because continuations radically change the way your actions are invoked, it is important to understand how this affects interceptors. The most important think to know is that continuations kick in only when the execute() method is called. This means that on every request (regardless of whether it is a new request or a continuation), the interceptors will be called. This is what makes it possible to apply new request parameters to your action even though the rest of the call stack appears to look the same.

This is generally exactly what you would want, except some interceptors, namely the Execute and Wait Interceptor and possibly the Token Session Interceptor, have very different expectations about the workflow/lifecycle of the action invocation. In these cases, continuations should not be used.

Example

Getting started with continuations is extremely simple. The biggest thing to get used to is the very different conversational style with application workflow. Typically, you might have used session variables or hidden form fields to pass the state around. Using continuations, you use the Java language to handle that state. See the following body of a Guess class extending ActionSupport:

Error formatting macro: snippet: java.lang.IllegalArgumentException: Invalid url: must begin with a configured prefix.

Note how the class keeps the state (tries, in this example) as a local variable in the execute() method. The continuations will automatically pick up the invocation after the pause() method call and will restore all local variables, as if the logical loop is continuing "magically" (read on for more info on how it works).

The view is nothing special, except for that fact that it adheres to the URL concerns and uses the Form tag to render the URL. This makes sure that the continue parameter is included in all requests.

Error formatting macro: snippet: java.lang.IllegalArgumentException: Invalid url: must begin with a configured prefix.

Advanced: How it Works

Continuations are not magic, though sometimes they might seem like they are. In fact, they work by using some very intelligent byte-code manipulation. This means that in order to use continuations, your deployment environment allow for custom class loaders to handle loading your actions. Typically this is not a problem, but it should be called out.

Once the class is requested to be loaded, the framework will hand off the request to the RIFE/Continuations module, which will then check a few conditions:

  1. Does the class extend ActionSupport?
  2. Does the class have an execute() method?
  3. In the execute() method, are there any calls to pause()?

If the answer is yes to all three conditions, the class is then instrumented and the execute() method is rewritten with try/catch code, goto statements, and intelligent "state restoration" code. All this happens transparently and does not affect the ability to debug the class or otherwise code it.

See the pause() method JavaDocs in the ActionSupport class for more info:

Error formatting macro: snippet: java.lang.IllegalArgumentException: Invalid url: must begin with a configured prefix.