KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > webflow > config > FlowExecutorFactoryBean


1 /*
2  * Copyright 2002-2006 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.springframework.webflow.config;
17
18 import java.util.Map JavaDoc;
19
20 import org.springframework.beans.factory.FactoryBean;
21 import org.springframework.beans.factory.InitializingBean;
22 import org.springframework.util.Assert;
23 import org.springframework.webflow.conversation.ConversationManager;
24 import org.springframework.webflow.conversation.impl.SessionBindingConversationManager;
25 import org.springframework.webflow.core.collection.AttributeMap;
26 import org.springframework.webflow.core.collection.LocalAttributeMap;
27 import org.springframework.webflow.core.collection.MutableAttributeMap;
28 import org.springframework.webflow.definition.registry.FlowDefinitionLocator;
29 import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
30 import org.springframework.webflow.engine.impl.FlowExecutionImplFactory;
31 import org.springframework.webflow.engine.impl.FlowExecutionImplStateRestorer;
32 import org.springframework.webflow.execution.FlowExecutionFactory;
33 import org.springframework.webflow.execution.FlowExecutionListener;
34 import org.springframework.webflow.execution.factory.FlowExecutionListenerLoader;
35 import org.springframework.webflow.execution.factory.StaticFlowExecutionListenerLoader;
36 import org.springframework.webflow.execution.repository.FlowExecutionRepository;
37 import org.springframework.webflow.execution.repository.continuation.ClientContinuationFlowExecutionRepository;
38 import org.springframework.webflow.execution.repository.continuation.ContinuationFlowExecutionRepository;
39 import org.springframework.webflow.execution.repository.support.FlowExecutionStateRestorer;
40 import org.springframework.webflow.execution.repository.support.SimpleFlowExecutionRepository;
41 import org.springframework.webflow.executor.FlowExecutor;
42 import org.springframework.webflow.executor.FlowExecutorImpl;
43
44 /**
45  * The default flow executor factory implementation. As a <code>FactoryBean</code>,
46  * this class has been designed for use as a Spring managed bean.
47  * <p>
48  * This factory encapsulates the construction and assembly of a
49  * {@link FlowExecutor}, including the provision of its
50  * {@link FlowExecutionRepository} strategy.
51  * <p>
52  * The {@link #setDefinitionLocator(FlowDefinitionLocator) definition locator}
53  * property is required, all other properties are optional.
54  * <p>
55  * This class has been designed with subclassing in mind. If you want to do advanced
56  * Spring Web Flow customization, e.g. using a custom
57  * {@link org.springframework.webflow.executor.FlowExecutor} implementation,
58  * consider subclassing this class and overriding one or more of the provided
59  * hook methods.
60  *
61  * @author Keith Donald
62  * @author Erwin Vervaet
63  */

