<commit_before>/*
 * 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.config.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 <NAME>
 * @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] = true;
			}
			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;
	}
}
<commit_msg>Only remove cookie if ended flow session has no parent session.<commit_after>/*
 * 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.config.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 <NAME>
 * @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;
	}
}

{'fraction_non_alphanumeric': 0.0884095397235303, 'fraction_numerical': 0.004557192769254139, 'mean_word_length': 4.787692307692308, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7666016', 'n_tokens_mistral': 3978, 'n_tokens_neox': 3585, 'n_words': 1053}