/*
* Copyright 2004-2008 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.util.Assert;
import org.springframework.webflow.engine.Flow;
/**
* A director for assembling flows, delegating to a {@link FlowBuilder} to construct a flow. This class encapsulates the
* algorithm for using a FlowBuilder to assemble a Flow properly. It acts as the director in the classic GoF builder
* pattern.
* <p>
* Flow assemblers may be used in a standalone, programmatic fashion as follows:
*
* <pre>
* FlowBuilder builder = ...;
* FlowBuilder context = ...;
* Flow flow = new FlowAssembler(builder, builderContext).assembleFlow();
* </pre>
*
* @see org.springframework.webflow.engine.builder.FlowBuilder
*
* @author Keith Donald
* @author Erwin Vervaet
*/
public class FlowAssembler {
/**
* The flow builder strategy used to construct the flow from its component parts.
*/
private FlowBuilder flowBuilder;
/**
* Context needed to initialize the builder so it can perform a build operation.
*/
private FlowBuilderContext flowBuilderContext;
/**
* Create a new flow assembler that will direct Flow assembly using the specified builder strategy.
* @param flowBuilder the builder the factory will use to build flows
* @param flowBuilderContext context to influence the build process
*/
public FlowAssembler(FlowBuilder flowBuilder, FlowBuilderContext flowBuilderContext) {
Assert.notNull(flowBuilder, "A flow builder is required for flow assembly");
Assert.notNull(flowBuilderContext, "A flow builder context is required for flow assembly");
this.flowBuilder = flowBuilder;
this.flowBuilderContext = flowBuilderContext;
}
/**
* Returns the flow builder strategy used to construct the flow from its component parts.
*/
public FlowBuilder getFlowBuilder() {
return flowBuilder;
}
/**
* Returns the flow builder context.
* @return flow builder context
*/
public FlowBuilderContext getFlowBuilderContext() {
return flowBuilderContext;
}
/**
* Assembles the flow, directing the construction process by delegating to the configured FlowBuilder. Every call to
* this method will assemble the Flow instance.
* <p>
* This will drive the flow construction process as described in the {@link FlowBuilder} JavaDoc, starting with
* builder initialization using {@link FlowBuilder#init(FlowBuilderContext)} and finishing by cleaning up the
* builder with a call to {@link FlowBuilder#dispose()}.
* @return the constructed flow
* @throws FlowBuilderException when flow assembly fails
*/
public Flow assembleFlow() throws FlowBuilderException {
try {
flowBuilder.init(flowBuilderContext);
directAssembly();
return flowBuilder.getFlow();
} finally {
flowBuilder.dispose();
}
}
/**
* Build all parts of the flow by directing flow assembly by the flow builder.
* @throws FlowBuilderException when flow assembly fails
*/
protected void directAssembly() throws FlowBuilderException {
flowBuilder.buildVariables();
flowBuilder.buildInputMapper();
flowBuilder.buildStartActions();
flowBuilder.buildStates();
flowBuilder.buildGlobalTransitions();
flowBuilder.buildEndActions();
flowBuilder.buildOutputMapper();
flowBuilder.buildExceptionHandlers();
}
}