| /* |
| * Copyright 2004-2005 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.codehaus.groovy.grails.web.pageflow.execution.servlet; |
| |
| import java.io.Serializable; |
| import java.util.Map; |
| |
| import javax.servlet.http.Cookie; |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| |
| import org.apache.commons.lang.StringUtils; |
| import org.codehaus.groovy.grails.web.pageflow.exceptions.NoViewDefinedException; |
| import org.springframework.webflow.Event; |
| import org.springframework.webflow.Flow; |
| import org.springframework.webflow.FlowExecutionContext; |
| import org.springframework.webflow.FlowSession; |
| import org.springframework.webflow.RequestContext; |
| import org.springframework.webflow.State; |
| import org.springframework.webflow.ViewDescriptor; |
| import org.springframework.webflow.access.FlowLocator; |
| import org.springframework.webflow.execution.EnterStateVetoException; |
| import org.springframework.webflow.execution.FlowExecutionListener; |
| import org.springframework.webflow.execution.servlet.ServletEvent; |
| import org.springframework.webflow.execution.servlet.ServletFlowExecutionManager; |
| |
| /** |
| * <p>This specialisation of {@link org.springframework.webflow.execution.servlet.ServletFlowExecutionManager} |
| * stores and retrieves the flow execution id from a cookie if no flow execution id parameter is available. |
| * |
| * <p>Users must use the regular Spring Web Flow mechanism of passing the flow execution id as a parameter if |
| * more than one page flow is configured for a given URI. |
| * |
| * <p>The <code>_reset</code> parameter may be set to <code>true</code> to reset the flow execution id cookie value. |
| * This may be useful during development when the application server may be restarted often. The flow execution associated |
| * with the id stored in the cookie may be lost after a restart. Normally the browser needs to be closed to remove the cookie |
| * value. The <code>_reset</code> parameter does this for you. Remove the parameter from the URL to continue working |
| * with flow (not removing it will reset the cookie value on each request). |
| * |
| * @author Steven Devijver |
| * @since Jul 19, 2005 |
| */ |
| public class GrailsServletFlowExecutionManager extends |
| ServletFlowExecutionManager { |
| |
| public static final String FLOW_EXECUTION_ID_COOKIE_NAME = GrailsServletFlowExecutionManager.class.getName() + "$FlowExecutionIdCookie"; |
| private static final String TRUE = "true"; |
| private static final String RESET_PARAMETER = "_reset"; |
| |
| public GrailsServletFlowExecutionManager() { |
| super(); |
| } |
| |
| public GrailsServletFlowExecutionManager(Flow flow) { |
| super(flow); |
| } |
| |
| public GrailsServletFlowExecutionManager(FlowLocator flowLocator) { |
| super(flowLocator); |
| } |
| |
| protected Event createEvent(HttpServletRequest request, |
| HttpServletResponse response) { |
| return super.createEvent(request, response); |
| } |
| |
| protected String getFlowExecutionId(Event event) { |
| if (event instanceof ServletEvent) { |
| String flowExecutionId = super.getFlowExecutionId(event); |
| if (StringUtils.isBlank(flowExecutionId)) { |
| String resetValue = (String)event.getParameter(RESET_PARAMETER); |
| if (StringUtils.isNotBlank(resetValue) && TRUE.equals(resetValue)) { |
| ((ServletEvent)event).getRequest().setAttribute(RESET_PARAMETER, TRUE); |
| return null; |
| } |
| Cookie[] cookies = ((ServletEvent)event).getRequest().getCookies(); |
| for (int i = 0; cookies != null && i < cookies.length; i++) { |
| if (FLOW_EXECUTION_ID_COOKIE_NAME.equals(cookies[i].getName())) { |
| if (StringUtils.isNotBlank(cookies[i].getValue())) { |
| return cookies[i].getValue(); |
| } else { |
| return null; |
| } |
| } |
| } |
| return null; |
| } else { |
| return flowExecutionId; |
| } |
| } else { |
| return super.getFlowExecutionId(event); |
| } |
| } |
| |
| public ViewDescriptor handle(HttpServletRequest request, |
| HttpServletResponse response) throws Exception { |
| final boolean[] created = new boolean[1]; |
| final boolean[] sessionEnded = new boolean[1]; |
| final State[] stateEntered = new State[1]; |
| created[0] = false; |
| sessionEnded[0] = false; |
| ViewDescriptor viewDescriptor = super.handle(request, response, new FlowExecutionListener() { |
| public void created(FlowExecutionContext context) { |
| created[0] = true; |
| } |
| public void sessionStarted(RequestContext context) { |
| } |
| public void resumed(RequestContext context) { |
| } |
| public void sessionEnded(RequestContext context, FlowSession endedSession) { |
| sessionEnded[0] = endedSession.getParent() == null; |
| } |
| public void stateEntered(RequestContext context, State previousState, State state) { |
| stateEntered[0] = state; |
| } |
| public void eventSignaled(RequestContext context) { |
| } |
| public void requestProcessed(RequestContext context) { |
| } |
| public void loaded(FlowExecutionContext context, Serializable id) { |
| } |
| public void paused(RequestContext context) { |
| } |
| public void removed(FlowExecutionContext context, Serializable id) { |
| } |
| public void requestSubmitted(RequestContext context) { |
| } |
| public void saved(FlowExecutionContext context, Serializable id) { |
| } |
| public void sessionStarting(RequestContext context, State startState, Map input) throws EnterStateVetoException { |
| } |
| public void stateEntering(RequestContext context, State nextState) throws EnterStateVetoException { |
| } |
| }); |
| |
| if (viewDescriptor == null) { |
| throw new NoViewDefinedException("No view defined for state [" + stateEntered[0].getId() + "]!"); |
| } |
| |
| Cookie flowExecutionIdCookie = null; |
| if (sessionEnded[0] || (request.getAttribute(RESET_PARAMETER) != null && request.getAttribute(RESET_PARAMETER).equals(TRUE))) { |
| flowExecutionIdCookie = new Cookie(FLOW_EXECUTION_ID_COOKIE_NAME, ""); |
| } else if (created[0]) { |
| flowExecutionIdCookie = new Cookie(FLOW_EXECUTION_ID_COOKIE_NAME, (String)viewDescriptor.getAttribute(FLOW_EXECUTION_ID_ATTRIBUTE)); |
| } |
| if (flowExecutionIdCookie != null) { |
| response.addCookie(flowExecutionIdCookie); |
| } |
| |
| return viewDescriptor; |
| } |
| } |