1 16 package org.springframework.webflow.executor.jsf; 17 18 import java.io.IOException ; 19 import java.util.Iterator ; 20 import java.util.Map ; 21 22 import javax.faces.application.ViewHandler; 23 import javax.faces.component.UIViewRoot; 24 import javax.faces.context.FacesContext; 25 import javax.faces.event.PhaseEvent; 26 import javax.faces.event.PhaseId; 27 import javax.faces.event.PhaseListener; 28 29 import org.apache.commons.logging.Log; 30 import org.apache.commons.logging.LogFactory; 31 import org.springframework.webflow.context.ExternalContext; 32 import org.springframework.webflow.context.ExternalContextHolder; 33 import org.springframework.webflow.core.collection.LocalAttributeMap; 34 import org.springframework.webflow.definition.FlowDefinition; 35 import org.springframework.webflow.definition.registry.FlowDefinitionLocator; 36 import org.springframework.webflow.execution.FlowExecution; 37 import org.springframework.webflow.execution.FlowExecutionFactory; 38 import org.springframework.webflow.execution.ViewSelection; 39 import org.springframework.webflow.execution.repository.FlowExecutionKey; 40 import org.springframework.webflow.execution.repository.FlowExecutionRepository; 41 import org.springframework.webflow.execution.support.ApplicationView; 42 import org.springframework.webflow.execution.support.ExternalRedirect; 43 import org.springframework.webflow.execution.support.FlowDefinitionRedirect; 44 import org.springframework.webflow.execution.support.FlowExecutionRedirect; 45 import org.springframework.webflow.executor.support.FlowExecutorArgumentHandler; 46 import org.springframework.webflow.executor.support.RequestParameterFlowExecutorArgumentHandler; 47 48 74 public class FlowPhaseListener implements PhaseListener { 75 76 79 protected final Log logger = LogFactory.getLog(getClass()); 80 81 84 private FlowExecutorArgumentHandler argumentHandler = new RequestParameterFlowExecutorArgumentHandler(); 85 86 89 private ViewIdMapper viewIdMapper = new DefaultViewIdMapper(); 90 91 94 public FlowExecutorArgumentHandler getArgumentHandler() { 95 return argumentHandler; 96 } 97 98 101 public void setArgumentHandler(FlowExecutorArgumentHandler argumentHandler) { 102 this.argumentHandler = argumentHandler; 103 } 104 105 108 public ViewIdMapper getViewIdMapper() { 109 return viewIdMapper; 110 } 111 112 115 public void setViewIdMapper(ViewIdMapper viewIdMapper) { 116 this.viewIdMapper = viewIdMapper; 117 } 118 119 public PhaseId getPhaseId() { 120 return PhaseId.ANY_PHASE; 121 } 122 123 public void beforePhase(PhaseEvent event) { 124 if (event.getPhaseId() == PhaseId.RESTORE_VIEW) { 125 ExternalContextHolder.setExternalContext(new JsfExternalContext(event.getFacesContext())); 126 restoreFlowExecution(event.getFacesContext()); 127 } 128 else if (event.getPhaseId() == PhaseId.RENDER_RESPONSE) { 129 if (FlowExecutionHolderUtils.isFlowExecutionRestored(event.getFacesContext())) { 130 prepareResponse(getCurrentContext(), FlowExecutionHolderUtils.getFlowExecutionHolder(event 131 .getFacesContext())); 132 } 133 } 134 } 135 136 public void afterPhase(PhaseEvent event) { 137 if (event.getPhaseId() == PhaseId.RENDER_RESPONSE) { 138 try { 139 if (FlowExecutionHolderUtils.isFlowExecutionChanged(event.getFacesContext())) { 140 saveFlowExecution(getCurrentContext(), FlowExecutionHolderUtils.getFlowExecutionHolder(event 141 .getFacesContext())); 142 } 143 } 144 finally { 145 ExternalContextHolder.setExternalContext(null); 146 } 147 } 148 } 149 150 private JsfExternalContext getCurrentContext() { 151 return (JsfExternalContext) ExternalContextHolder.getExternalContext(); 152 } 153 154 protected void restoreFlowExecution(FacesContext facesContext) { 155 JsfExternalContext context = new JsfExternalContext(facesContext); 156 if (argumentHandler.isFlowExecutionKeyPresent(context)) { 157 FlowExecutionRepository repository = getRepository(context); 162 FlowExecutionKey flowExecutionKey = repository.parseFlowExecutionKey(argumentHandler 163 .extractFlowExecutionKey(context)); 164 FlowExecution flowExecution = repository.getFlowExecution(flowExecutionKey); 165 if (logger.isDebugEnabled()) { 166 logger.debug("Loaded existing flow execution from repository with id '" + flowExecutionKey + "'"); 167 } 168 FlowExecutionHolderUtils.setFlowExecutionHolder(new FlowExecutionHolder(flowExecutionKey, flowExecution), 169 facesContext); 170 } 171 else if (argumentHandler.isFlowIdPresent(context)) { 172 String flowId = argumentHandler.extractFlowId(context); 175 FlowDefinition flowDefinition = getLocator(context).getFlowDefinition(flowId); 176 FlowExecution flowExecution = getFactory(context).createFlowExecution(flowDefinition); 177 FlowExecutionHolder holder = new FlowExecutionHolder(flowExecution); 178 FlowExecutionHolderUtils.setFlowExecutionHolder(holder, facesContext); 179 ViewSelection selectedView = flowExecution.start(createInput(flowExecution, context), context); 180 if (logger.isDebugEnabled()) { 181 logger.debug("Started new flow execution"); 182 } 183 holder.setViewSelection(selectedView); 184 holder.markNeedsSave(); 185 } 186 } 187 188 195 protected LocalAttributeMap createInput(FlowExecution flowExecution, ExternalContext context) { 196 return null; 197 } 198 199 protected void prepareResponse(JsfExternalContext context, FlowExecutionHolder holder) { 200 if (holder.needsSave()) { 201 generateKey(context, holder); 202 } 203 ViewSelection selectedView = holder.getViewSelection(); 204 if (selectedView == null) { 205 selectedView = holder.getFlowExecution().refresh(context); 206 holder.setViewSelection(selectedView); 207 } 208 if (selectedView instanceof ApplicationView) { 209 prepareApplicationView(context.getFacesContext(), holder); 210 } 211 else if (selectedView instanceof FlowExecutionRedirect) { 212 String url = argumentHandler.createFlowExecutionUrl(holder.getFlowExecutionKey().toString(), holder 213 .getFlowExecution(), context); 214 sendRedirect(url, context); 215 } 216 else if (selectedView instanceof ExternalRedirect) { 217 String flowExecutionKey = holder.getFlowExecution().isActive() ? holder.getFlowExecutionKey().toString() 218 : null; 219 String url = argumentHandler.createExternalUrl((ExternalRedirect) holder.getViewSelection(), 220 flowExecutionKey, context); 221 sendRedirect(url, context); 222 } 223 else if (selectedView instanceof FlowDefinitionRedirect) { 224 String url = argumentHandler.createFlowDefinitionUrl((FlowDefinitionRedirect) holder.getViewSelection(), 225 context); 226 sendRedirect(url, context); 227 } 228 } 229 230 protected void prepareApplicationView(FacesContext facesContext, FlowExecutionHolder holder) { 231 ApplicationView forward = (ApplicationView) holder.getViewSelection(); 232 if (forward != null) { 233 putInto(facesContext.getExternalContext().getRequestMap(), forward.getModel()); 234 updateViewRoot(facesContext, viewIdMapper.mapViewId(forward.getViewName())); 235 } 236 Map requestMap = facesContext.getExternalContext().getRequestMap(); 237 argumentHandler.exposeFlowExecutionContext(holder.getFlowExecutionKey().toString(), holder.getFlowExecution(), 238 requestMap); 239 } 240 241 private void updateViewRoot(FacesContext facesContext, String viewId) { 242 UIViewRoot viewRoot = facesContext.getViewRoot(); 243 if (viewRoot == null || hasViewChanged(viewRoot, viewId)) { 244 if (logger.isDebugEnabled()) { 246 logger.debug("Creating new view with id '" + viewId + "' from previous view with id '" 247 + viewRoot.getViewId() + "'"); 248 } 249 ViewHandler handler = facesContext.getApplication().getViewHandler(); 250 UIViewRoot view = handler.createView(facesContext, viewId); 251 facesContext.setViewRoot(view); 252 } 253 } 254 255 private boolean hasViewChanged(UIViewRoot viewRoot, String viewId) { 256 return !viewRoot.getViewId().equals(viewId); 257 } 258 259 private void generateKey(JsfExternalContext context, FlowExecutionHolder holder) { 260 FlowExecution flowExecution = holder.getFlowExecution(); 261 if (flowExecution.isActive()) { 262 FlowExecutionKey flowExecutionKey = holder.getFlowExecutionKey(); 265 FlowExecutionRepository repository = getRepository(context); 266 if (flowExecutionKey == null) { 267 flowExecutionKey = repository.generateKey(flowExecution); 269 } 270 else { 271 flowExecutionKey = repository.getNextKey(flowExecution, flowExecutionKey); 274 } 275 holder.setFlowExecutionKey(flowExecutionKey); 276 } 277 } 278 279 protected void saveFlowExecution(JsfExternalContext context, FlowExecutionHolder holder) { 280 FlowExecution flowExecution = holder.getFlowExecution(); 281 FlowExecutionRepository repository = getRepository(context); 282 if (flowExecution.isActive()) { 283 if (logger.isDebugEnabled()) { 285 logger.debug("Saving continuation to repository with key " + holder.getFlowExecutionKey()); 286 } 287 repository.putFlowExecution(holder.getFlowExecutionKey(), flowExecution); 288 } 289 else { 290 if (holder.getFlowExecutionKey() != null) { 291 if (logger.isDebugEnabled()) { 293 logger.debug("Removing execution in repository with key '" + holder.getFlowExecutionKey() + "'"); 294 } 295 repository.removeFlowExecution(holder.getFlowExecutionKey()); 296 } 297 } 298 } 299 300 307 private void putInto(Map targetMap, Map map) { 308 try { 309 targetMap.putAll(map); 310 } 311 catch (UnsupportedOperationException e) { 312 Iterator it = map.entrySet().iterator(); 315 while (it.hasNext()) { 316 Map.Entry entry = (Map.Entry ) it.next(); 317 targetMap.put(entry.getKey(), entry.getValue()); 318 } 319 } 320 } 321 322 private void sendRedirect(String url, JsfExternalContext context) { 323 try { 324 context.getFacesContext().getExternalContext().redirect(url); 325 context.getFacesContext().responseComplete(); 326 } 327 catch (IOException e) { 328 throw new IllegalArgumentException ("Could not send redirect to " + url); 329 } 330 } 331 332 336 public static class DefaultViewIdMapper implements ViewIdMapper { 337 public String mapViewId(String viewName) { 338 return viewName; 339 } 340 } 341 342 private FlowDefinitionLocator getLocator(JsfExternalContext context) { 343 return FlowFacesUtils.getDefinitionLocator(context.getFacesContext()); 344 } 345 346 private FlowExecutionFactory getFactory(JsfExternalContext context) { 347 return FlowFacesUtils.getExecutionFactory(context.getFacesContext()); 348 } 349 350 private FlowExecutionRepository getRepository(JsfExternalContext context) { 351 return FlowFacesUtils.getExecutionRepository(context.getFacesContext()); 352 } 353 } | Popular Tags |