64 public class FlowExecutorFactoryBean implements FactoryBean, InitializingBean {
65
66     /**
67      * The locator the executor will use to access flow definitions registered
68      * in a central registry. Required.
69      */

70     private FlowDefinitionLocator definitionLocator;
71
72     /**
73      * Execution attributes to apply.
74      */

75     private MutableAttributeMap executionAttributes;
76     
77     /**
78      * The loader that will determine which listeners to attach to flow definition executions.
79      */

80     private FlowExecutionListenerLoader executionListenerLoader;
81     
82     /**
83      * The conversation manager to be used by the flow execution repository to
84      * store state associated with conversations driven by Spring Web Flow.
85      */

86     private ConversationManager conversationManager = new SessionBindingConversationManager();
87
88     /**
89      * The type of execution repository to configure with executors created by
90      * this factory. Optional. Will fallback to default value if not set.
91      */

92     private RepositoryType repositoryType;
93
94     /**
95      * The flow executor this factory bean creates.
96      */

97     private FlowExecutor flowExecutor;
98
99     /**
100      * Spring Web Flow executor system defaults.
101      */

102     private FlowSystemDefaults defaults = new FlowSystemDefaults();
103     
104     /**
105      * Sets the flow definition locator that will locate flow definitions needed
106      * for execution. Typically also a {@link FlowDefinitionRegistry}. Required.
107      * @param definitionLocator the flow definition locator (registry)
108      */

109     public void setDefinitionLocator(FlowDefinitionLocator definitionLocator) {
110         this.definitionLocator = definitionLocator;
111     }
112
113     /**
114      * Sets the system attributes that apply to flow executions launched by the
115      * executor created by this factory. Execution attributes may affect flow
116      * execution behavior.
117      * <p>
118      * Note: this method simply accepts a generic <code>java.util.Map</code>
119      * to allow for easy configuration by Spring. The map entries should consist
120      * of non-null String keys with object values.
121      * @param executionAttributes the flow execution system attributes
122      */

123     public void setExecutionAttributes(Map JavaDoc executionAttributes) {
124         this.executionAttributes = new LocalAttributeMap(executionAttributes);
125     }
126
127     /**
128      * Convenience setter that sets a single listener that always applies to flow
129      * executions launched by the executor created by this factory.
130      * @param executionListener the flow execution listener
131      */

132     public void setExecutionListener(FlowExecutionListener executionListener) {
133         setExecutionListeners(new FlowExecutionListener[] { executionListener });
134     }
135
136     /**
137      * Convenience setter that sets a list of listeners that always apply to
138      * flow executions launched by the executor created by this factory.
139      * @param executionListeners the flow execution listeners
140      */

141     public void setExecutionListeners(FlowExecutionListener[] executionListeners) {
142         setExecutionListenerLoader(new StaticFlowExecutionListenerLoader(executionListeners));
143     }
144
145     /**
146      * Sets the strategy for loading the listeners that will observe executions
147      * of a flow definition. Allows full control over what listeners should
148      * apply to executions of a flow definition launched by the executor created
149      * by this factory.
150      */

151     public void setExecutionListenerLoader(FlowExecutionListenerLoader executionListenerLoader) {
152         this.executionListenerLoader = executionListenerLoader;
153     }
154
155     /**
156      * Sets the type of flow execution repository that should be configured for
157      * the flow executors created by this factory. This factory encapsulates the
158      * construction of the repository implementation corresponding to the
159      * provided type.
160      * @param repositoryType the flow execution repository type
161      */

162     public void setRepositoryType(RepositoryType repositoryType) {
163         this.repositoryType = repositoryType;
164     }
165
166     /**
167      * Sets the strategy for managing conversations that should be configured
168      * for flow executors created by this factory.
169      * <p>
170      * The conversation manager is used by the flow execution repository
171      * subsystem to begin and end new conversations that store execution state.
172      */

173     public void setConversationManager(ConversationManager conversationManager) {
174         this.conversationManager = conversationManager;
175     }
176     
177     /**
178      * Set system defaults that should be used.
179      * @param defaults the defaults to use.
180      */

181     public void setDefaults(FlowSystemDefaults defaults) {
182         this.defaults = defaults;
183     }
184
185     // implementing InitializingBean
186

187     public void afterPropertiesSet() throws Exception JavaDoc {
188         Assert.notNull(definitionLocator, "The flow definition locator is required");
189         
190         // apply defaults
191
executionAttributes = defaults.applyExecutionAttributes(executionAttributes);
192         repositoryType = defaults.applyIfNecessary(repositoryType);
193         
194         // pass all available parameters to the hook methods so that they
195
// can participate in the construction process
196

197         // a factory for flow executions
198
FlowExecutionFactory executionFactory =
199             createFlowExecutionFactory(executionAttributes, executionListenerLoader);
200         
201         // a strategy to restore deserialized flow executions
202
FlowExecutionStateRestorer executionStateRestorer =
203             createFlowExecutionStateRestorer(definitionLocator, executionAttributes, executionListenerLoader);
204         
205         // a repository to store flow executions
206
FlowExecutionRepository executionRepository =
207             createExecutionRepository(repositoryType, executionStateRestorer, conversationManager);
208         
209         // combine all pieces of the puzzle to get an operational flow executor
210
flowExecutor = createFlowExecutor(definitionLocator, executionFactory, executionRepository);
211     }
212
213     // subclassing hook methods
214

215     /**
216      * Create the flow execution factory to be used by the executor produced by this
217      * factory bean. Configure the execution factory appropriately. Subclasses may
218      * override if they which to use a custom execution factory, e.g. to use a custom
219      * FlowExecution implementation.
220      * @param executionAttributes execution attributes to apply to created executions
221      * @param executionListenerLoader decides which listeners to apply to created executions
222      * @return a new flow execution factory instance
223      */

224     protected FlowExecutionFactory createFlowExecutionFactory(
225             AttributeMap executionAttributes, FlowExecutionListenerLoader executionListenerLoader) {
226         FlowExecutionImplFactory executionFactory = new FlowExecutionImplFactory();
227         executionFactory.setExecutionAttributes(executionAttributes);
228         if (executionListenerLoader != null) {
229             executionFactory.setExecutionListenerLoader(executionListenerLoader);
230         }
231         return executionFactory;
232     }
233     
234     /**
235      * Create the flow execution state restorer to be used by the executor produced by
236      * this factory bean. Configure the state restorer appropriately. Subclasses may
237      * override if they which to use a custom state restorer implementation.
238      * @param definitionLocator the definition locator to use
239      * @param executionAttributes execution attributes to apply to restored executions
240      * @param executionListenerLoader decides which listeners should apply to restored
241      * flow executions
242      * @return a new state restorer instance
243      */

244     protected FlowExecutionStateRestorer createFlowExecutionStateRestorer(
245             FlowDefinitionLocator definitionLocator, AttributeMap executionAttributes,
246             FlowExecutionListenerLoader executionListenerLoader) {
247         FlowExecutionImplStateRestorer executionStateRestorer = new FlowExecutionImplStateRestorer(definitionLocator);
248         executionStateRestorer.setExecutionAttributes(executionAttributes);
249         if (executionListenerLoader != null) {
250             executionStateRestorer.setExecutionListenerLoader(executionListenerLoader);
251         }
252         return executionStateRestorer;
253     }
254
255     /**
256      * Factory method for creating the flow execution repository for saving and
257      * loading executing flows. Subclasses may override to customize the
258      * repository implementation used.
259      * @param repositoryType a hint indicating what type of repository to create
260      * @param executionStateRestorer the execution state restorer strategy to be used by
261      * the repository
262      * @param conversationManager the conversation manager to use
263      * @return a new flow execution repository instance
264      */

265     protected FlowExecutionRepository createExecutionRepository(
266             RepositoryType repositoryType, FlowExecutionStateRestorer executionStateRestorer,
267             ConversationManager conversationManager) {
268         if (repositoryType == RepositoryType.SIMPLE) {
269             return new SimpleFlowExecutionRepository(executionStateRestorer, conversationManager);
270         }
271         else if (repositoryType == RepositoryType.CONTINUATION) {
272             return new ContinuationFlowExecutionRepository(executionStateRestorer, conversationManager);
273         }
274         else if (repositoryType == RepositoryType.CLIENT) {
275             return new ClientContinuationFlowExecutionRepository(executionStateRestorer, conversationManager);
276         }
277         else if (repositoryType == RepositoryType.SINGLEKEY) {
278             SimpleFlowExecutionRepository repository = new SimpleFlowExecutionRepository(executionStateRestorer,
279                     conversationManager);
280             repository.setAlwaysGenerateNewNextKey(false);
281             return repository;
282         }
283         else {
284             throw new IllegalStateException JavaDoc("Cannot create execution repository - unsupported repository type "
285                     + repositoryType);
286         }
287     }
288     
289     /**
290      * Create the flow executor instance created by this factory bean and configure
291      * it appropriately. Subclasses may override if they which to use a custom executor
292      * implementation.
293      * @param definitionLocator the definition locator to use
294      * @param executionFactory the execution factory to use
295      * @param executionRepository the execution repository to use
296      * @return a new flow executor instance
297      */

298     protected FlowExecutor createFlowExecutor(
299             FlowDefinitionLocator definitionLocator, FlowExecutionFactory executionFactory,
300             FlowExecutionRepository executionRepository) {
301         return new FlowExecutorImpl(definitionLocator, executionFactory, executionRepository);
302     }
303
304     // implementing FactoryBean
305

306     public Class JavaDoc getObjectType() {
307         return FlowExecutor.class;
308     }
309
310     public boolean isSingleton() {
311         return true;
312     }
313
314     public Object JavaDoc getObject() throws Exception JavaDoc {
315         return flowExecutor;
316     }
317 }
Popular Tags