diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowExecutionHolderUtils.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowExecutionHolderUtils.java index 72ce5945..33ed8bcf 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowExecutionHolderUtils.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowExecutionHolderUtils.java @@ -41,23 +41,6 @@ public class FlowExecutionHolderUtils { return (FlowExecutionHolder) context.getExternalContext().getRequestMap().get(getFlowExecutionHolderKey()); } - /** - * Returns the current flow execution holder for the given faces context. - * @param context faces context - * @return the flow execution holder or null if none set - * @throws EvaluationException if no flow execution was bound - */ - public static FlowExecution getRequiredCurrentFlowExecution(FacesContext context) throws EvaluationException { - FlowExecutionHolder holder = getFlowExecutionHolder(context); - if (holder != null) { - return holder.getFlowExecution(); - } - else { - throw new EvaluationException( - "FlowExecution is not bound to current thread context - has the flow ended or expired?"); - } - } - /** * Sets the current flow execution holder for the given faces context. * @param holder the flow execution holder @@ -75,6 +58,23 @@ public class FlowExecutionHolderUtils { public static boolean isFlowExecutionRestored(FacesContext context) { return getFlowExecutionHolder(context) != null; } + + /** + * Returns the current flow execution holder for the given faces context. + * @param context faces context + * @return the flow execution holder or null if none set + * @throws EvaluationException if no flow execution was bound + */ + public static FlowExecution getRequiredCurrentFlowExecution(FacesContext context) throws EvaluationException { + FlowExecutionHolder holder = getFlowExecutionHolder(context); + if (holder != null) { + return holder.getFlowExecution(); + } + else { + throw new EvaluationException( + "FlowExecution is not bound to current thread context - has the flow ended or expired?"); + } + } private static String getFlowExecutionHolderKey() { return FlowExecutionHolder.class.getName(); diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowPhaseListener.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowPhaseListener.java index ee817682..5c3fbaf8 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowPhaseListener.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowPhaseListener.java @@ -73,6 +73,12 @@ import org.springframework.webflow.executor.support.ResponseInstructionHandler; */ public class FlowPhaseListener implements PhaseListener { + /** + * The name of the attribute the flow execution key will be tracked under in the JSF View Root for managing the + * current flow execution key. + */ + private static final String FLOW_EXECUTION_KEY_VIEW_ROOT_ATTRIBUTE = "_flowExecutionKey"; + /** * Logger, usable by subclasses. */ @@ -163,7 +169,8 @@ public class FlowPhaseListener implements PhaseListener { if (event.getPhaseId() == PhaseId.RESTORE_VIEW) { ExternalContextHolder.setExternalContext(new JsfExternalContext(event.getFacesContext())); restoreFlowExecution(event.getFacesContext()); - } else if (event.getPhaseId() == PhaseId.RENDER_RESPONSE) { + } + else if (event.getPhaseId() == PhaseId.RENDER_RESPONSE) { try { if (FlowExecutionHolderUtils.isFlowExecutionRestored(event.getFacesContext())) { FlowExecutionHolder holder = FlowExecutionHolderUtils.getFlowExecutionHolder(event @@ -199,9 +206,10 @@ public class FlowPhaseListener implements PhaseListener { } else { // restore the key from an attribute in the root of the component tree - flowExecutionKey = repository.parseFlowExecutionKey((String)facesContext.getViewRoot().getAttributes().get("_flowExecutionKey")); + flowExecutionKey = repository.parseFlowExecutionKey((String) facesContext.getViewRoot().getAttributes() + .get(FLOW_EXECUTION_KEY_VIEW_ROOT_ATTRIBUTE)); // remove it (it should always be placed back before response rendering) - facesContext.getViewRoot().getAttributes().remove("_flowExecutionKey"); + facesContext.getViewRoot().getAttributes().remove(FLOW_EXECUTION_KEY_VIEW_ROOT_ATTRIBUTE); } FlowExecutionLock lock = repository.getLock(flowExecutionKey); lock.lock(); @@ -213,8 +221,7 @@ public class FlowPhaseListener implements PhaseListener { lock), facesContext); } else if (argumentHandler.isFlowIdPresent(context)) { - // launch a new flow execution (this could happen as part of a flow - // redirect) + // launch a new flow execution (this could happen as part of a flow redirect) String flowId = argumentHandler.extractFlowId(context); FlowDefinition flowDefinition = getLocator(context).getFlowDefinition(flowId); FlowExecution flowExecution = getFactory(context).createFlowExecution(flowDefinition); @@ -245,6 +252,11 @@ public class FlowPhaseListener implements PhaseListener { } } + /** + * Prepare the appropriate JSF response (e.g. rendering a view, sending a redirect, etc). + * @param context the context + * @param holder the holder + */ protected void prepareResponse(final JsfExternalContext context, final FlowExecutionHolder holder) { generateKey(context, holder); ViewSelection selectedView = holder.getViewSelection(); @@ -284,20 +296,28 @@ public class FlowPhaseListener implements PhaseListener { }.handleQuietly(new ResponseInstruction(holder.getFlowExecution(), selectedView)); } + /** + * Prepare the JSF view for rendering. + * @param facesContext the faces context + * @param holder the holder of the current flow execution + */ protected void prepareApplicationView(FacesContext facesContext, FlowExecutionHolder holder) { ApplicationView forward = (ApplicationView) holder.getViewSelection(); if (forward != null) { + // expose the view's "model map" in the request map putInto(facesContext.getExternalContext().getRequestMap(), forward.getModel()); + // update the root component if necessary updateViewRoot(facesContext, viewIdMapper.mapViewId(forward.getViewName())); } - Map requestMap = facesContext.getExternalContext().getRequestMap(); String flowExecutionKey = holder.getFlowExecution().isActive() ? holder.getFlowExecutionKey().toString() : null; if (flowExecutionKey != null) { // expose to view root for preservation in the component tree if (viewRootAttributeMapPresent(facesContext)) { - facesContext.getViewRoot().getAttributes().put("_flowExecutionKey", flowExecutionKey); + facesContext.getViewRoot().getAttributes() + .put(FLOW_EXECUTION_KEY_VIEW_ROOT_ATTRIBUTE, flowExecutionKey); } } + Map requestMap = facesContext.getExternalContext().getRequestMap(); argumentHandler.exposeFlowExecutionContext(flowExecutionKey, holder.getFlowExecution(), requestMap); } @@ -326,40 +346,42 @@ public class FlowPhaseListener implements PhaseListener { } } } - + // private helpers private JsfExternalContext getCurrentContext() { return (JsfExternalContext) ExternalContextHolder.getExternalContext(); } - + /** - * Returns true if the root of the component tree contains the flow execution key attribute, used - * to restore the flow execution on subsequent reqests. + * Returns true if the root of the component tree contains the flow execution key attribute, used to restore the + * flow execution on subsequent reqests. * @param facesContext the key * @return true if yes, false otherwise */ private boolean isFlowExecutionKeyInViewRoot(FacesContext facesContext) { if (viewRootAttributeMapPresent(facesContext)) { - return facesContext.getViewRoot().getAttributes().containsKey("_flowExecutionKey"); - } else { + return facesContext.getViewRoot().getAttributes().containsKey(FLOW_EXECUTION_KEY_VIEW_ROOT_ATTRIBUTE); + } + else { return false; } } /** * Simple little helper that returns true if the view root attribute map is non-null. - * @param facesContext the faces context + * @param facesContext the faces context * @return true if so, false otherwise */ private boolean viewRootAttributeMapPresent(FacesContext facesContext) { if (facesContext.getViewRoot() != null && facesContext.getViewRoot().getAttributes() != null) { return true; - } else { + } + else { return false; } } - + private void updateViewRoot(FacesContext facesContext, String viewId) { UIViewRoot viewRoot = facesContext.getViewRoot(); if (viewRoot == null || hasViewChanged(viewRoot, viewId)) { diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowPropertyResolver.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowPropertyResolver.java index 68a5ce19..69b7ba9b 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowPropertyResolver.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowPropertyResolver.java @@ -57,8 +57,7 @@ public class FlowPropertyResolver extends PropertyResolver { return resolverDelegate.getType(base, index); } else { - // can't access flow scope by index, so can't determine type. Return - // null per JSF spec + // can't access flow scope by index, so can't determine type. Return null per JSF spec return null; } } @@ -88,7 +87,7 @@ public class FlowPropertyResolver extends PropertyResolver { return resolverDelegate.getValue(base, index); } else { - throw new ReferenceSyntaxException("Cannot apply an index value to Flow map"); + throw new ReferenceSyntaxException("Cannot apply an index value to flow scope map"); } } @@ -97,7 +96,7 @@ public class FlowPropertyResolver extends PropertyResolver { return resolverDelegate.getValue(base, property); } if (!(property instanceof String)) { - throw new PropertyNotFoundException("Unable to get value from Flow map, as key is non-String"); + throw new PropertyNotFoundException("Unable to get value from flow scope map - key is non-String"); } FlowExecution execution = (FlowExecution)base; String attributeName = (String)property; @@ -108,8 +107,7 @@ public class FlowPropertyResolver extends PropertyResolver { WebApplicationContext wac = getWebApplicationContext(context); if (wac.containsBean(attributeName)) { // note: this resolver doesn't care, but this should normally be - // either a stateless singleton bean, or a stateful/stateless - // prototype + // either a stateless singleton bean, or a stateful/stateless prototype value = wac.getBean(attributeName); execution.getActiveSession().getScope().put(attributeName, value); } @@ -135,7 +133,7 @@ public class FlowPropertyResolver extends PropertyResolver { if (!(base instanceof FlowExecution)) { resolverDelegate.setValue(base, index, value); } - throw new ReferenceSyntaxException("Can not apply an index value to Flow map"); + throw new ReferenceSyntaxException("Cannot apply an index value to flow scope"); } public void setValue(Object base, Object property, Object value) throws EvaluationException, @@ -147,7 +145,7 @@ public class FlowPropertyResolver extends PropertyResolver { if (property == null || !(property instanceof String) || ((String)property).length() == 0) { throw new PropertyNotFoundException( - "Attempt to set Flow attribute with null name, empty name, or non-String name"); + "Attempt to set flow attribute with null name, empty name, or non-String name"); } FlowExecution execution = (FlowExecution)base; execution.getActiveSession().getScope().put((String)property, value);