/*
* Copyright 2004-2012 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 java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.js.ajax.AjaxHandler;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import org.springframework.webflow.context.servlet.FilenameFlowUrlHandler;
import org.springframework.webflow.context.servlet.FlowUrlHandler;
import org.springframework.webflow.executor.FlowExecutor;
/**
* The adapter between the Spring MVC Controller layer and the Spring Web Flow engine. This controller allows Spring Web
* Flow to run embedded as a Controller within a DispatcherServlet, the key piece of the Spring Web MVC platform. It is
* expected a DispatcherServlet HandlerMapping will care for mapping all requests for flows to this controller for
* handling.
*
* @author Keith Donald
*/
public class FlowController implements Controller, ApplicationContextAware, InitializingBean {
private FlowHandlerAdapter flowHandlerAdapter;
private Map<String, FlowHandler> flowHandlers = new HashMap<String, FlowHandler>();
private boolean customFlowHandlerAdapterSet;
/**
* Creates a new flow controller.
* @see #setFlowExecutor(FlowExecutor)
* @see #setFlowUrlHandler(FlowUrlHandler)
* @see #setAjaxHandler(AjaxHandler)
* @see #setFlowHandlerAdapter(FlowHandlerAdapter)
* @see #afterPropertiesSet()
*/
public FlowController() {
flowHandlerAdapter = new FlowHandlerAdapter();
flowHandlerAdapter.setFlowUrlHandler(new FilenameFlowUrlHandler());
}
/**
* Returns the central service for executing flows. Required.
*/
public FlowExecutor getFlowExecutor() {
return flowHandlerAdapter.getFlowExecutor();
}
/**
* Sets the central service for executing flows. Required.
* @param flowExecutor
*/
public void setFlowExecutor(FlowExecutor flowExecutor) {
flowHandlerAdapter.setFlowExecutor(flowExecutor);
}
/**
* Returns the configured flow url handler.
*/
public FlowUrlHandler getFlowUrlHandler() {
return flowHandlerAdapter.getFlowUrlHandler();
}
/**
* Sets the configured flow url handler.
* @param urlHandler the flow url handler.
*/
public void setFlowUrlHandler(FlowUrlHandler urlHandler) {
flowHandlerAdapter.setFlowUrlHandler(urlHandler);
}
/**
* Returns the configured Ajax handler.
*/
public AjaxHandler getAjaxHandler() {
return flowHandlerAdapter.getAjaxHandler();
}
/**
* Sets the configured Ajax handler.
* @param ajaxHandler the ajax handler
*/
public void setAjaxHandler(AjaxHandler ajaxHandler) {
flowHandlerAdapter.setAjaxHandler(ajaxHandler);
}
/**
* Set whether redirects sent by this controller should be compatible with HTTP 1.0 clients.
* <p>
* By default, this will enforce a redirect HTTP status code of 302 by delegating to
* <code>HttpServletResponse.sendRedirect</code>. Setting this to false will send HTTP status code 303, which is the
* correct code for HTTP 1.1 clients, but not understood by HTTP 1.0 clients.
* <p>
* Many HTTP 1.1 clients treat 302 just like 303, not making any difference. However, some clients depend on 303
* when redirecting after a POST request; turn this flag off in such a scenario.
* @see javax.servlet.http.HttpServletResponse#sendRedirect
*/
public void setRedirectHttp10Compatible(boolean redirectHttp10Compatible) {
flowHandlerAdapter.setRedirectHttp10Compatible(redirectHttp10Compatible);
}
/**
* Sets the custom flow handles for managing the access to flows in a custom manner.
* @param flowHandlers the flow handler map
*/
public void setFlowHandlers(Map<String, FlowHandler> flowHandlers) {
this.flowHandlers = flowHandlers;
}
/**
* Registers a flow handler this controller should delegate to to customize the control logic associated with
* managing the execution of a specific flow.
* @param flowHandler the handler
*/
public void registerFlowHandler(FlowHandler flowHandler) {
flowHandlers.put(flowHandler.getFlowId(), flowHandler);
}
/**
* Returns the flow handler adapter which this Controller uses internally to carry out handler workflow.
*/
public FlowHandlerAdapter getFlowHandlerAdapter() {
return flowHandlerAdapter;
}
/**
* Sets the flow handler adapter which this Controller uses internally to carry out handler workflow. Call this
* instead of the convenience accesors to completely customize flow controller workflow.
* @param flowHandlerAdapter the flow handler adapter
*/
public void setFlowHandlerAdapter(FlowHandlerAdapter flowHandlerAdapter) {
this.flowHandlerAdapter = flowHandlerAdapter;
customFlowHandlerAdapterSet = true;
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (!customFlowHandlerAdapterSet) {
flowHandlerAdapter.setApplicationContext(applicationContext);
}
}
public void afterPropertiesSet() throws Exception {
if (!customFlowHandlerAdapterSet) {
flowHandlerAdapter.afterPropertiesSet();
}
}
// subclassing hooks
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
FlowHandler handler = getFlowHandler(request);
return flowHandlerAdapter.handle(request, response, handler);
}
// internal helpers
private FlowHandler getFlowHandler(HttpServletRequest request) {
FlowUrlHandler urlHandler = flowHandlerAdapter.getFlowUrlHandler();
String flowId = urlHandler.getFlowId(request);
return getFlowHandler(flowId);
}
private FlowHandler getFlowHandler(String flowId) {
FlowHandler handler = flowHandlers.get(flowId);
if (handler == null) {
handler = new DefaultFlowHandler(flowId);
}
return handler;
}
private static class DefaultFlowHandler extends AbstractFlowHandler {
private String flowId;
public DefaultFlowHandler(String flowId) {
this.flowId = flowId;
}
public String getFlowId() {
return flowId;
}
}
}