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.apache.commons.logging.Log;
019: import org.apache.commons.logging.LogFactory;
020: import org.springframework.util.Assert;
021: import org.springframework.webflow.core.collection.AttributeMap;
022: import org.springframework.webflow.core.collection.CollectionUtils;
023: import org.springframework.webflow.engine.Flow;
024:
025: /**
026: * A director for assembling flows, delegating to a {@link FlowBuilder} to
027: * construct a flow. This class encapsulates the algorithm for using a
028: * FlowBuilder to assemble a Flow properly. It acts as the director in the
029: * classic GoF builder pattern.
030: * <p>
031: * Flow assemblers may be used in a standalone, programmatic fashion as follows:
032: *
033: * <pre>
034: * FlowBuilder builder = ...;
035: * Flow flow = new FlowAssembler("myFlow", builder).assembleFlow();
036: * </pre>
037: *
038: * @see org.springframework.webflow.engine.builder.FlowBuilder
039: *
040: * @author Keith Donald
041: * @author Erwin Vervaet
042: */
043: public class FlowAssembler {
044:
045: private static final Log logger = LogFactory
046: .getLog(FlowAssembler.class);
047:
048: /**
049: * The identifier to assign to the flow.
050: */
051: private String flowId;
052:
053: /**
054: * Attributes that can be used to affect flow construction.
055: */
056: private AttributeMap flowAttributes;
057:
058: /**
059: * The flow builder strategy used to construct the flow from its component
060: * parts.
061: */
062: private FlowBuilder flowBuilder;
063:
064: /**
065: * Create a new flow assembler that will direct Flow assembly using the
066: * specified builder strategy.
067: * @param flowId the flow id to assign
068: * @param flowBuilder the builder the factory will use to build flows
069: */
070: public FlowAssembler(String flowId, FlowBuilder flowBuilder) {
071: this (flowId, null, flowBuilder);
072: }
073:
074: /**
075: * Create a new flow assembler that will direct Flow assembly using the
076: * specified builder strategy.
077: * @param flowId the flow id to assign
078: * @param flowAttributes externally assigned flow attributes that can affect
079: * flow construction
080: * @param flowBuilder the builder the factory will use to build flows
081: */
082: public FlowAssembler(String flowId, AttributeMap flowAttributes,
083: FlowBuilder flowBuilder) {
084: Assert.hasText(flowId, "The flow id is required");
085: Assert.notNull(flowBuilder, "The flow builder is required");
086: this .flowId = flowId;
087: this .flowAttributes = (flowAttributes != null ? flowAttributes
088: : CollectionUtils.EMPTY_ATTRIBUTE_MAP);
089: this .flowBuilder = flowBuilder;
090: }
091:
092: /**
093: * Returns the identifier to assign to the flow.
094: */
095: public String getFlowId() {
096: return flowId;
097: }
098:
099: /**
100: * Returns externally assigned attributes that can be used to affect flow
101: * construction.
102: */
103: public AttributeMap getFlowAttributes() {
104: return flowAttributes;
105: }
106:
107: /**
108: * Returns the flow builder strategy used to construct the flow from its
109: * component parts.
110: */
111: public FlowBuilder getFlowBuilder() {
112: return flowBuilder;
113: }
114:
115: /**
116: * Assembles the flow, directing the construction process by delegating to
117: * the configured FlowBuilder. Every call to this method will assemble
118: * the Flow instance.
119: * <p>
120: * This will drive the flow construction process as described in the
121: * {@link FlowBuilder} JavaDoc, starting with builder initialisation using
122: * {@link FlowBuilder#init(String, AttributeMap)} and finishing by
123: * cleaning up the builder with a call to {@link FlowBuilder#dispose()}.
124: * @return the constructed flow
125: * @throws FlowBuilderException when flow assembly fails
126: */
127: public Flow assembleFlow() throws FlowBuilderException {
128: if (logger.isDebugEnabled()) {
129: logger.debug("Assembling flow definition with id '"
130: + flowId + "' using flow builder '" + flowBuilder
131: + "'; externally assigned flow attributes are '"
132: + flowAttributes + "'");
133: }
134: try {
135: flowBuilder.init(flowId, flowAttributes);
136: directAssembly();
137: return flowBuilder.getFlow();
138: } finally {
139: flowBuilder.dispose();
140: }
141: }
142:
143: /**
144: * Build all parts of the flow by directing flow assembly by the flow
145: * builder.
146: * @throws FlowBuilderException when flow assembly fails
147: */
148: protected void directAssembly() throws FlowBuilderException {
149: flowBuilder.buildVariables();
150: flowBuilder.buildInputMapper();
151: flowBuilder.buildStartActions();
152: flowBuilder.buildInlineFlows();
153: flowBuilder.buildStates();
154: flowBuilder.buildGlobalTransitions();
155: flowBuilder.buildEndActions();
156: flowBuilder.buildOutputMapper();
157: flowBuilder.buildExceptionHandlers();
158: }
159: }
|