/*
* Copyright 2004-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.webflow.mvc.servlet;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import org.springframework.webflow.context.servlet.DefaultFlowUrlHandler;
import org.springframework.webflow.context.servlet.FlowUrlHandler;
import org.springframework.webflow.definition.FlowDefinition;
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
/**
* Implementation of {@link org.springframework.web.servlet.HandlerMapping} that follows a simple convention for
* creating URL path mappings from the <i>ids</i> of registered {@link FlowDefinition flow definitions}.
*
* This implementation returns a FlowHandler that invokes a flow if the current request path matches the id of a flow in
* the configured {@link FlowDefinitionRegistry}. Alternatively, a custom {@link FlowHandler} may also be registered
* with in containing ApplicationContext with that id and it will be returned. This allows for more control over the
* invocation of a flow from Spring MVC environment.
*
* Null is returned in the case of no flow id match, allowing the next handler mapping in the chain to execute.
*
* @author Keith Donald
*/
public class FlowHandlerMapping extends AbstractHandlerMapping {
private static final Log logger = LogFactory.getLog(FlowHandlerMapping.class);
private FlowDefinitionRegistry flowRegistry;
private FlowUrlHandler flowUrlHandler;
/**
* Returns the registry of flows to query when this mapping is tested.
* @return the flow definition registry
*/
public FlowDefinitionRegistry getFlowRegistry() {
return flowRegistry;
}
/**
* Sets the registry of flows to query when this mapping is tested. Optional. If not set, this handler mapping will
* look in the containing application context for a bean with id <code>flowRegistry</code>.
* @param flowRegistry the flow definition registry
*/
public void setFlowRegistry(FlowDefinitionRegistry flowRegistry) {
this.flowRegistry = flowRegistry;
}
/**
* Returns the configured flow url handler.
*/
public FlowUrlHandler getFlowUrlHandler() {
return flowUrlHandler;
}
/**
* Sets the flow URL handler, which allows customization for how the flow id is determined for each request tested
* by this mapping. Defaults to a {@link DefaultFlowUrlHandler}.
* @param flowUrlHandler the flow URL handler
*/
public void setFlowUrlHandler(FlowUrlHandler flowUrlHandler) {
this.flowUrlHandler = flowUrlHandler;
}
protected void initServletContext(ServletContext servletContext) {
Assert.notNull(flowRegistry, "The FlowRegistry to query when mapping requests is required");
if (flowUrlHandler == null) {
flowUrlHandler = new DefaultFlowUrlHandler();
}
}
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
String flowId = flowUrlHandler.getFlowId(request);
if (flowId == null) {
return null;
}
if (getApplicationContext().containsBean(flowId)) {
Object handler = getApplicationContext().getBean(flowId);
if (handler instanceof FlowHandler) {
if (logger.isDebugEnabled()) {
logger.debug("Mapping request with URI '" + request.getRequestURI() + "' to flow with id '"
+ flowId + "'; custom FlowHandler " + handler + " will manage flow execution");
}
return handler;
}
}
if (flowRegistry.containsFlowDefinition(flowId)) {
if (logger.isDebugEnabled()) {
logger.debug("Mapping request with URI '" + request.getRequestURI() + "' to flow with id '" + flowId
+ "'");
}
return createDefaultFlowHandler(flowId);
}
if (logger.isDebugEnabled()) {
logger.debug("No flow mapping found for request with URI '" + request.getRequestURI() + "'");
}
return null;
}
/**
* Factory method that returns the default flow handler for the flow with the given id. Subclasses may override to
* return their own custom default FlowHandler.
* @param flowId the id of the flow to handle invocation of
* @return the default flow handler
*/
protected FlowHandler createDefaultFlowHandler(String flowId) {
return new DefaultFlowHandler(flowId);
}
private static class DefaultFlowHandler extends AbstractFlowHandler {
private String flowId;
public DefaultFlowHandler(String flowId) {
this.flowId = flowId;
}
public String getFlowId() {
return flowId;
}
}
}