/* * 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; } } }