/* * 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.builder; import org.springframework.binding.expression.Expression; import org.springframework.binding.mapping.Mapper; import org.springframework.webflow.core.collection.AttributeMap; import org.springframework.webflow.engine.ActionState; import org.springframework.webflow.engine.DecisionState; import org.springframework.webflow.engine.EndState; import org.springframework.webflow.engine.Flow; import org.springframework.webflow.engine.FlowExecutionExceptionHandler; import org.springframework.webflow.engine.State; import org.springframework.webflow.engine.SubflowAttributeMapper; import org.springframework.webflow.engine.SubflowState; import org.springframework.webflow.engine.TargetStateResolver; import org.springframework.webflow.engine.Transition; import org.springframework.webflow.engine.TransitionCriteria; import org.springframework.webflow.engine.TransitionableState; import org.springframework.webflow.engine.ViewState; import org.springframework.webflow.engine.ViewVariable; import org.springframework.webflow.execution.Action; import org.springframework.webflow.execution.ViewFactory; /** * A factory for core web flow elements such as {@link Flow flows}, {@link State states}, and {@link Transition * transitions}. * <p> * This factory encapsulates the construction of each Flow implementation as well as each core artifact type. Subclasses * may customize how the core elements are created. * * @author Keith Donald * @author Erwin Vervaet */ public class FlowArtifactFactory { /** * Factory method that creates a new {@link Flow} definition object. * <p> * Note this method does not return a fully configured Flow instance, it only encapsulates the selection of * implementation. A {@link FlowAssembler} delegating to a calling {@link FlowBuilder} is expected to assemble the * Flow fully before returning it to external clients. * @param id the flow identifier, should be unique to all flows in an application (required) * @param attributes attributes to assign to the Flow, which may also be used to affect flow construction; may be * null * @return the initial flow instance, ready for assembly by a FlowBuilder */ public Flow createFlow(String id, AttributeMap<?> attributes) { return Flow.create(id, attributes); } /** * Factory method that creates a new view state, a state where a user is allowed to participate in the flow. This * method is an atomic operation that returns a fully initialized state. It encapsulates the selection of the view * state implementation as well as the state assembly. * @param id the identifier to assign to the state, must be unique to its owning flow (required) * @param flow the flow that will own (contain) this state (required) * @param entryActions any state entry actions; may be null * @param viewFactory the state view factory strategy * @param redirect whether to send a flow execution redirect before rendering * @param popup whether to display the view in a popup window * @param renderActions any 'render actions' to execute on entry and refresh; may be null * @param transitions any transitions (paths) out of this state; may be null * @param exceptionHandlers any exception handlers; may be null * @param exitActions any state exit actions; may be null * @param attributes attributes to assign to the State, which may also be used to affect state construction; may be * null * @return the fully initialized view state instance */ public State createViewState(String id, Flow flow, ViewVariable[] variables, Action[] entryActions, ViewFactory viewFactory, Boolean redirect, boolean popup, Action[] renderActions, Transition[] transitions, FlowExecutionExceptionHandler[] exceptionHandlers, Action[] exitActions, AttributeMap<?> attributes) { ViewState viewState = new ViewState(flow, id, viewFactory); viewState.addVariables(variables); viewState.setRedirect(redirect); viewState.setPopup(popup); viewState.getRenderActionList().addAll(renderActions); configureCommonProperties(viewState, entryActions, transitions, exceptionHandlers, exitActions, attributes); return viewState; } /** * Factory method that creates a new action state, a state where a system action is executed. This method is an * atomic operation that returns a fully initialized state. It encapsulates the selection of the action state * implementation as well as the state assembly. * @param id the identifier to assign to the state, must be unique to its owning flow (required) * @param flow the flow that will own (contain) this state (required) * @param entryActions any state entry actions; may be null * @param actions the actions to execute when the state is entered (required) * @param transitions any transitions (paths) out of this state; may be null * @param exceptionHandlers any exception handlers; may be null * @param exitActions any state exit actions; may be null * @param attributes attributes to assign to the State, which may also be used to affect state construction; may be * null * @return the fully initialized action state instance */ public State createActionState(String id, Flow flow, Action[] entryActions, Action[] actions, Transition[] transitions, FlowExecutionExceptionHandler[] exceptionHandlers, Action[] exitActions, AttributeMap<?> attributes) { ActionState actionState = new ActionState(flow, id); actionState.getActionList().addAll(actions); configureCommonProperties(actionState, entryActions, transitions, exceptionHandlers, exitActions, attributes); return actionState; } /** * Factory method that creates a new decision state, a state where a flow routing decision is made. This method is * an atomic operation that returns a fully initialized state. It encapsulates the selection of the decision state * implementation as well as the state assembly. * @param id the identifier to assign to the state, must be unique to its owning flow (required) * @param flow the flow that will own (contain) this state (required) * @param entryActions any state entry actions; may be null * @param transitions any transitions (paths) out of this state * @param exceptionHandlers any exception handlers; may be null * @param exitActions any state exit actions; may be null * @param attributes attributes to assign to the State, which may also be used to affect state construction; may be * null * @return the fully initialized decision state instance */ public State createDecisionState(String id, Flow flow, Action[] entryActions, Transition[] transitions, FlowExecutionExceptionHandler[] exceptionHandlers, Action[] exitActions, AttributeMap<?> attributes) { DecisionState decisionState = new DecisionState(flow, id); configureCommonProperties(decisionState, entryActions, transitions, exceptionHandlers, exitActions, attributes); return decisionState; } /** * Factory method that creates a new subflow state, a state where a parent flow spawns another flow as a subflow. * This method is an atomic operation that returns a fully initialized state. It encapsulates the selection of the * subflow state implementation as well as the state assembly. * @param id the identifier to assign to the state, must be unique to its owning flow (required) * @param flow the flow that will own (contain) this state (required) * @param entryActions any state entry actions; may be null * @param subflow the subflow definition (required) * @param attributeMapper the subflow input and output attribute mapper; may be null * @param transitions any transitions (paths) out of this state * @param exceptionHandlers any exception handlers; may be null * @param exitActions any state exit actions; may be null * @param attributes attributes to assign to the State, which may also be used to affect state construction; may be * null * @return the fully initialized subflow state instance */ public State createSubflowState(String id, Flow flow, Action[] entryActions, Expression subflow, SubflowAttributeMapper attributeMapper, Transition[] transitions, FlowExecutionExceptionHandler[] exceptionHandlers, Action[] exitActions, AttributeMap<?> attributes) { SubflowState subflowState = new SubflowState(flow, id, subflow); if (attributeMapper != null) { subflowState.setAttributeMapper(attributeMapper); } configureCommonProperties(subflowState, entryActions, transitions, exceptionHandlers, exitActions, attributes); return subflowState; } /** * Factory method that creates a new end state, a state where an executing flow session terminates. This method is * an atomic operation that returns a fully initialized state. It encapsulates the selection of the end state * implementation as well as the state assembly. * @param id the identifier to assign to the state, must be unique to its owning flow (required) * @param flow the flow that will own (contain) this state (required) * @param entryActions any state entry actions; may be null * @param finalResponseAction the state response renderer; may be null * @param outputMapper the state output mapper; may be null * @param exceptionHandlers any exception handlers; may be null * @param attributes attributes to assign to the State, which may also be used to affect state construction; may be * null * @return the fully initialized subflow state instance */ public State createEndState(String id, Flow flow, Action[] entryActions, Action finalResponseAction, Mapper outputMapper, FlowExecutionExceptionHandler[] exceptionHandlers, AttributeMap<?> attributes) { EndState endState = new EndState(flow, id); if (finalResponseAction != null) { endState.setFinalResponseAction(finalResponseAction); } if (outputMapper != null) { endState.setOutputMapper(outputMapper); } configureCommonProperties(endState, entryActions, exceptionHandlers, attributes); return endState; } /** * Factory method that creates a new transition, a path from one step in a flow to another. This method is an atomic * operation that returns a fully initialized transition. It encapsulates the selection of the transition * implementation as well as the transition assembly. * @param targetStateResolver the resolver of the target state of the transition (required) * @param matchingCriteria the criteria that matches the transition; may be null * @param executionCriteria the criteria that governs execution of the transition after match; may be null * @param attributes attributes to assign to the transition, which may also be used to affect transition * construction; may be null * @return the fully initialized transition instance */ public Transition createTransition(TargetStateResolver targetStateResolver, TransitionCriteria matchingCriteria, TransitionCriteria executionCriteria, AttributeMap<?> attributes) { Transition transition = new Transition(targetStateResolver); if (matchingCriteria != null) { transition.setMatchingCriteria(matchingCriteria); } if (executionCriteria != null) { transition.setExecutionCriteria(executionCriteria); } transition.getAttributes().putAll(attributes); return transition; } // internal helpers /** * Configure common properties for a transitionable state. */ private void configureCommonProperties(TransitionableState state, Action[] entryActions, Transition[] transitions, FlowExecutionExceptionHandler[] exceptionHandlers, Action[] exitActions, AttributeMap<?> attributes) { configureCommonProperties(state, entryActions, exceptionHandlers, attributes); state.getTransitionSet().addAll(transitions); state.getExitActionList().addAll(exitActions); } /** * Configure common properties for a state. */ private void configureCommonProperties(State state, Action[] entryActions, FlowExecutionExceptionHandler[] exceptionHandlers, AttributeMap<?> attributes) { state.getEntryActionList().addAll(entryActions); state.getExceptionHandlerSet().addAll(exceptionHandlers); state.getAttributes().putAll(attributes); } }