001: /*
002: * Created on 13 Sep 2007
003: */
004: package uk.org.ponder.rsf.swf.support;
005:
006: import org.springframework.webflow.context.ExternalContext;
007: import org.springframework.webflow.context.ExternalContextHolder;
008: import org.springframework.webflow.core.FlowException;
009: import org.springframework.webflow.execution.FlowExecution;
010: import org.springframework.webflow.execution.ViewSelection;
011: import org.springframework.webflow.execution.repository.FlowExecutionKey;
012: import org.springframework.webflow.execution.repository.FlowExecutionLock;
013: import org.springframework.webflow.execution.repository.FlowExecutionRepository;
014: import org.springframework.webflow.executor.FlowExecutorImpl;
015: import org.springframework.webflow.executor.ResponseInstruction;
016:
017: /**
018: * A mirror of the builtin SWF "FlowExecutorImpl" construct, modified marginally
019: * to supply a "work payload" represented by a Runnable to be executed before
020: * the flow is closed. The implementation "operate" is a composite of the
021: * "resume" and "refresh" functions of the original Executor, since the event
022: * identity or even whether there is an event will not be known until the
023: * supplied "StringGetter" has executed within the context of the opened flow.
024: * </p>
025: * Within RSF, this Executor takes place as an "AlterationWrapper".
026: *
027: * @author Antranig Basman (antranig@caret.cam.ac.uk)
028: *
029: */
030:
031: public class SWFFlowExecutorImpl {
032:
033: private FlowExecutionRepository executionRepository;
034:
035: public void setFlowExecutorImpl(FlowExecutorImpl flowExecutorImpl) {
036: executionRepository = flowExecutorImpl.getExecutionRepository();
037: }
038:
039: public void operate(String flowExecutionKey,
040: SWFExecutionPayload payload, final ExternalContext context)
041: throws FlowException {
042: // expose external context as a thread-bound service
043: ExternalContextHolder.setExternalContext(context);
044: try {
045: final FlowExecutionKey key = executionRepository
046: .parseFlowExecutionKey(flowExecutionKey);
047: FlowExecutionLock lock = executionRepository.getLock(key);
048: // make sure we're the only one manipulating the flow execution
049: lock.lock();
050: try {
051: final FlowExecution flowExecution = executionRepository
052: .getFlowExecution(key);
053: payload.executeInRequest(flowExecution,
054: new ResponseInstructionGetter() {
055: public ResponseInstruction getResponse(
056: String eventId) {
057: if (eventId != null) {
058: ViewSelection selectedView = flowExecution
059: .signalEvent(eventId,
060: context);
061:
062: if (flowExecution.isActive()) {
063: // execution still active => store it in the repository
064: FlowExecutionKey innerkey = executionRepository
065: .getNextKey(
066: flowExecution,
067: key);
068: executionRepository
069: .putFlowExecution(
070: innerkey,
071: flowExecution);
072: return new ResponseInstruction(
073: innerkey.toString(),
074: flowExecution,
075: selectedView);
076: } else {
077: // execution ended => remove it from the repository
078: executionRepository
079: .removeFlowExecution(key);
080: return new ResponseInstruction(
081: flowExecution,
082: selectedView);
083: }
084: } else {
085: ViewSelection selectedView = flowExecution
086: .refresh(context);
087: // don't generate a new key for a refresh, just update
088: // the flow execution with it's existing key
089: executionRepository
090: .putFlowExecution(key,
091: flowExecution);
092: return new ResponseInstruction(key
093: .toString(), flowExecution,
094: selectedView);
095: }
096: }
097: });
098:
099: } finally {
100: lock.unlock();
101: }
102: } finally {
103: ExternalContextHolder.setExternalContext(null);
104: }
105: }
106:
107: }
|