/* * 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.engine.impl; import java.util.Iterator; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.util.Assert; import org.springframework.webflow.core.collection.AttributeMap; import org.springframework.webflow.core.collection.CollectionUtils; import org.springframework.webflow.core.collection.LocalAttributeMap; import org.springframework.webflow.core.collection.MutableAttributeMap; import org.springframework.webflow.definition.FlowDefinition; import org.springframework.webflow.definition.registry.FlowDefinitionLocator; import org.springframework.webflow.engine.Flow; import org.springframework.webflow.execution.FlowExecution; import org.springframework.webflow.execution.FlowExecutionFactory; import org.springframework.webflow.execution.FlowExecutionKey; import org.springframework.webflow.execution.FlowExecutionKeyFactory; import org.springframework.webflow.execution.factory.FlowExecutionListenerLoader; import org.springframework.webflow.execution.factory.StaticFlowExecutionListenerLoader; /** * A factory for instances of the {@link FlowExecutionImpl default flow execution} implementation. * @author Keith Donald */ public class FlowExecutionImplFactory implements FlowExecutionFactory { private static final Log logger = LogFactory.getLog(FlowExecutionImplFactory.class); private AttributeMap<Object> executionAttributes = CollectionUtils.EMPTY_ATTRIBUTE_MAP; private FlowExecutionListenerLoader executionListenerLoader = StaticFlowExecutionListenerLoader.EMPTY_INSTANCE; private FlowExecutionKeyFactory executionKeyFactory = new SimpleFlowExecutionKeyFactory(); /** * Sets the attributes to apply to flow executions created by this factory. Execution attributes may affect flow * execution behavior. * @param executionAttributes flow execution system attributes */ public void setExecutionAttributes(AttributeMap<Object> executionAttributes) { this.executionAttributes = executionAttributes; } /** * Sets the strategy for loading listeners that should observe executions of a flow definition. Allows full control * over what listeners should apply for executions of a flow definition. */ public void setExecutionListenerLoader(FlowExecutionListenerLoader executionListenerLoader) { this.executionListenerLoader = executionListenerLoader; } /** * Sets the strategy for generating flow execution keys for persistent flow executions. */ public void setExecutionKeyFactory(FlowExecutionKeyFactory executionKeyFactory) { this.executionKeyFactory = executionKeyFactory; } public FlowExecution createFlowExecution(FlowDefinition flowDefinition) { Assert.isInstanceOf(Flow.class, flowDefinition, "FlowDefinition is of the wrong type: "); if (logger.isDebugEnabled()) { logger.debug("Creating new execution of '" + flowDefinition.getId() + "'"); } FlowExecutionImpl execution = new FlowExecutionImpl((Flow) flowDefinition); execution.setAttributes(executionAttributes); execution.setListeners(executionListenerLoader.getListeners(execution.getDefinition())); execution.setKeyFactory(executionKeyFactory); return execution; } public FlowExecution restoreFlowExecution(FlowExecution flowExecution, FlowDefinition flowDefinition, FlowExecutionKey flowExecutionKey, MutableAttributeMap<Object> conversationScope, FlowDefinitionLocator subflowDefinitionLocator) { Assert.isInstanceOf(FlowExecutionImpl.class, flowExecution, "FlowExecution is of the wrong type: "); Assert.isInstanceOf(Flow.class, flowDefinition, "FlowDefinition is of the wrong type: "); FlowExecutionImpl execution = (FlowExecutionImpl) flowExecution; Flow flow = (Flow) flowDefinition; execution.setFlow(flow); if (execution.hasSessions()) { FlowSessionImpl rootSession = execution.getRootSession(); rootSession.setFlow(flow); rootSession.setState(flow.getStateInstance(rootSession.getStateId())); if (execution.hasSubflowSessions()) { for (Iterator<FlowSessionImpl> it = execution.getSubflowSessionIterator(); it.hasNext();) { FlowSessionImpl subflowSession = it.next(); Flow subflowDef = (Flow) subflowDefinitionLocator.getFlowDefinition(subflowSession.getFlowId()); subflowSession.setFlow(subflowDef); subflowSession.setState(subflowDef.getStateInstance(subflowSession.getStateId())); } } } execution.setKey(flowExecutionKey); if (conversationScope == null) { conversationScope = new LocalAttributeMap<Object>(); } execution.setConversationScope(conversationScope); execution.setAttributes(executionAttributes); execution.setListeners(executionListenerLoader.getListeners(execution.getDefinition())); execution.setKeyFactory(executionKeyFactory); return execution; } /** * Simple key factory suitable for standalone usage and testing. Not expected to be used in a web environment. */ private static class SimpleFlowExecutionKeyFactory implements FlowExecutionKeyFactory { private int sequence; public FlowExecutionKey getKey(FlowExecution execution) { if (execution.getKey() == null) { return new SimpleFlowExecutionKey(nextSequence()); } else { // keep the same key return execution.getKey(); } } public void removeAllFlowExecutionSnapshots(FlowExecution execution) { } public void removeFlowExecutionSnapshot(FlowExecution execution) { } public void updateFlowExecutionSnapshot(FlowExecution execution) { } private synchronized int nextSequence() { return ++sequence; } private static class SimpleFlowExecutionKey extends FlowExecutionKey { private int value; public SimpleFlowExecutionKey(int value) { this.value = value; } public boolean equals(Object o) { if (!(o instanceof SimpleFlowExecutionKey)) { SimpleFlowExecutionKey key = (SimpleFlowExecutionKey) o; return value == key.value; } return false; } public int hashCode() { return value; } public String toString() { return String.valueOf(value); } } } }