KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > webflow > execution > repository > continuation > ContinuationFlowExecutionRepository


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.execution.repository.continuation;
17
18 import java.io.Serializable JavaDoc;
19
20 import org.springframework.util.Assert;
21 import org.springframework.webflow.conversation.Conversation;
22 import org.springframework.webflow.conversation.ConversationManager;
23 import org.springframework.webflow.execution.FlowExecution;
24 import org.springframework.webflow.execution.repository.FlowExecutionKey;
25 import org.springframework.webflow.execution.repository.FlowExecutionRestorationFailureException;
26 import org.springframework.webflow.execution.repository.support.AbstractConversationFlowExecutionRepository;
27 import org.springframework.webflow.execution.repository.support.FlowExecutionStateRestorer;
28 import org.springframework.webflow.util.RandomGuidUidGenerator;
29 import org.springframework.webflow.util.UidGenerator;
30
31 /**
32  * Stores <i>one to many</i> flow execution continuations (snapshots) per
33  * conversation, where each continuation represents a paused, restorable
34  * view-state of a flow execution snapshotted at a point in time.
35  * <p>
36  * The set of active user conversations are managed by a
37  * {@link ConversationManager} implementation, which this repository delegates
38  * to.
39  * <p>
40  * This repository is responsible for:
41  * <ul>
42  * <li>Beginning a new conversation when a new flow execution is made
43  * persistent. Each conversation is assigned a unique conversartion id which
44  * forms one part of the flow execution key.
45  * <li>Associating a flow execution with that conversation by adding a
46  * {@link FlowExecutionContinuation} to a continuation group.<br>
47  * When a flow execution is placed in this repository a new continuation
48  * snapshot is created, assigned an id, and added to the group. Each
49  * continuation logically represents a state of the conversation at a point in
50  * time <i>that can be restored and continued</i>. These continuations can be
51  * restored to support users going back in their browser to continue a
52  * conversation from a previous point.
53  * <li>Ending existing conversations when persistent flow executions end, as
54  * part of a repository removal operation.
55  * </ul>
56  * <p>
57  * This repository implementation also provides support for <i>conversation
58  * invalidation after completion</i>, where once a logical conversation
59  * completes (by one of its FlowExecution's reaching an end state), the entire
60  * conversation (including all continuations) is invalidated. This prevents the
61  * possibility of duplicate submission after completion.
62  * <p>
63  * This repository implementation should be considered when you do have to
64  * support browser navigational button use, e.g. you cannot lock down the
65  * browser and require that all navigational events to be routed explicitly
66  * through Spring Web Flow.
67  *
68  * @author Keith Donald
69  */

