001: /*
002: * Copyright 2004-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.springframework.webflow.engine.builder;
017:
018: import org.springframework.binding.mapping.AttributeMapper;
019: import org.springframework.webflow.core.collection.AttributeMap;
020: import org.springframework.webflow.engine.ActionState;
021: import org.springframework.webflow.engine.DecisionState;
022: import org.springframework.webflow.engine.EndState;
023: import org.springframework.webflow.engine.Flow;
024: import org.springframework.webflow.engine.FlowAttributeMapper;
025: import org.springframework.webflow.engine.FlowExecutionExceptionHandler;
026: import org.springframework.webflow.engine.State;
027: import org.springframework.webflow.engine.SubflowState;
028: import org.springframework.webflow.engine.TargetStateResolver;
029: import org.springframework.webflow.engine.Transition;
030: import org.springframework.webflow.engine.TransitionCriteria;
031: import org.springframework.webflow.engine.TransitionableState;
032: import org.springframework.webflow.engine.ViewSelector;
033: import org.springframework.webflow.engine.ViewState;
034: import org.springframework.webflow.execution.Action;
035:
036: /**
037: * A factory for core web flow elements such as {@link Flow flows},
038: * {@link State states}, and {@link Transition transitions}.
039: * <p>
040: * This factory encapsulates the construction of each Flow implementation as
041: * well as each core artifact type. Subclasses may customize how the core elements
042: * are created, useful for plugging in custom implementations.
043: *
044: * @author Keith Donald
045: * @author Erwin Vervaet
046: */
047: public class FlowArtifactFactory {
048:
049: /**
050: * Factory method that creates a new {@link Flow} definition object.
051: * <p>
052: * Note this method does not return a fully configured Flow instance, it
053: * only encapsulates the selection of implementation. A
054: * {@link FlowAssembler} delegating to a calling {@link FlowBuilder} is
055: * expected to assemble the Flow fully before returning it to external
056: * clients.
057: * @param id the flow identifier, should be unique to all flows in an
058: * application (required)
059: * @param attributes attributes to assign to the Flow, which may also be
060: * used to affect flow construction; may be null
061: * @return the initial flow instance, ready for assembly by a FlowBuilder
062: * @throws FlowArtifactLookupException an exception occured creating the
063: * Flow instance
064: */
065: public Flow createFlow(String id, AttributeMap attributes)
066: throws FlowArtifactLookupException {
067: Flow flow = new Flow(id);
068: flow.getAttributeMap().putAll(attributes);
069: return flow;
070: }
071:
072: /**
073: * Factory method that creates a new view state, a state where a user is
074: * allowed to participate in the flow. This method is an atomic operation
075: * that returns a fully initialized state. It encapsulates the selection of
076: * the view state implementation as well as the state assembly.
077: * @param id the identifier to assign to the state, must be unique to its
078: * owning flow (required)
079: * @param flow the flow that will own (contain) this state (required)
080: * @param entryActions any state entry actions; may be null
081: * @param viewSelector the state view selector strategy; may be null
082: * @param renderActions any 'render actions' to execute on entry and refresh;
083: * may be null
084: * @param transitions any transitions (paths) out of this state; may be null
085: * @param exceptionHandlers any exception handlers; may be null
086: * @param exitActions any state exit actions; may be null
087: * @param attributes attributes to assign to the State, which may also be
088: * used to affect state construction; may be null
089: * @return the fully initialized view state instance
090: * @throws FlowArtifactLookupException an exception occured creating the
091: * state
092: */
093: public State createViewState(String id, Flow flow,
094: Action[] entryActions, ViewSelector viewSelector,
095: Action[] renderActions, Transition[] transitions,
096: FlowExecutionExceptionHandler[] exceptionHandlers,
097: Action[] exitActions, AttributeMap attributes)
098: throws FlowArtifactLookupException {
099: ViewState viewState = new ViewState(flow, id);
100: if (viewSelector != null) {
101: viewState.setViewSelector(viewSelector);
102: }
103: viewState.getRenderActionList().addAll(renderActions);
104: configureCommonProperties(viewState, entryActions, transitions,
105: exceptionHandlers, exitActions, attributes);
106: return viewState;
107: }
108:
109: /**
110: * Factory method that creates a new action state, a state where a system
111: * action is executed. This method is an atomic operation that returns a
112: * fully initialized state. It encapsulates the selection of the action
113: * state implementation as well as the state assembly.
114: * @param id the identifier to assign to the state, must be unique to its
115: * owning flow (required)
116: * @param flow the flow that will own (contain) this state (required)
117: * @param entryActions any state entry actions; may be null
118: * @param actions the actions to execute when the state is entered
119: * (required)
120: * @param transitions any transitions (paths) out of this state; may be null
121: * @param exceptionHandlers any exception handlers; may be null
122: * @param exitActions any state exit actions; may be null
123: * @param attributes attributes to assign to the State, which may also be
124: * used to affect state construction; may be null
125: * @return the fully initialized action state instance
126: * @throws FlowArtifactLookupException an exception occured creating the
127: * state
128: */
129: public State createActionState(String id, Flow flow,
130: Action[] entryActions, Action[] actions,
131: Transition[] transitions,
132: FlowExecutionExceptionHandler[] exceptionHandlers,
133: Action[] exitActions, AttributeMap attributes)
134: throws FlowArtifactLookupException {
135: ActionState actionState = new ActionState(flow, id);
136: actionState.getActionList().addAll(actions);
137: configureCommonProperties(actionState, entryActions,
138: transitions, exceptionHandlers, exitActions, attributes);
139: return actionState;
140: }
141:
142: /**
143: * Factory method that creates a new decision state, a state where a flow
144: * routing decision is made. This method is an atomic operation that returns
145: * a fully initialized state. It encapsulates the selection of the decision
146: * state implementation as well as the state assembly.
147: * @param id the identifier to assign to the state, must be unique to its
148: * owning flow (required)
149: * @param flow the flow that will own (contain) this state (required)
150: * @param entryActions any state entry actions; may be null
151: * @param transitions any transitions (paths) out of this state
152: * @param exceptionHandlers any exception handlers; may be null
153: * @param exitActions any state exit actions; may be null
154: * @param attributes attributes to assign to the State, which may also be
155: * used to affect state construction; may be null
156: * @return the fully initialized decision state instance
157: * @throws FlowArtifactLookupException an exception occured creating the
158: * state
159: */
160: public State createDecisionState(String id, Flow flow,
161: Action[] entryActions, Transition[] transitions,
162: FlowExecutionExceptionHandler[] exceptionHandlers,
163: Action[] exitActions, AttributeMap attributes)
164: throws FlowArtifactLookupException {
165: DecisionState decisionState = new DecisionState(flow, id);
166: configureCommonProperties(decisionState, entryActions,
167: transitions, exceptionHandlers, exitActions, attributes);
168: return decisionState;
169: }
170:
171: /**
172: * Factory method that creates a new subflow state, a state where a parent
173: * flow spawns another flow as a subflow. This method is an atomic operation
174: * that returns a fully initialized state. It encapsulates the selection of
175: * the subflow state implementation as well as the state assembly.
176: * @param id the identifier to assign to the state, must be unique to its
177: * owning flow (required)
178: * @param flow the flow that will own (contain) this state (required)
179: * @param entryActions any state entry actions; may be null
180: * @param subflow the subflow definition (required)
181: * @param attributeMapper the subflow input and output attribute mapper; may
182: * be null
183: * @param transitions any transitions (paths) out of this state
184: * @param exceptionHandlers any exception handlers; may be null
185: * @param exitActions any state exit actions; may be null
186: * @param attributes attributes to assign to the State, which may also be
187: * used to affect state construction; may be null
188: * @return the fully initialized subflow state instance
189: * @throws FlowArtifactLookupException an exception occured creating the
190: * state
191: */
192: public State createSubflowState(String id, Flow flow,
193: Action[] entryActions, Flow subflow,
194: FlowAttributeMapper attributeMapper,
195: Transition[] transitions,
196: FlowExecutionExceptionHandler[] exceptionHandlers,
197: Action[] exitActions, AttributeMap attributes)
198: throws FlowArtifactLookupException {
199: SubflowState subflowState = new SubflowState(flow, id, subflow);
200: if (attributeMapper != null) {
201: subflowState.setAttributeMapper(attributeMapper);
202: }
203: configureCommonProperties(subflowState, entryActions,
204: transitions, exceptionHandlers, exitActions, attributes);
205: return subflowState;
206: }
207:
208: /**
209: * Factory method that creates a new end state, a state where an executing
210: * flow session terminates. This method is an atomic operation that returns
211: * a fully initialized state. It encapsulates the selection of the end state
212: * implementation as well as the state assembly.
213: * @param id the identifier to assign to the state, must be unique to its
214: * owning flow (required)
215: * @param flow the flow that will own (contain) this state (required)
216: * @param entryActions any state entry actions; may be null
217: * @param viewSelector the state confirmation view selector strategy; may be
218: * null
219: * @param outputMapper the state output mapper; may be null
220: * @param exceptionHandlers any exception handlers; may be null
221: * @param attributes attributes to assign to the State, which may also be
222: * used to affect state construction; may be null
223: * @return the fully initialized subflow state instance
224: * @throws FlowArtifactLookupException an exception occured creating the
225: * state
226: */
227: public State createEndState(String id, Flow flow,
228: Action[] entryActions, ViewSelector viewSelector,
229: AttributeMapper outputMapper,
230: FlowExecutionExceptionHandler[] exceptionHandlers,
231: AttributeMap attributes) throws FlowArtifactLookupException {
232: EndState endState = new EndState(flow, id);
233: if (viewSelector != null) {
234: endState.setViewSelector(viewSelector);
235: }
236: if (outputMapper != null) {
237: endState.setOutputMapper(outputMapper);
238: }
239: configureCommonProperties(endState, entryActions,
240: exceptionHandlers, attributes);
241: return endState;
242: }
243:
244: /**
245: * Factory method that creates a new transition, a path from one step in a
246: * flow to another. This method is an atomic operation that returns a fully
247: * initialized transition. It encapsulates the selection of the transition
248: * implementation as well as the transition assembly.
249: * @param targetStateResolver the resolver of the target state of the transition (required)
250: * @param matchingCriteria the criteria that matches the transition; may be
251: * null
252: * @param executionCriteria the criteria that governs execution of the
253: * transition after match; may be null
254: * @param attributes attributes to assign to the transition, which may also
255: * be used to affect transition construction; may be null
256: * @return the fully initialized transition instance
257: * @throws FlowArtifactLookupException an exception occured creating the
258: * transition
259: */
260: public Transition createTransition(
261: TargetStateResolver targetStateResolver,
262: TransitionCriteria matchingCriteria,
263: TransitionCriteria executionCriteria,
264: AttributeMap attributes) throws FlowArtifactLookupException {
265: Transition transition = new Transition(targetStateResolver);
266: if (matchingCriteria != null) {
267: transition.setMatchingCriteria(matchingCriteria);
268: }
269: if (executionCriteria != null) {
270: transition.setExecutionCriteria(executionCriteria);
271: }
272: transition.getAttributeMap().putAll(attributes);
273: return transition;
274: }
275:
276: // internal helpers
277:
278: /**
279: * Configure common properties for a transitionable state.
280: */
281: private void configureCommonProperties(TransitionableState state,
282: Action[] entryActions, Transition[] transitions,
283: FlowExecutionExceptionHandler[] exceptionHandlers,
284: Action[] exitActions, AttributeMap attributes) {
285: configureCommonProperties(state, entryActions,
286: exceptionHandlers, attributes);
287: state.getTransitionSet().addAll(transitions);
288: state.getExitActionList().addAll(exitActions);
289: }
290:
291: /**
292: * Configure common properties for a state.
293: */
294: private void configureCommonProperties(State state,
295: Action[] entryActions,
296: FlowExecutionExceptionHandler[] exceptionHandlers,
297: AttributeMap attributes) {
298: state.getEntryActionList().addAll(entryActions);
299: state.getExceptionHandlerSet().addAll(exceptionHandlers);
300: state.getAttributeMap().putAll(attributes);
301: }
302: }
|