1 /* Copyright 2006-2007 Graeme Rocher
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
15 package org
.codehaus
.groovy
.grails
.webflow
.executor
;
17 import org
.springframework
.webflow
.executor
.FlowExecutorImpl
;
18 import org
.springframework
.webflow
.executor
.ResponseInstruction
;
19 import org
.springframework
.webflow
.definition
.registry
.FlowDefinitionLocator
;
20 import org
.springframework
.webflow
.definition
.FlowDefinition
;
21 import org
.springframework
.webflow
.execution
.FlowExecutionFactory
;
22 import org
.springframework
.webflow
.execution
.FlowExecution
;
23 import org
.springframework
.webflow
.execution
.ViewSelection
;
24 import org
.springframework
.webflow
.execution
.FlowExecutionContextHolder
;
25 import org
.springframework
.webflow
.execution
.repository
.FlowExecutionRepository
;
26 import org
.springframework
.webflow
.execution
.repository
.FlowExecutionKey
;
27 import org
.springframework
.webflow
.execution
.repository
.FlowExecutionLock
;
28 import org
.springframework
.webflow
.context
.ExternalContext
;
29 import org
.springframework
.webflow
.context
.ExternalContextHolder
;
30 import org
.springframework
.webflow
.core
.FlowException
;
31 import org
.apache
.commons
.logging
.Log
;
32 import org
.apache
.commons
.logging
.LogFactory
;
35 * Class description here.
37 * @author Graeme Rocher
40 * Created: Jul 20, 2007
43 public class GrailsFlowExecutor
extends FlowExecutorImpl
{
45 private static final Log logger
= LogFactory
.getLog(FlowExecutorImpl
.class);
47 * Create a new flow executor.
49 * @param definitionLocator the locator for accessing flow definitions to
51 * @param executionFactory the factory for creating executions of flow
53 * @param executionRepository the repository for persisting paused flow
56 public GrailsFlowExecutor(FlowDefinitionLocator definitionLocator
, FlowExecutionFactory executionFactory
, FlowExecutionRepository executionRepository
) {
57 super(definitionLocator
, executionFactory
, executionRepository
);
60 public ResponseInstruction
launch(String flowDefinitionId
, ExternalContext context
) throws FlowException
{
61 if (logger
.isDebugEnabled()) {
62 logger
.debug("Launching flow execution for flow definition '" + flowDefinitionId
+ "'");
64 // expose external context as a thread-bound service
65 ExternalContextHolder
.setExternalContext(context
);
67 FlowDefinition flowDefinition
= getDefinitionLocator().getFlowDefinition(flowDefinitionId
);
68 FlowExecution flowExecution
= getExecutionFactory().createFlowExecution(flowDefinition
);
69 FlowExecutionContextHolder
.setFlowExecutionContext(flowExecution
);
70 ViewSelection selectedView
= flowExecution
.start(createInput(context
), context
);
71 if (flowExecution
.isActive()) {
72 // execution still active => store it in the repository
73 final FlowExecutionRepository executionRepository
= getExecutionRepository();
74 FlowExecutionKey key
= executionRepository
.generateKey(flowExecution
);
75 FlowExecutionLock lock
= executionRepository
.getLock(key
);
78 executionRepository
.putFlowExecution(key
, flowExecution
);
83 return new ResponseInstruction(key
.toString(), flowExecution
, selectedView
);
86 // execution already ended => just render the selected view
87 return new ResponseInstruction(flowExecution
, selectedView
);
91 cleanUpAfterFlowExecution();
95 private void cleanUpAfterFlowExecution() {
96 FlowExecutionContextHolder
.setFlowExecutionContext(null);
97 ExternalContextHolder
.setExternalContext(null);
100 public ResponseInstruction
resume(String flowExecutionKey
, String eventId
, ExternalContext context
) throws FlowException
{
101 if (logger
.isDebugEnabled()) {
102 logger
.debug("Resuming flow execution with key '" + flowExecutionKey
+
103 "' on user event '" + eventId
+ "'");
105 // expose external context as a thread-bound service
106 ExternalContextHolder
.setExternalContext(context
);
108 final FlowExecutionRepository executionRepository
= getExecutionRepository();
109 FlowExecutionKey key
= executionRepository
.parseFlowExecutionKey(flowExecutionKey
);
110 FlowExecutionLock lock
= executionRepository
.getLock(key
);
111 // make sure we're the only one manipulating the flow execution
114 FlowExecution flowExecution
= executionRepository
.getFlowExecution(key
);
115 FlowExecutionContextHolder
.setFlowExecutionContext(flowExecution
);
116 ViewSelection selectedView
= flowExecution
.signalEvent(eventId
, context
);
117 if (flowExecution
.isActive()) {
118 // execution still active => store it in the repository
119 key
= executionRepository
.getNextKey(flowExecution
, key
);
120 executionRepository
.putFlowExecution(key
, flowExecution
);
121 return new ResponseInstruction(key
.toString(), flowExecution
, selectedView
);
124 // execution ended => remove it from the repository
125 executionRepository
.removeFlowExecution(key
);
126 return new ResponseInstruction(flowExecution
, selectedView
);
134 cleanUpAfterFlowExecution();
139 public ResponseInstruction
refresh(String flowExecutionKey
, ExternalContext context
) throws FlowException
{
140 if (logger
.isDebugEnabled()) {
141 logger
.debug("Refreshing flow execution with key '" + flowExecutionKey
+ "'");
143 // expose external context as a thread-bound service
144 ExternalContextHolder
.setExternalContext(context
);
146 final FlowExecutionRepository executionRepository
= getExecutionRepository();
147 FlowExecutionKey key
= executionRepository
.parseFlowExecutionKey(flowExecutionKey
);
148 FlowExecutionLock lock
= executionRepository
.getLock(key
);
149 // make sure we're the only one manipulating the flow execution
152 FlowExecution flowExecution
= executionRepository
.getFlowExecution(key
);
153 FlowExecutionContextHolder
.setFlowExecutionContext(flowExecution
);
154 ViewSelection selectedView
= flowExecution
.refresh(context
);
155 // don't generate a new key for a refresh, just update
156 // the flow execution with it's existing key
157 executionRepository
.putFlowExecution(key
, flowExecution
);
158 return new ResponseInstruction(key
.toString(), flowExecution
, selectedView
);
165 cleanUpAfterFlowExecution();