70 public class ContinuationFlowExecutionRepository extends AbstractConversationFlowExecutionRepository {
71
72     /**
73      * The conversation attribute that stores the "continuation group".
74      */

75     private static final String JavaDoc CONTINUATION_GROUP_ATTRIBUTE = "continuationGroup";
76
77     /**
78      * The continuation factory that will be used to create new continuations to
79      * be added to active conversations.
80      */

81     private FlowExecutionContinuationFactory continuationFactory = new SerializedFlowExecutionContinuationFactory();
82
83     /**
84      * The uid generation strategy to use.
85      */

86     private UidGenerator continuationIdGenerator = new RandomGuidUidGenerator();
87
88     /**
89      * The maximum number of continuations that can be active per conversation.
90      */

91     private int maxContinuations;
92
93     /**
94      * Create a new continuation based flow execution repository using given state
95      * restorer and conversation manager.
96      * @param executionStateRestorer the state restoration strategy to use
97      * @param conversationManager the conversation manager to use
98      */

99     public ContinuationFlowExecutionRepository(FlowExecutionStateRestorer executionStateRestorer,
100             ConversationManager conversationManager) {
101         super(executionStateRestorer, conversationManager);
102     }
103
104     /**
105      * Returns the continuation factory that encapsulates the construction of
106      * continuations stored in this repository. Defaults to
107      * {@link SerializedFlowExecutionContinuationFactory}.
108      */

109     public FlowExecutionContinuationFactory getContinuationFactory() {
110         return continuationFactory;
111     }
112
113     /**
114      * Sets the continuation factory that encapsulates the construction of
115      * continuations stored in this repository.
116      */

117     public void setContinuationFactory(FlowExecutionContinuationFactory continuationFactory) {
118         Assert.notNull(continuationFactory, "The continuation factory is required");
119         this.continuationFactory = continuationFactory;
120     }
121
122     /**
123      * Returns the uid generation strategy used to generate continuation
124      * identifiers. Defaults to {@link RandomGuidUidGenerator}.
125      */

126     public UidGenerator getContinuationIdGenerator() {
127         return continuationIdGenerator;
128     }
129
130     /**
131      * Sets the uid generation strategy used to generate unique continuation
132      * identifiers for {@link FlowExecutionKey flow execution keys}.
133      */

134     public void setContinuationIdGenerator(UidGenerator continuationIdGenerator) {
135         Assert.notNull(continuationIdGenerator, "The continuation id generator is required");
136         this.continuationIdGenerator = continuationIdGenerator;
137     }
138
139     /**
140      * Returns the maximum number of continuations allowed per conversation in
141      * this repository.
142      */

143     public int getMaxContinuations() {
144         return maxContinuations;
145     }
146
147     /**
148      * Sets the maximum number of continuations allowed per conversation in this
149      * repository. Use -1 for unlimited.
150      */

151     public void setMaxContinuations(int maxContinuations) {
152         this.maxContinuations = maxContinuations;
153     }
154     
155     public FlowExecution getFlowExecution(FlowExecutionKey key) {
156         FlowExecutionContinuation continuation = getContinuation(key);
157         try {
158             FlowExecution execution = continuation.unmarshal();
159             // flow execution was deserialized, so restore transient state
160
return getExecutionStateRestorer().restoreState(execution, getConversationScope(key));
161         }
162         catch (ContinuationUnmarshalException e) {
163             throw new FlowExecutionRestorationFailureException(key, e);
164         }
165     }
166
167     public void putFlowExecution(FlowExecutionKey key, FlowExecution flowExecution) {
168         FlowExecutionContinuationGroup continuationGroup = getContinuationGroup(key);
169         FlowExecutionContinuation continuation = continuationFactory.createContinuation(flowExecution);
170         continuationGroup.add(getContinuationId(key), continuation);
171         putConversationScope(key, flowExecution.getConversationScope());
172     }
173
174     protected void onBegin(Conversation conversation) {
175         // setup a new continuation group for the conversation
176
FlowExecutionContinuationGroup continuationGroup = new FlowExecutionContinuationGroup(maxContinuations);
177         conversation.putAttribute(CONTINUATION_GROUP_ATTRIBUTE, continuationGroup);
178     }
179
180     protected Serializable JavaDoc generateContinuationId(FlowExecution flowExecution) {
181         return continuationIdGenerator.generateUid();
182     }
183
184     protected Serializable JavaDoc parseContinuationId(String JavaDoc encodedId) {
185         return continuationIdGenerator.parseUid(encodedId);
186     }
187
188     /**
189      * Returns the continuation group associated with the governing
190      * conversation.
191      * @param key the flow execution key
192      * @return the continuation group
193      */

194     FlowExecutionContinuationGroup getContinuationGroup(FlowExecutionKey key) {
195         FlowExecutionContinuationGroup group =
196             (FlowExecutionContinuationGroup)getConversation(key).getAttribute(CONTINUATION_GROUP_ATTRIBUTE);
197         return group;
198     }
199
200     /**
201      * Returns the continuation in the group with the specified key.
202      * @param key the flow execution key
203      * @return the continuation.
204      */

205     protected FlowExecutionContinuation getContinuation(FlowExecutionKey key)
206             throws FlowExecutionRestorationFailureException {
207         try {
208             return getContinuationGroup(key).get(getContinuationId(key));
209         }
210         catch (ContinuationNotFoundException e) {
211             throw new FlowExecutionRestorationFailureException(key, e);
212         }
213     }
214 }
Popular Tags