I'm considering the following FlowExecutionManager as a way to guarantee only one execution of a flow per http session and to 'rejoin' a previously abandoned flow without specifying the flow execution id. Flows are designated as singletons by adding the 'singleton' attribute in the flow definition.

SWF team, is this a bad idea? I suppose a flow marked as a singleton precludes launching a flow as a child of itself. Can you think of any other gotchas that would make using this problematic? Thanks!

Code:
import org.springframework.webflow.Event;
import org.springframework.webflow.Flow;
import org.springframework.webflow.execution.FlowExecution;
import org.springframework.webflow.execution.FlowExecutionStorage;
import org.springframework.webflow.execution.FlowExecutionStorageException;
import org.springframework.webflow.execution.NoSuchFlowExecutionException;
import org.springframework.webflow.execution.servlet.ServletEvent;
import org.springframework.webflow.execution.servlet.ServletFlowExecutionManager;

import java.io.Serializable;

/**
 * Enables singleton behavior for flows with the <code>singleton</code> attribute
 * set to "true".
 * <p/>
 * Specifically, when a singleton flow is requested by a client the HTTP session will
 * be examined for a pre-existing flow execution id for the requested flow.  If one is found
 * then the client will rejoin that flow execution.
 * <p/>
 * The default behavior still applies to non-singleton flows. Each request for a flow
 * that does not specify a flow execution id will generate a new flow execution.
 *
 * @author Alex Wolfe
 */
public class SingletonFlowExecutionManager extends ServletFlowExecutionManager &#123;
    private static final String SINGLETON_ANNOTATION = "singleton";

    /**
     * Get the flow execution id. If the execution id is provided by the <code>event</code>
     * then use it.  Otherwise if the flow is annotated as a singleton, examine the session
     * to determine if an execution of the flow has already been stored.  If it has, then we
     * want to reuse the stored execution, and thus its id is returned.
     * <p/>
     * If no flow execution was requested and the flow is  not a singleton &#40;or if no singleton
     * excution id was found in the session&#41;, then return <code>null</code>.
     *
     * @param event The source http event
     * @return Either the requested flow execution id, the singleton flow execution id, or <code>
     *         null</code> if no flow execution id is available
     */
    protected String getFlowExecutionId&#40;Event event&#41; &#123;
        String flowExecutionId = super.getFlowExecutionId&#40;event&#41;;
        return flowExecutionId == null ? getFlowExecutionIdFromSession&#40;event, getFlow&#40;event&#41;&#41; &#58; flowExecutionId;
    &#125;

    /**
     * Examine the HTTP Session for a pre-existing flow execution id for the specified
     * singleton flow. If the flow isn't a singleton, then simply return null.
     * Flow execution ids are stored in the session, keyed by the corresponding flow id
     * for all singleton flows.
     *
     * @param requestingEvent The external http event
     * @param flow            The flow
     * @return The flow execution id for the specified singleton flow, if it the specified flow
     *         is a singleton, otherwise return </code>null</code>
     */
    protected String getFlowExecutionIdFromSession&#40;Event requestingEvent, Flow flow&#41; &#123;
        if &#40;isSingleton&#40;flow&#41;&#41;
            return &#40;String&#41; ServletEvent.getSession&#40;requestingEvent, false&#41;.getAttribute&#40;flow.getId&#40;&#41;&#41;;
        return null;
    &#125;

    /**
     * If the specified <code>flow</code> is a singleton flow, then set the <code>flowExecutionId</code>
     * in the http session keyed by flow id. Otherwise, do nothing.
     *
     * @param requestingEvent The external http event
     * @param flow            The flow
     * @param flowExecutionId The flow execution id to set
     * @return The unmodified flowExecutionId
     */
    protected Serializable setFlowExecutionIdInSession&#40;Event requestingEvent, Flow flow, Serializable flowExecutionId&#41; &#123;
        if &#40;isSingleton&#40;flow&#41;&#41;
            ServletEvent.getSession&#40;requestingEvent, false&#41;.setAttribute&#40;flow.getId&#40;&#41;, flowExecutionId&#41;;
        return flowExecutionId;
    &#125;

    /**
     * Is the specified flow a singleton flow?  Meaning, do all requests from a single client for
     * this flow use the same flow execution?
     *
     * @param flow The flow
     * @return <code>true</code> if the flow is a singleton, otherwise <code>false</code>
     */
    protected boolean isSingleton&#40;Flow flow&#41; &#123;
        return flow.containsAttribute&#40;SINGLETON_ANNOTATION&#41; &&
                flow.getAttribute&#40;SINGLETON_ANNOTATION&#41;.equals&#40;"true"&#41;;
    &#125;

    /**
     * Set the <code>FlowExecutionStorage</code> strategy after anonymously wrapping
     * the specified <code>storage</code> such that all calls to
     * <code>FlowExecutionStorage.save&#40;Serializable, FlowExecution, Event&#41;</code> map
     * root flow id to flow execution id in the http session.
     * <p/>
     * This mapping is later examined to rejoin previously started flow executions using
     * nothing more than the flow id.
     *
     * @param storage The <code>FlowExecutionStorage</code> to be wrapped and set.
     */
    public void setStorage&#40;final FlowExecutionStorage storage&#41; &#123;
        super.setStorage&#40;new FlowExecutionStorage&#40;&#41; &#123;
            public FlowExecution load&#40;Serializable id, Event requestingEvent&#41; 
                    throws NoSuchFlowExecutionException, FlowExecutionStorageException &#123;
                return storage.load&#40;id, requestingEvent&#41;;
            &#125;

            public Serializable save&#40;Serializable id, FlowExecution flowExecution, Event requestingEvent&#41; 
                    throws FlowExecutionStorageException &#123;
                return setFlowExecutionIdInSession&#40;
                        requestingEvent,
                        flowExecution.getRootFlow&#40;&#41;,
                        storage.save&#40;id, flowExecution, requestingEvent&#41;
                &#41;;
            &#125;

            public void remove&#40;Serializable id, Event requestingEvent&#41; throws FlowExecutionStorageException &#123;
                storage.remove&#40;id, requestingEvent&#41;;
            &#125;
        &#125;&#41;;
    &#125;
&#125;