001: /*
002: * Created on 16 Jul 2007
003: */
004: package uk.org.ponder.rsf.swf.support;
005:
006: import java.util.Collection;
007: import java.util.Iterator;
008: import java.util.Map;
009:
010: import org.springframework.webflow.context.ExternalContext;
011: import org.springframework.webflow.execution.FlowExecution;
012: import org.springframework.webflow.execution.support.ApplicationView;
013: import org.springframework.webflow.execution.support.ExternalRedirect;
014: import org.springframework.webflow.execution.support.FlowDefinitionRedirect;
015: import org.springframework.webflow.executor.FlowExecutor;
016: import org.springframework.webflow.executor.ResponseInstruction;
017:
018: import uk.org.ponder.beanutil.PathUtil;
019: import uk.org.ponder.beanutil.support.ConcreteWBL;
020: import uk.org.ponder.hashutil.IDGenerator;
021: import uk.org.ponder.rsf.flow.ARIResult;
022: import uk.org.ponder.rsf.preservation.GenericBeanCopyPreservationStrategy;
023: import uk.org.ponder.rsf.request.EarlyRequestParser;
024: import uk.org.ponder.rsf.swf.util.RSFSWFUtil;
025: import uk.org.ponder.rsf.swf.viewparams.SWFEventViewParams;
026: import uk.org.ponder.rsf.swf.viewparams.SWFLaunchViewParams;
027: import uk.org.ponder.rsf.swf.viewparams.SWFViewParams;
028: import uk.org.ponder.rsf.viewstate.AnyViewParameters;
029: import uk.org.ponder.rsf.viewstate.NoViewParameters;
030: import uk.org.ponder.rsf.viewstate.RawURLState;
031: import uk.org.ponder.rsf.viewstate.RawViewParameters;
032: import uk.org.ponder.rsf.viewstate.RedirectViewParameters;
033: import uk.org.ponder.rsf.viewstate.ViewParameters;
034: import uk.org.ponder.rsf.viewstate.ViewParamsCodec;
035: import uk.org.ponder.rsf.viewstate.ViewParamsInterceptor;
036: import uk.org.ponder.rsf.viewstate.ViewParamsRegistry;
037: import uk.org.ponder.stringutil.StringList;
038:
039: /**
040: * The core adapter between RSF and SWF semantics. Will be invoked by a
041: * {@link ViewParamsInterceptor} on a render cycle, or by one of SWFEventBean
042: * and SWFLaunchBean on an action cycle. Note that on the render cycle execution
043: * is EARLY, before the alteration cycle - whereas on the action cycle it is
044: * LATE, during "execute method binding".
045: *
046: * @author Antranig Basman (antranig@caret.cam.ac.uk)
047: */
048:
049: public class SWFExecutor {
050: private ExternalContext externalContext;
051:
052: private FlowExecutor executor;
053:
054: private AnyViewParameters outgoing;
055:
056: private Map inchuck;
057:
058: private SWFViewParams incoming;
059:
060: private ViewParamsRegistry viewParamsRegistry;
061:
062: private ViewParamsCodec viewParamsCodec;
063:
064: private IDGenerator IDGenerator;
065:
066: private GenericBeanCopyPreservationStrategy preservationStrategy;
067:
068: private String requestType;
069:
070: private SWFFlowExecutorImpl payloadExecutor;
071:
072: public void setIDGenerator(IDGenerator generator) {
073: IDGenerator = generator;
074: }
075:
076: public void setPreservationStrategy(
077: GenericBeanCopyPreservationStrategy preservationStrategy) {
078: this .preservationStrategy = preservationStrategy;
079: }
080:
081: public Map getInChuckMap() {
082: return inchuck;
083: }
084:
085: public void setExternalContext(ExternalContext externalContext) {
086: this .externalContext = externalContext;
087: }
088:
089: public void setFlowExecutor(FlowExecutor executor) {
090: this .executor = executor;
091: }
092:
093: public void setViewParamsRegistry(
094: ViewParamsRegistry viewParamsRegistry) {
095: this .viewParamsRegistry = viewParamsRegistry;
096: }
097:
098: public void setViewParamsCodec(ViewParamsCodec viewParamsCodec) {
099: this .viewParamsCodec = viewParamsCodec;
100: }
101:
102: public void setRequestType(String requestType) {
103: this .requestType = requestType;
104: }
105:
106: public void setSWFFlowExecutorImpl(
107: SWFFlowExecutorImpl payloadExecutor) {
108: this .payloadExecutor = payloadExecutor;
109: }
110:
111: public SWFFlowExecutorImpl getSWFFlowExecutorImpl() {
112: return payloadExecutor;
113: }
114:
115: public void execute(final SWFViewParams incoming,
116: SWFExecutionPayload payload) {
117: ResponseInstruction ri = null;
118: if (incoming.flowId != null) {
119: ri = executor.launch(incoming.flowId, externalContext);
120: interpretResponseInstruction(ri, incoming);
121: } else {
122: if (payload == null) {
123: payload = new SWFExecutionPayload() {
124: public void executeInRequest(
125: FlowExecution execution,
126: ResponseInstructionGetter rig) {
127: ResponseInstruction ri = rig
128: .getResponse(incoming.event);
129: interpretResponseInstruction(ri, incoming);
130: }
131: };
132: }
133:
134: payloadExecutor.operate(incoming.flowExecutionKey, payload,
135: externalContext);
136: }
137:
138: }
139:
140: private StringList keysToNames(Collection keySet) {
141: StringList togo = new StringList();
142: for (Iterator keyit = keySet.iterator(); keyit.hasNext();) {
143: String key = (String) keyit.next();
144: String escaped = PathUtil.composePath("", key);
145: togo.add(escaped);
146: }
147: return togo;
148: }
149:
150: // Courtesy to allow portability of JSF-style flows which name views by
151: // schemes like
152: // /viewname.jsp
153: private String stripViewName(String viewName) {
154: int slashpos = viewName.lastIndexOf('/');
155: if (slashpos != -1) {
156: viewName = viewName.substring(slashpos + 1);
157: }
158: int dotpos = viewName.indexOf('.');
159: if (dotpos != -1) {
160: viewName = viewName.substring(0, dotpos);
161: }
162: return viewName;
163: }
164:
165: public void interpretResponseInstruction(ResponseInstruction ri,
166: SWFViewParams incoming) {
167: boolean redirect = true;
168: AnyViewParameters togo = null;
169: this .incoming = incoming;
170: if (ri.isApplicationView()) {
171: if (incoming.flowExecutionKey == null) {
172: throw new IllegalStateException(
173: "Invalid flow transition - "
174: + "RSF does not support operation of flows without 'alwaysRedirectOnPause' = true - "
175: + "please correct the flow executor definition");
176: }
177: ApplicationView av = (ApplicationView) ri
178: .getViewSelection();
179: String viewid = stripViewName(av.getViewName());
180: ViewParameters exemplar = viewParamsRegistry
181: .getViewParamsExemplar(viewid);
182: boolean isget = requestType
183: .equals(EarlyRequestParser.RENDER_REQUEST);
184: if (isget && incoming.params != null) {
185: viewParamsCodec.parseViewParams(exemplar,
186: new RawURLState(incoming.params, null), null);
187: }
188: exemplar.errortoken = incoming.errortoken;
189: exemplar.errorredirect = incoming.errorredirect;
190: exemplar.debugrender = incoming.debugrender;
191:
192: redirect = false;
193: // Note that the actual code constructing the model is implemented as
194: // public AttributeMap getModel() {
195: // return
196: // getConversationScope().union(getFlowScope()).union(getFlashScope()).union(getRequestScope());
197: // within RequestControlContextImpl.
198: inchuck = av.getModel();
199: if (!ri.getFlowExecutionContext().isActive()
200: && !inchuck.isEmpty()) {
201: String tokenid = IDGenerator.generateID();
202: preservationStrategy.preserveImmediate(new ConcreteWBL(
203: inchuck), keysToNames(inchuck.keySet()),
204: tokenid);
205: exemplar.endflow = "1";
206: exemplar.flowtoken = tokenid;
207: }
208: togo = exemplar;
209: } else if (ri.isFlowDefinitionRedirect()) {
210: FlowDefinitionRedirect fdr = (FlowDefinitionRedirect) ri
211: .getViewSelection();
212: togo = new SWFLaunchViewParams(fdr.getFlowDefinitionId(),
213: fdr.getExecutionInput());
214: } else if (ri.isFlowExecutionRedirect()) {
215: // Especially on a POST form, incoming is full of all sorts of
216: // undesirable stuff. But we need to be sure we are properly passing
217: // parameters which ARE required.
218: // SWFViewParams reparams = (SWFViewParams) incoming.copy();
219: SWFViewParams reparams = new SWFEventViewParams(null);
220: if (ri.getFlowExecutionContext().isActive()) {
221: reparams.flowExecutionKey = ri.getFlowExecutionKey();
222: inchuck = RSFSWFUtil.getModelForcibly(ri
223: .getFlowExecutionContext());
224: }
225: togo = reparams;
226: } else if (ri.isExternalRedirect()) {
227: ExternalRedirect er = (ExternalRedirect) ri
228: .getViewSelection();
229: togo = new RawViewParameters(er.getUrl());
230: } else if (ri.isNull()) {
231: togo = new NoViewParameters();
232: }
233: outgoing = redirect ? new RedirectViewParameters(togo) : togo;
234: }
235:
236: public AnyViewParameters getOutgoingParameters() {
237: return outgoing;
238: }
239:
240: public SWFViewParams getIncomingParameters() {
241: return incoming;
242: }
243:
244: public ARIResult getARIResult() {
245: ARIResult togo = new ARIResult();
246: AnyViewParameters resultingView = outgoing;
247: if (outgoing instanceof RedirectViewParameters) {
248: resultingView = ((RedirectViewParameters) outgoing).target;
249: }
250: togo.resultingView = resultingView;
251: togo.propagateBeans = ARIResult.FLOW_END;
252: return togo;
253: }
254:
255: }
|