/*
* Created on 13 Sep 2007
*/
package uk.org.ponder.rsf.swf.support;
import org.springframework.webflow.context.ExternalContext;
import org.springframework.webflow.context.ExternalContextHolder;
import org.springframework.webflow.core.FlowException;
import org.springframework.webflow.execution.FlowExecution;
import org.springframework.webflow.execution.ViewSelection;
import org.springframework.webflow.execution.repository.FlowExecutionKey;
import org.springframework.webflow.execution.repository.FlowExecutionLock;
import org.springframework.webflow.execution.repository.FlowExecutionRepository;
import org.springframework.webflow.executor.FlowExecutorImpl;
import org.springframework.webflow.executor.ResponseInstruction;
/**
* A mirror of the builtin SWF "FlowExecutorImpl" construct, modified marginally
* to supply a "work payload" represented by a Runnable to be executed before
* the flow is closed. The implementation "operate" is a composite of the
* "resume" and "refresh" functions of the original Executor, since the event
* identity or even whether there is an event will not be known until the
* supplied "StringGetter" has executed within the context of the opened flow.
* </p>
* Within RSF, this Executor takes place as an "AlterationWrapper".
*
* @author Antranig Basman (antranig@caret.cam.ac.uk)
*
*/
public class SWFFlowExecutorImpl {
private FlowExecutionRepository executionRepository;
public void setFlowExecutorImpl(FlowExecutorImpl flowExecutorImpl) {
executionRepository = flowExecutorImpl.getExecutionRepository();
}
public void operate(String flowExecutionKey, SWFExecutionPayload payload,
final ExternalContext context) throws FlowException {
// expose external context as a thread-bound service
ExternalContextHolder.setExternalContext(context);
try {
final FlowExecutionKey key = executionRepository
.parseFlowExecutionKey(flowExecutionKey);
FlowExecutionLock lock = executionRepository.getLock(key);
// make sure we're the only one manipulating the flow execution
lock.lock();
try {
final FlowExecution flowExecution = executionRepository
.getFlowExecution(key);
payload.executeInRequest(flowExecution,
new ResponseInstructionGetter() {
public ResponseInstruction getResponse(String eventId) {
if (eventId != null) {
ViewSelection selectedView = flowExecution.signalEvent(
eventId, context);
if (flowExecution.isActive()) {
// execution still active => store it in the repository
FlowExecutionKey innerkey = executionRepository.getNextKey(
flowExecution, key);
executionRepository.putFlowExecution(innerkey,
flowExecution);
return new ResponseInstruction(innerkey.toString(),
flowExecution, selectedView);
}
else {
// execution ended => remove it from the repository
executionRepository.removeFlowExecution(key);
return new ResponseInstruction(flowExecution, selectedView);
}
}
else {
ViewSelection selectedView = flowExecution.refresh(context);
// don't generate a new key for a refresh, just update
// the flow execution with it's existing key
executionRepository.putFlowExecution(key, flowExecution);
return new ResponseInstruction(key.toString(), flowExecution,
selectedView);
}
}
});
}
finally {
lock.unlock();
}
}
finally {
ExternalContextHolder.setExternalContext(null);
}
}
}
|