Interacting with the calling environment

This tip explains how Spring Web Flow code can interact with the calling environment.
19/01/2007 - By Erwin Vervaet (erwin@ervacon.com) - Spring Web Flow version 1.0

The Spring Web Flow framework integrates with a number of hosting Web MVC frameworks, like Spring MVC and Struts. It also supports several different environments like Servlets, Portlets and JUnit tests. To make this possible, Spring Web Flow exists at a higher level of abstraction. Instead of giving the developer direct access to environment specific constructs like the HttpServletRequest, Spring Web Flow allows application code to interact with the framework using the RequestContext.

In most cases, this higher level of abstraction is beneficial. For instance, it allows you to reuse a flow in both a Servlet and a Portlet environment without changes. However, it is sometimes needed to get direct access to the calling environment from inside a Web Flow. How do we do that?

The gateway provided by Spring Web Flow to access the calling environment is the ExternalContext, available from the RequestContext. The ExternalContext allows abstracted access to common functionality provided by the calling environment. For instance, the ExternalContext.getSessionMap method allows you to access attributes stored in the HttpSession when running in a Servlet environment.

If you really need to get to the low level details of the calling environment, you can do that by downcasting the ExternalContext to an environment specific subclass. For instance, the following Action obtains a direct reference to the calling HttpServletRequest and uses it to get the HTTP method (GET, POST, ...) used in the request.

public class SampleAction extends AbstractAction {

	@Override
	protected Event doExecute(RequestContext context) throws Exception {
		ServletExternalContext externalContext = (ServletExternalContext)context.getExternalContext();
		HttpServletRequest request = externalContext.getRequest();
		context.getRequestScope().put("httpMethod", request.getMethod());
		return success();
	}
}

The ExternalContext JavaDoc lists all known subclasses. Each subclass provides access to the low level elements of a particular environment. For instance, the StrutsExternalContext allows you to get a reference to the Struts ActionMapping.

It's a best practice to try and keep your flows environment independent. Doing that maximizes reuse possibilities. If you still need low level access to the calling environment, consider factoring this logic into a FlowExecutionListener. That way you can plugin the behavior depending on the deployment situation.

As an example, we could refactor the above SampleAction into a SampleListener that puts the HTTP request method into request scope like so:

public class SampleListener extends FlowExecutionListenerAdapter {
	
	@Override
	public void requestSubmitted(RequestContext context) {
		ServletExternalContext externalContext = (ServletExternalContext)context.getExternalContext();
		HttpServletRequest request = externalContext.getRequest();
		context.getRequestScope().put("httpMethod", request.getMethod());
	}
}

This will keep the main flow environment independent. We can just plug the listener into the flow execution when we're deploying in a Servlet engine.

Discussion

Discuss this tip with fellow Spring Web Flow users on the Spring Web Flow forum.

For more Spring Web Flow related information, visit the Ervacon Spring Web Flow Portal and read Working with Spring Web Flow.

© Copyright Ervacon 2008. All Rights Reserved. Contact us.
All trademarks and copyrights on this page are owned by their respective owners.