1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.application;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.Comparator;
26 import java.util.EnumSet;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.concurrent.ConcurrentHashMap;
33 import java.util.logging.Level;
34 import java.util.logging.Logger;
35
36 import java.util.regex.Pattern;
37 import javax.el.MethodExpression;
38 import javax.faces.FacesException;
39 import javax.faces.application.ConfigurableNavigationHandler;
40 import javax.faces.application.FacesMessage;
41 import javax.faces.application.NavigationCase;
42 import javax.faces.application.ProjectStage;
43 import javax.faces.application.ViewHandler;
44 import javax.faces.component.UIComponent;
45 import javax.faces.component.UIViewAction;
46 import javax.faces.component.UIViewRoot;
47 import javax.faces.component.visit.VisitCallback;
48 import javax.faces.component.visit.VisitContext;
49 import javax.faces.component.visit.VisitHint;
50 import javax.faces.component.visit.VisitResult;
51 import javax.faces.context.ExternalContext;
52 import javax.faces.context.FacesContext;
53 import javax.faces.context.PartialViewContext;
54 import javax.faces.flow.Flow;
55 import javax.faces.flow.FlowCallNode;
56 import javax.faces.flow.FlowHandler;
57 import javax.faces.flow.FlowNode;
58 import javax.faces.flow.MethodCallNode;
59 import javax.faces.flow.Parameter;
60 import javax.faces.flow.ReturnNode;
61 import javax.faces.flow.SwitchCase;
62 import javax.faces.flow.SwitchNode;
63 import javax.faces.flow.ViewNode;
64 import javax.faces.view.ViewDeclarationLanguage;
65 import javax.faces.view.ViewMetadata;
66
67 import org.apache.myfaces.config.RuntimeConfig;
68 import org.apache.myfaces.config.element.NavigationRule;
69 import org.apache.myfaces.flow.FlowHandlerImpl;
70 import org.apache.myfaces.shared.application.NavigationUtils;
71 import org.apache.myfaces.shared.renderkit.html.util.SharedStringBuilder;
72 import org.apache.myfaces.shared.util.ClassUtils;
73 import org.apache.myfaces.shared.util.HashMapUtils;
74 import org.apache.myfaces.shared.util.StringUtils;
75 import org.apache.myfaces.util.FilenameUtils;
76 import org.apache.myfaces.view.facelets.ViewPoolProcessor;
77 import org.apache.myfaces.view.facelets.tag.jsf.PreDisposeViewEvent;
78
79
80
81
82
83
84 public class NavigationHandlerImpl
85 extends ConfigurableNavigationHandler
86 {
87 private static final Logger log = Logger.getLogger(NavigationHandlerImpl.class.getName());
88
89 private static final String SKIP_ITERATION_HINT = "javax.faces.visit.SKIP_ITERATION";
90
91 private static final Set<VisitHint> VISIT_HINTS = Collections.unmodifiableSet(
92 EnumSet.of(VisitHint.SKIP_ITERATION));
93
94 private static final String OUTCOME_NAVIGATION_SB = "oam.navigation.OUTCOME_NAVIGATION_SB";
95
96 private static final Pattern AMP_PATTERN = Pattern.compile("&(amp;)?");
97
98 private static final String ASTERISK = "*";
99
100 private Map<String, Set<NavigationCase>> _navigationCases = null;
101
102 private List<_WildcardPattern> _wildcardPatterns = new ArrayList<_WildcardPattern>();
103 private Boolean _developmentStage;
104
105 private Map<String, _FlowNavigationStructure> _flowNavigationStructureMap =
106 new ConcurrentHashMap<String, _FlowNavigationStructure>();
107
108 private NavigationHandlerSupport navigationHandlerSupport;
109
110 public NavigationHandlerImpl()
111 {
112 if (log.isLoggable(Level.FINEST))
113 {
114 log.finest("New NavigationHandler instance created");
115 }
116 }
117
118 @Override
119 public void handleNavigation(FacesContext facesContext, String fromAction, String outcome)
120 {
121 handleNavigation(facesContext, fromAction, outcome, null);
122 }
123
124 @Override
125 public void handleNavigation(FacesContext facesContext, String fromAction,
126 String outcome, String toFlowDocumentId)
127 {
128
129 NavigationContext navigationContext = new NavigationContext();
130 NavigationCase navigationCase = null;
131 try
132 {
133 navigationCase = getNavigationCommand(facesContext, navigationContext, fromAction, outcome,
134 toFlowDocumentId);
135 }
136 finally
137 {
138 navigationContext.finish(facesContext);
139 }
140
141 if (navigationCase != null)
142 {
143 if (log.isLoggable(Level.FINEST))
144 {
145 log.finest("handleNavigation fromAction=" + fromAction + " outcome=" + outcome +
146 " toViewId =" + navigationCase.getToViewId(facesContext) +
147 " redirect=" + navigationCase.isRedirect());
148 }
149 boolean isViewActionProcessingBroadcastAndRequiresRedirect = false;
150 if (UIViewAction.isProcessingBroadcast(facesContext))
151 {
152
153
154
155
156 facesContext.getExternalContext().getFlash().setKeepMessages(true);
157 String fromViewId = (facesContext.getViewRoot() == null) ? null :
158 facesContext.getViewRoot().getViewId();
159 String toViewId = navigationCase.getToViewId(facesContext);
160
161
162
163 if (fromViewId == null && toViewId != null)
164 {
165 isViewActionProcessingBroadcastAndRequiresRedirect = true;
166 }
167 else if (fromViewId != null && !fromViewId.equals(toViewId))
168 {
169 isViewActionProcessingBroadcastAndRequiresRedirect = true;
170 }
171 }
172 if (navigationCase.isRedirect() || isViewActionProcessingBroadcastAndRequiresRedirect)
173 {
174
175
176
177
178
179
180
181 FlowHandler flowHandler = facesContext.getApplication().getFlowHandler();
182 List<Flow> activeFlows = FlowHandlerImpl.getActiveFlows(facesContext, flowHandler);
183 Flow currentFlow = flowHandler.getCurrentFlow(facesContext);
184 Flow targetFlow = calculateTargetFlow(facesContext, outcome, flowHandler,
185 activeFlows, toFlowDocumentId);
186
187 Map<String,List<String>> navigationCaseParameters = navigationCase.getParameters();
188
189
190
191 if (currentFlow != targetFlow)
192 {
193
194 if ((currentFlow != null && !currentFlow.equals(targetFlow)) ||
195 (targetFlow != null && !targetFlow.equals(currentFlow)))
196 {
197 if (navigationCaseParameters == null)
198 {
199 navigationCaseParameters = new HashMap<>();
200 }
201
202
203 if (currentFlow != null && targetFlow == null)
204 {
205
206 List<String> list = new ArrayList<String>(1);
207 list.add(FlowHandler.NULL_FLOW);
208 navigationCaseParameters.put(FlowHandler.TO_FLOW_DOCUMENT_ID_REQUEST_PARAM_NAME, list);
209
210
211 List<String> list2 = new ArrayList<String>(1);
212 list2.add("");
213 navigationCaseParameters.put(FlowHandler.FLOW_ID_REQUEST_PARAM_NAME, list2);
214 }
215 else
216 {
217
218
219
220
221
222 List<String> list = new ArrayList<String>(1);
223 list.add((toFlowDocumentId == null ? "" : toFlowDocumentId));
224 navigationCaseParameters.put(FlowHandler.TO_FLOW_DOCUMENT_ID_REQUEST_PARAM_NAME, list);
225
226
227 List<String> list2 = new ArrayList<String>(1);
228 list2.add(targetFlow.getId());
229 navigationCaseParameters.put(FlowHandler.FLOW_ID_REQUEST_PARAM_NAME, list2);
230 }
231 }
232 }
233
234 ExternalContext externalContext = facesContext.getExternalContext();
235 ViewHandler viewHandler = facesContext.getApplication().getViewHandler();
236 String toViewId = navigationCase.getToViewId(facesContext);
237
238 String redirectPath = viewHandler.getRedirectURL(
239 facesContext, toViewId,
240 NavigationUtils.getEvaluatedNavigationParameters(facesContext,
241 navigationCaseParameters) ,
242 navigationCase.isIncludeViewParams());
243
244
245
246
247
248 applyFlowTransition(facesContext, navigationContext);
249
250
251 UIViewRoot viewRoot = facesContext.getViewRoot();
252 if (viewRoot != null && !toViewId.equals(viewRoot.getViewId()))
253 {
254
255 Map<String, Object> viewMap = viewRoot.getViewMap(false);
256 if (viewMap != null)
257 {
258 viewMap.clear();
259 }
260 }
261
262
263
264
265
266 PartialViewContext partialViewContext = facesContext.getPartialViewContext();
267 String viewId = facesContext.getViewRoot() != null ? facesContext.getViewRoot().getViewId() : null;
268 if ( partialViewContext.isPartialRequest() &&
269 !partialViewContext.isRenderAll() &&
270 toViewId != null &&
271 !toViewId.equals(viewId))
272 {
273 partialViewContext.setRenderAll(true);
274 }
275
276
277 ViewPoolProcessor processor = ViewPoolProcessor.getInstance(facesContext);
278 if (processor != null &&
279 processor.isViewPoolEnabledForThisView(facesContext, facesContext.getViewRoot()))
280 {
281 processor.disposeView(facesContext, facesContext.getViewRoot());
282 }
283
284
285 externalContext.getFlash().setRedirect(true);
286 try
287 {
288 externalContext.redirect(redirectPath);
289 facesContext.responseComplete();
290 }
291 catch (IOException e)
292 {
293 throw new FacesException(e.getMessage(), e);
294 }
295 }
296 else
297 {
298 ViewHandler viewHandler = facesContext.getApplication().getViewHandler();
299
300 String newViewId = navigationCase.getToViewId(facesContext);
301
302
303
304
305
306 PartialViewContext partialViewContext = facesContext.getPartialViewContext();
307 String viewId = facesContext.getViewRoot() != null ? facesContext.getViewRoot().getViewId() : null;
308 if ( partialViewContext.isPartialRequest() &&
309 !partialViewContext.isRenderAll() &&
310 newViewId != null &&
311 !newViewId.equals(viewId))
312 {
313 partialViewContext.setRenderAll(true);
314 }
315
316 if (facesContext.getViewRoot() != null &&
317 facesContext.getViewRoot().getAttributes().containsKey("oam.CALL_PRE_DISPOSE_VIEW"))
318 {
319 try
320 {
321 facesContext.getAttributes().put(SKIP_ITERATION_HINT, Boolean.TRUE);
322
323 VisitContext visitContext = VisitContext.createVisitContext(facesContext, null, VISIT_HINTS);
324 facesContext.getViewRoot().visitTree(visitContext,
325 new PreDisposeViewCallback());
326 }
327 finally
328 {
329 facesContext.getAttributes().remove(SKIP_ITERATION_HINT);
330 }
331 }
332
333 applyFlowTransition(facesContext, navigationContext);
334
335
336 ViewPoolProcessor processor = ViewPoolProcessor.getInstance(facesContext);
337 if (processor != null &&
338 processor.isViewPoolEnabledForThisView(facesContext, facesContext.getViewRoot()))
339 {
340 processor.disposeView(facesContext, facesContext.getViewRoot());
341 }
342
343
344 UIViewRoot viewRoot = null;
345
346 String derivedViewId = viewHandler.deriveViewId(facesContext, newViewId);
347
348 if (derivedViewId != null)
349 {
350 ViewDeclarationLanguage vdl = viewHandler.getViewDeclarationLanguage(facesContext, derivedViewId);
351
352 if (vdl != null)
353 {
354 ViewMetadata metadata = vdl.getViewMetadata(facesContext, newViewId);
355
356 if (metadata != null)
357 {
358 viewRoot = metadata.createMetadataView(facesContext);
359 }
360 }
361 }
362
363
364
365
366
367 if (viewRoot == null)
368 {
369 viewRoot = viewHandler.createView(facesContext, newViewId);
370 }
371
372 facesContext.setViewRoot(viewRoot);
373 facesContext.renderResponse();
374 }
375 }
376 else
377 {
378
379 if (log.isLoggable(Level.FINEST))
380 {
381 log.finest("handleNavigation fromAction=" + fromAction + " outcome=" + outcome +
382 " no matching navigation-case found, staying on current ViewRoot");
383 }
384 }
385 }
386
387 private void applyFlowTransition(FacesContext facesContext, NavigationContext navigationContext)
388 {
389
390
391 if (navigationContext != null &&
392 navigationContext.getSourceFlows() != null ||
393 (navigationContext.getTargetFlows() != null &&
394 !navigationContext.getTargetFlows().isEmpty()))
395 {
396 FlowHandler flowHandler = facesContext.getApplication().getFlowHandler();
397 for (int i = 0; i < navigationContext.getTargetFlows().size(); i++)
398 {
399 Flow sourceFlow = navigationContext.getSourceFlows().get(i);
400 Flow targetFlow = navigationContext.getTargetFlows().get(i);
401
402 flowHandler.transition(facesContext, sourceFlow, targetFlow,
403 navigationContext.getFlowCallNodes().get(i),
404 navigationContext.getNavigationCase().getToViewId(facesContext));
405 sourceFlow = targetFlow;
406 }
407 }
408 }
409
410
411
412
413 protected NavigationHandlerSupport getNavigationHandlerSupport()
414 {
415 if (navigationHandlerSupport == null)
416 {
417 navigationHandlerSupport = new DefaultNavigationHandlerSupport();
418 }
419 return navigationHandlerSupport;
420 }
421
422 public void setNavigationHandlerSupport(NavigationHandlerSupport navigationHandlerSupport)
423 {
424 this.navigationHandlerSupport = navigationHandlerSupport;
425 }
426
427 private static class PreDisposeViewCallback implements VisitCallback
428 {
429
430 public VisitResult visit(VisitContext context, UIComponent target)
431 {
432 context.getFacesContext().getApplication().publishEvent(context.getFacesContext(),
433 PreDisposeViewEvent.class, target);
434
435 return VisitResult.ACCEPT;
436 }
437 }
438
439
440
441
442 public NavigationCase getNavigationCase(FacesContext facesContext, String fromAction, String outcome)
443 {
444 NavigationContext navigationContext = new NavigationContext();
445 try
446 {
447 return getNavigationCommand(facesContext, navigationContext, fromAction, outcome, null);
448 }
449 finally
450 {
451 navigationContext.finish(facesContext);
452 }
453 }
454
455 public NavigationCase getNavigationCommandFromGlobalNavigationCases(
456 FacesContext facesContext, String viewId, NavigationContext navigationContext,
457 String fromAction, String outcome)
458 {
459 Map<String, Set<NavigationCase>> casesMap = getNavigationCases();
460 NavigationCase navigationCase = null;
461
462 Set<? extends NavigationCase> casesSet;
463 if (viewId != null)
464 {
465 casesSet = casesMap.get(viewId);
466 if (casesSet != null)
467 {
468
469 navigationCase = calcMatchingNavigationCase(facesContext, casesSet, fromAction, outcome);
470 }
471 }
472
473 if (navigationCase == null)
474 {
475
476
477 List<_WildcardPattern> wildcardPatterns = getSortedWildcardPatterns();
478
479 for (int i = 0; i < wildcardPatterns.size(); i++)
480 {
481 _WildcardPattern wildcardPattern = wildcardPatterns.get(i);
482 if (wildcardPattern.match(viewId))
483 {
484 casesSet = casesMap.get(wildcardPattern.getPattern());
485 if (casesSet != null)
486 {
487 navigationCase = calcMatchingNavigationCase(facesContext, casesSet, fromAction, outcome);
488 if (navigationCase != null)
489 {
490 break;
491 }
492 }
493 }
494 }
495 }
496 return navigationCase;
497 }
498
499 private Flow calculateTargetFlow(FacesContext facesContext, String outcome,
500 FlowHandler flowHandler, List<Flow> activeFlows, String toFlowDocumentId)
501 {
502 Flow targetFlow = null;
503 if (toFlowDocumentId != null)
504 {
505 targetFlow = flowHandler.getFlow(facesContext, toFlowDocumentId, outcome);
506 }
507 if (targetFlow == null && !activeFlows.isEmpty())
508 {
509 for (Flow currentFlow : activeFlows)
510 {
511 targetFlow = flowHandler.getFlow(facesContext, currentFlow.getDefiningDocumentId(), outcome);
512 if (targetFlow != null)
513 {
514 break;
515 }
516 }
517 }
518 if (targetFlow == null)
519 {
520 targetFlow = flowHandler.getFlow(facesContext, "", outcome);
521 }
522 return targetFlow;
523 }
524
525 public NavigationCase getNavigationCommand(
526 FacesContext facesContext, NavigationContext navigationContext, String fromAction, String outcome,
527 String toFlowDocumentId)
528 {
529 String viewId = facesContext.getViewRoot() != null ? facesContext.getViewRoot().getViewId() : null;
530 NavigationCase navigationCase = getNavigationCommandFromGlobalNavigationCases(
531 facesContext, viewId, navigationContext, fromAction, outcome);
532 if (outcome != null && navigationCase == null)
533 {
534 FlowHandler flowHandler = facesContext.getApplication().getFlowHandler();
535 List<Flow> activeFlows = FlowHandlerImpl.getActiveFlows(facesContext, flowHandler);
536
537
538 Flow targetFlow = calculateTargetFlow(facesContext, outcome, flowHandler, activeFlows, toFlowDocumentId);
539 Flow currentFlow = navigationContext.getCurrentFlow(facesContext);
540 FlowCallNode targetFlowCallNode = null;
541 boolean startFlow = false;
542 String startFlowDocumentId = null;
543 String startFlowId = null;
544 boolean checkFlowNode = false;
545 String outcomeToGo = outcome;
546 String actionToGo = fromAction;
547
548 if (currentFlow != null)
549 {
550
551
552
553 if (targetFlow != null)
554 {
555 if (flowHandler.isActive(facesContext, targetFlow.getDefiningDocumentId(), targetFlow.getId()))
556 {
557
558
559 FlowNode flowNode = targetFlow.getNode(outcome);
560 if (flowNode != null)
561 {
562 checkFlowNode = true;
563 }
564 else
565 {
566 startFlow = true;
567 }
568 }
569 else
570 {
571 startFlow = true;
572 }
573 }
574 else
575 {
576
577 checkFlowNode = true;
578 }
579 }
580 else
581 {
582 if (targetFlow != null)
583 {
584
585 startFlow = true;
586 }
587 }
588 if (!startFlow)
589 {
590 for (Flow activeFlow : activeFlows)
591 {
592 FlowNode node = activeFlow.getNode(outcome);
593 if (node != null)
594 {
595 currentFlow = activeFlow;
596 break;
597 }
598 _FlowNavigationStructure flowNavigationStructure = _flowNavigationStructureMap.get(
599 activeFlow.getId());
600 navigationCase = getNavigationCaseFromFlowStructure(facesContext,
601 flowNavigationStructure, fromAction, outcome, viewId);
602 if (navigationCase != null)
603 {
604 currentFlow = activeFlow;
605 break;
606 }
607 }
608 }
609
610
611 if (startFlow || (checkFlowNode && currentFlow != null))
612 {
613 boolean complete = false;
614 boolean checkNavCase = true;
615
616 while (!complete && (startFlow || checkFlowNode))
617 {
618 if (startFlow)
619 {
620 if (flowHandler.isActive(facesContext, targetFlow.getDefiningDocumentId(), targetFlow.getId())
621 && targetFlowCallNode == null)
622 {
623
624 Flow baseReturnFlow = navigationContext.getCurrentFlow(facesContext);
625
626 while (baseReturnFlow != null && !(baseReturnFlow.getDefiningDocumentId().equals(
627 targetFlow.getDefiningDocumentId()) &&
628 baseReturnFlow.getId().equals(targetFlow.getId())) )
629 {
630 navigationContext.popFlow(facesContext);
631 baseReturnFlow = navigationContext.getCurrentFlow(facesContext);
632 }
633 navigationContext.popFlow(facesContext);
634 currentFlow = navigationContext.getCurrentFlow(facesContext);
635 navigationContext.addTargetFlow(baseReturnFlow, currentFlow, null);
636 }
637 if (startFlowId == null)
638 {
639 startFlowDocumentId = targetFlow.getDefiningDocumentId();
640 startFlowId = targetFlowCallNode == null ? targetFlow.getId() : targetFlowCallNode.getId();
641 }
642 navigationContext.addTargetFlow(currentFlow, targetFlow, targetFlowCallNode);
643 targetFlowCallNode = null;
644
645
646 navigationContext.pushFlow(facesContext, targetFlow);
647 currentFlow = targetFlow;
648
649
650 outcomeToGo = resolveStartNodeOutcome(targetFlow);
651 checkFlowNode = true;
652 startFlow = false;
653 }
654 if (checkFlowNode)
655 {
656 FlowNode flowNode = currentFlow.getNode(outcomeToGo);
657 if (flowNode != null)
658 {
659 checkNavCase = true;
660 if (!complete && flowNode instanceof SwitchNode)
661 {
662 outcomeToGo = calculateSwitchOutcome(facesContext, (SwitchNode) flowNode);
663
664
665 actionToGo = currentFlow.getId();
666 flowNode = currentFlow.getNode(outcomeToGo);
667 continue;
668 }
669 if (!complete && flowNode instanceof FlowCallNode)
670 {
671
672 FlowCallNode flowCallNode = (FlowCallNode) flowNode;
673 targetFlow = calculateFlowCallTargetFlow(facesContext,
674 flowHandler, flowCallNode, currentFlow);
675 if (targetFlow != null)
676 {
677 targetFlowCallNode = flowCallNode;
678 startFlow = true;
679 continue;
680 }
681 else
682 {
683
684
685 complete = true;
686 }
687 }
688 if (!complete && flowNode instanceof MethodCallNode)
689 {
690 MethodCallNode methodCallNode = (MethodCallNode) flowNode;
691 String vdlViewIdentifier = calculateVdlViewIdentifier(facesContext, methodCallNode);
692
693 if (vdlViewIdentifier != null)
694 {
695 outcomeToGo = vdlViewIdentifier;
696 actionToGo = currentFlow.getId();
697 continue;
698 }
699 else
700 {
701 complete = true;
702 }
703 }
704 if (!complete && flowNode instanceof ReturnNode)
705 {
706 ReturnNode returnNode = (ReturnNode) flowNode;
707 String fromOutcome = returnNode.getFromOutcome(facesContext);
708 actionToGo = currentFlow.getId();
709 Flow sourceFlow = currentFlow;
710 Flow baseReturnFlow = navigationContext.getCurrentFlow(facesContext);
711
712 while (baseReturnFlow != null && !(baseReturnFlow.getDefiningDocumentId().equals(
713 currentFlow.getDefiningDocumentId()) &&
714 baseReturnFlow.getId().equals(currentFlow.getId())) )
715 {
716 navigationContext.popFlow(facesContext);
717 baseReturnFlow = navigationContext.getCurrentFlow(facesContext);
718 }
719 navigationContext.popFlow(facesContext);
720 currentFlow = navigationContext.getCurrentFlow(facesContext);
721 navigationContext.addTargetFlow(sourceFlow, currentFlow, null);
722 outcomeToGo = fromOutcome;
723 String lastDisplayedViewId = navigationContext.getLastDisplayedViewId(facesContext,
724 currentFlow);
725
726
727
728
729
730
731 navigationCase = getNavigationCommand(facesContext,
732 navigationContext, actionToGo, outcomeToGo, FlowHandler.NULL_FLOW);
733 if (navigationCase != null)
734 {
735 navigationCase = new FlowNavigationCase(navigationCase,
736 flowNode.getId(), FlowHandler.NULL_FLOW);
737 complete = true;
738 }
739 else
740 {
741
742 if (lastDisplayedViewId != null)
743 {
744 navigationCase = createNavigationCase(
745 viewId, flowNode.getId(), lastDisplayedViewId, FlowHandler.NULL_FLOW);
746 complete = true;
747 }
748 }
749 if (currentFlow == null)
750 {
751 complete = true;
752 }
753 continue;
754 }
755 if (!complete && flowNode instanceof ViewNode)
756 {
757 ViewNode viewNode = (ViewNode) flowNode;
758 navigationCase = createNavigationCase(viewId, flowNode.getId(),
759 viewNode.getVdlDocumentId());
760 complete = true;
761 }
762 else
763 {
764
765 complete = true;
766 }
767 }
768 else if (checkNavCase)
769 {
770
771 _FlowNavigationStructure flowNavigationStructure = _flowNavigationStructureMap.get(
772 currentFlow.getId());
773 navigationCase = getNavigationCaseFromFlowStructure(facesContext,
774 flowNavigationStructure, actionToGo, outcomeToGo, viewId);
775
776
777
778
779 if (navigationCase != null)
780 {
781 outcomeToGo = navigationCase.getToViewId(facesContext);
782 checkNavCase = false;
783 }
784 else
785 {
786
787 complete = true;
788 }
789 }
790 else
791 {
792 complete = true;
793 }
794 }
795 }
796
797 if (outcomeToGo != null && navigationCase == null)
798 {
799 navigationCase = getOutcomeNavigationCase (facesContext, actionToGo, outcomeToGo);
800 }
801 }
802 if (startFlowId != null)
803 {
804 navigationCase = new FlowNavigationCase(navigationCase, startFlowId, startFlowDocumentId);
805 }
806 }
807 if (outcome != null && navigationCase == null)
808 {
809
810
811 navigationCase = getOutcomeNavigationCase (facesContext, fromAction, outcome);
812 }
813 if (outcome != null && navigationCase == null && !facesContext.isProjectStage(ProjectStage.Production))
814 {
815 final FacesMessage facesMessage = new FacesMessage("No navigation case match for viewId " + viewId +
816 ", action " + fromAction + " and outcome " + outcome);
817 facesMessage.setSeverity(FacesMessage.SEVERITY_WARN);
818 facesContext.addMessage(null, facesMessage);
819 }
820 if (navigationCase != null)
821 {
822 navigationContext.setNavigationCase(navigationCase);
823 }
824 return navigationContext.getNavigationCase();
825
826 }
827
828 private String resolveStartNodeOutcome(Flow targetFlow)
829 {
830 String outcomeToGo;
831 if (targetFlow.getStartNodeId() == null)
832 {
833
834
835
836 outcomeToGo = "/" + targetFlow.getId()+ "/" +
837 targetFlow.getId() + ".xhtml";
838 }
839 else
840 {
841 outcomeToGo = targetFlow.getStartNodeId();
842 }
843 return outcomeToGo;
844 }
845
846 private String calculateSwitchOutcome(FacesContext facesContext, SwitchNode switchNode)
847 {
848 String outcomeToGo = null;
849 boolean resolved = false;
850
851
852
853 for (SwitchCase switchCase : switchNode.getCases())
854 {
855 Boolean isConditionTrue = switchCase.getCondition(facesContext);
856 if (Boolean.TRUE.equals(isConditionTrue))
857 {
858 outcomeToGo = switchCase.getFromOutcome();
859 resolved = true;
860 break;
861 }
862 }
863 if (!resolved)
864 {
865 outcomeToGo = switchNode.getDefaultOutcome(facesContext);
866 }
867 return outcomeToGo;
868 }
869
870 private Flow calculateFlowCallTargetFlow(FacesContext facesContext, FlowHandler flowHandler,
871 FlowCallNode flowCallNode, Flow currentFlow)
872 {
873 Flow targetFlow = null;
874
875
876
877
878
879
880
881
882 String calledFlowDocumentId = flowCallNode.getCalledFlowDocumentId(facesContext);
883 if (calledFlowDocumentId == null)
884 {
885 calledFlowDocumentId = currentFlow.getDefiningDocumentId();
886 }
887 targetFlow = flowHandler.getFlow(facesContext,
888 calledFlowDocumentId,
889 flowCallNode.getCalledFlowId(facesContext));
890 if (targetFlow == null && !"".equals(calledFlowDocumentId))
891 {
892 targetFlow = flowHandler.getFlow(facesContext, "",
893 flowCallNode.getCalledFlowId(facesContext));
894 }
895 return targetFlow;
896 }
897
898 private String calculateVdlViewIdentifier(FacesContext facesContext, MethodCallNode methodCallNode)
899 {
900 String vdlViewIdentifier = null;
901 MethodExpression method = methodCallNode.getMethodExpression();
902 if (method != null)
903 {
904 Object value = invokeMethodCallNode(facesContext, methodCallNode);
905 if (value != null)
906 {
907 vdlViewIdentifier = value.toString();
908 }
909 else if (methodCallNode.getOutcome() != null)
910 {
911 vdlViewIdentifier = (String) methodCallNode.getOutcome().getValue(
912 facesContext.getELContext());
913 }
914 }
915 return vdlViewIdentifier;
916 }
917
918 private Object invokeMethodCallNode(FacesContext facesContext, MethodCallNode methodCallNode)
919 {
920 MethodExpression method = methodCallNode.getMethodExpression();
921 Object value = null;
922
923 if (methodCallNode.getParameters() != null &&
924 !methodCallNode.getParameters().isEmpty())
925 {
926 Object[] parameters = new Object[methodCallNode.getParameters().size()];
927 Class[] clazzes = new Class[methodCallNode.getParameters().size()];
928 for (int i = 0; i < methodCallNode.getParameters().size(); i++)
929 {
930 Parameter param = methodCallNode.getParameters().get(i);
931 parameters[i] = param.getValue().getValue(facesContext.getELContext());
932 clazzes[i] = param.getName() != null ?
933 ClassUtils.simpleJavaTypeToClass(param.getName()) :
934 (parameters[i] == null ? String.class : parameters[i].getClass());
935 }
936
937
938
939 method = facesContext.getApplication().getExpressionFactory().createMethodExpression(
940 facesContext.getELContext(), method.getExpressionString(), null, clazzes);
941 value = method.invoke(facesContext.getELContext(), parameters);
942 }
943 else
944 {
945 value = method.invoke(facesContext.getELContext(), null);
946 }
947 return value;
948 }
949
950 private NavigationCase getNavigationCaseFromFlowStructure(FacesContext facesContext,
951 _FlowNavigationStructure flowNavigationStructure, String fromAction, String outcome, String viewId)
952 {
953 Set<NavigationCase> casesSet = null;
954 NavigationCase navigationCase = null;
955
956 if (viewId != null)
957 {
958 casesSet = flowNavigationStructure.getNavigationCases().get(viewId);
959 if (casesSet != null)
960 {
961
962 navigationCase = calcMatchingNavigationCase(facesContext, casesSet, fromAction, outcome);
963 }
964 }
965 if (navigationCase == null)
966 {
967 List<_WildcardPattern> wildcardPatterns = flowNavigationStructure.getWildcardKeys();
968 for (int i = 0; i < wildcardPatterns.size(); i++)
969 {
970 _WildcardPattern wildcardPattern = wildcardPatterns.get(i);
971 if (wildcardPattern.match(viewId))
972 {
973 casesSet = flowNavigationStructure.getNavigationCases().get(wildcardPattern.getPattern());
974 if (casesSet != null)
975 {
976 navigationCase = calcMatchingNavigationCase(facesContext, casesSet, fromAction, outcome);
977 if (navigationCase != null)
978 {
979 break;
980 }
981 }
982 }
983 }
984 }
985 return navigationCase;
986 }
987
988
989
990
991
992
993
994 private NavigationCase createNavigationCase(String fromViewId, String outcome, String toViewId)
995 {
996 return new NavigationCase(fromViewId, null, outcome, null, toViewId, null, false, false);
997 }
998
999 private NavigationCase createNavigationCase(String fromViewId, String outcome,
1000 String toViewId, String toFlowDocumentId)
1001 {
1002 return new NavigationCase(fromViewId, null, outcome, null, toViewId,
1003 toFlowDocumentId, null, false, false);
1004 }
1005
1006
1007
1008
1009
1010
1011
1012 private NavigationCase getOutcomeNavigationCase (FacesContext facesContext, String fromAction, String outcome)
1013 {
1014 String implicitViewId = null;
1015 boolean includeViewParams = false;
1016 int index;
1017 boolean isRedirect = false;
1018 String queryString = null;
1019 NavigationCase result = null;
1020 String viewId = facesContext.getViewRoot() != null ? facesContext.getViewRoot().getViewId() : null;
1021
1022 StringBuilder viewIdToTest = SharedStringBuilder.get(facesContext, OUTCOME_NAVIGATION_SB);
1023 viewIdToTest.append(outcome);
1024
1025
1026 index = viewIdToTest.indexOf ("?");
1027 if (index != -1)
1028 {
1029 queryString = viewIdToTest.substring (index + 1);
1030
1031 viewIdToTest.setLength(index);
1032
1033
1034 if (queryString.indexOf ("faces-redirect=true") != -1)
1035 {
1036 isRedirect = true;
1037 }
1038
1039
1040
1041 if (queryString.indexOf("includeViewParams=true") != -1
1042 || queryString.indexOf("faces-include-view-params=true") != -1)
1043 {
1044 includeViewParams = true;
1045 }
1046 }
1047
1048
1049 index = viewIdToTest.indexOf (".");
1050 if (index == -1)
1051 {
1052 if (viewId != null)
1053 {
1054 index = viewId.lastIndexOf('.');
1055
1056 if (index != -1)
1057 {
1058
1059 viewIdToTest.append(viewId.substring (index));
1060 }
1061 }
1062 else
1063 {
1064
1065
1066
1067
1068
1069
1070
1071
1072 String tempViewId = getNavigationHandlerSupport().calculateViewId(facesContext);
1073 if (tempViewId != null)
1074 {
1075 index = tempViewId.lastIndexOf('.');
1076 if(index != -1)
1077 {
1078 viewIdToTest.append(tempViewId.substring (index));
1079 }
1080 }
1081 }
1082 if (log.isLoggable(Level.FINEST))
1083 {
1084 log.finest("getOutcomeNavigationCase -> viewIdToTest: " + viewIdToTest);
1085 }
1086 }
1087
1088
1089
1090
1091
1092 boolean startWithSlash = false;
1093 if (viewIdToTest.length() > 0)
1094 {
1095 startWithSlash = (viewIdToTest.charAt(0) == '/');
1096 }
1097 if (!startWithSlash)
1098 {
1099 index = -1;
1100 if( viewId != null )
1101 {
1102 index = viewId.lastIndexOf('/');
1103 }
1104
1105 if (index == -1)
1106 {
1107
1108 viewIdToTest.insert(0,"/");
1109 }
1110
1111 else
1112 {
1113
1114 viewIdToTest.insert(0, viewId, 0, index + 1);
1115 }
1116 }
1117
1118
1119 String viewIdToTestString = null;
1120 boolean applyNormalization = false;
1121
1122 for (int i = 0; i < viewIdToTest.length()-1; i++)
1123 {
1124 if (viewIdToTest.charAt(i) == '.' &&
1125 viewIdToTest.charAt(i+1) == '/')
1126 {
1127 applyNormalization = true;
1128 break;
1129 }
1130 }
1131 if (applyNormalization)
1132 {
1133 viewIdToTestString = FilenameUtils.normalize(viewIdToTest.toString(), true);
1134 }
1135 else
1136 {
1137 viewIdToTestString = viewIdToTest.toString();
1138 }
1139
1140
1141 try
1142 {
1143 implicitViewId = facesContext.getApplication().getViewHandler().deriveViewId (
1144 facesContext, viewIdToTestString);
1145 }
1146
1147 catch (UnsupportedOperationException e)
1148 {
1149
1150
1151
1152
1153 }
1154
1155 if (implicitViewId != null)
1156 {
1157
1158
1159 Map<String, List<String>> params = null;
1160 if (queryString != null && !"".equals(queryString))
1161 {
1162
1163 String[] splitQueryParams = AMP_PATTERN.split(queryString);
1164 params = new HashMap<String, List<String>>(splitQueryParams.length,
1165 (splitQueryParams.length* 4 + 3) / 3);
1166 for (String queryParam : splitQueryParams)
1167 {
1168 String[] splitParam = StringUtils.splitShortString(queryParam, '=');
1169 if (splitParam.length == 2)
1170 {
1171
1172 if ("includeViewParams".equals(splitParam[0])
1173 || "faces-include-view-params".equals(splitParam[0])
1174 || "faces-redirect".equals(splitParam[0]))
1175 {
1176
1177 continue;
1178 }
1179 List<String> paramValues = params.get(splitParam[0]);
1180 if (paramValues == null)
1181 {
1182
1183 paramValues = new ArrayList<String>();
1184 params.put(splitParam[0], paramValues);
1185 }
1186 paramValues.add(splitParam[1]);
1187 }
1188 else
1189 {
1190
1191 throw new FacesException("Invalid parameter \"" +
1192 queryParam + "\" in outcome " + outcome);
1193 }
1194 }
1195 }
1196
1197
1198 result = new NavigationCase (viewId, fromAction, outcome, null,
1199 implicitViewId, params, isRedirect, includeViewParams);
1200 }
1201
1202 return result;
1203 }
1204
1205
1206
1207
1208 public String getViewId(FacesContext context, String fromAction, String outcome)
1209 {
1210 return this.getNavigationCase(context, fromAction, outcome).getToViewId(context);
1211 }
1212
1213
1214
1215
1216
1217
1218
1219
1220 public String beforeNavigation(String viewId)
1221 {
1222 return null;
1223 }
1224
1225 private NavigationCase calcMatchingNavigationCase(FacesContext context,
1226 Set<? extends NavigationCase> casesList,
1227 String actionRef,
1228 String outcome)
1229 {
1230 NavigationCase noConditionCase = null;
1231 NavigationCase firstCase = null;
1232 NavigationCase firstCaseIf = null;
1233 NavigationCase secondCase = null;
1234 NavigationCase secondCaseIf = null;
1235 NavigationCase thirdCase = null;
1236 NavigationCase thirdCaseIf = null;
1237 NavigationCase fourthCase = null;
1238 NavigationCase fourthCaseIf = null;
1239
1240 for (NavigationCase caze : casesList)
1241 {
1242 String cazeOutcome = caze.getFromOutcome();
1243 String cazeActionRef = caze.getFromAction();
1244 Boolean cazeIf = caze.getCondition(context);
1245 boolean ifMatches = (cazeIf == null ? false : cazeIf.booleanValue());
1246
1247
1248
1249 if(outcome == null && (cazeOutcome != null || cazeIf == null) && actionRef == null)
1250 {
1251
1252 continue;
1253 }
1254
1255
1256 if (cazeOutcome == null && cazeActionRef == null &&
1257 cazeIf == null && noConditionCase == null && outcome != null)
1258 {
1259 noConditionCase = caze;
1260 }
1261
1262 if (cazeActionRef != null)
1263 {
1264 if (cazeOutcome != null)
1265 {
1266 if ((actionRef != null) && (outcome != null) && cazeActionRef.equals (actionRef) &&
1267 cazeOutcome.equals (outcome))
1268 {
1269
1270
1271
1272 if (cazeIf != null)
1273 {
1274 if (ifMatches)
1275 {
1276 firstCaseIf = caze;
1277
1278 }
1279
1280 continue;
1281 }
1282 else
1283 {
1284 firstCase = caze;
1285
1286 }
1287 }
1288 }
1289 else
1290 {
1291 if ((actionRef != null) && cazeActionRef.equals (actionRef))
1292 {
1293
1294
1295
1296 if (cazeIf != null)
1297 {
1298 if (ifMatches)
1299 {
1300 thirdCaseIf = caze;
1301
1302 }
1303
1304 continue;
1305 }
1306 else
1307 {
1308 if (outcome != null)
1309 {
1310 thirdCase = caze;
1311
1312 }
1313
1314 continue;
1315 }
1316 }
1317 else
1318 {
1319
1320
1321
1322
1323 continue;
1324 }
1325 }
1326 }
1327 else
1328 {
1329 if (cazeOutcome != null && (outcome != null) && cazeOutcome.equals (outcome))
1330 {
1331
1332
1333
1334 if (cazeIf != null)
1335 {
1336 if (ifMatches)
1337 {
1338 secondCaseIf = caze;
1339
1340 }
1341
1342 continue;
1343 }
1344 else
1345 {
1346 secondCase = caze;
1347
1348 }
1349 }
1350 }
1351
1352
1353
1354 if (outcome != null && cazeIf != null)
1355 {
1356
1357 if (ifMatches)
1358 {
1359 fourthCaseIf = caze;
1360
1361 }
1362
1363 continue;
1364 }
1365
1366 if ((cazeIf != null) && ifMatches)
1367 {
1368 fourthCase = caze;
1369
1370 }
1371 }
1372
1373 if (firstCaseIf != null)
1374 {
1375 return firstCaseIf;
1376 }
1377 else if (firstCase != null)
1378 {
1379 return firstCase;
1380 }
1381 else if (secondCaseIf != null)
1382 {
1383 return secondCaseIf;
1384 }
1385 else if (secondCase != null)
1386 {
1387 return secondCase;
1388 }
1389 else if (thirdCaseIf != null)
1390 {
1391 return thirdCaseIf;
1392 }
1393 else if (thirdCase != null)
1394 {
1395 return thirdCase;
1396 }
1397 else if (fourthCaseIf != null)
1398 {
1399 return fourthCaseIf;
1400 }
1401 else if (fourthCase != null)
1402 {
1403 return fourthCase;
1404 }
1405
1406 return noConditionCase;
1407 }
1408
1409 private List<_WildcardPattern> getSortedWildcardPatterns()
1410 {
1411 return _wildcardPatterns;
1412 }
1413
1414 @Override
1415 public Map<String, Set<NavigationCase>> getNavigationCases()
1416 {
1417 if (_developmentStage == null)
1418 {
1419 _developmentStage = FacesContext.getCurrentInstance().isProjectStage(ProjectStage.Development);
1420 }
1421 if (!Boolean.TRUE.equals(_developmentStage))
1422 {
1423 if (_navigationCases == null)
1424 {
1425 FacesContext facesContext = FacesContext.getCurrentInstance();
1426 ExternalContext externalContext = facesContext.getExternalContext();
1427 RuntimeConfig runtimeConfig = RuntimeConfig.getCurrentInstance(externalContext);
1428
1429 calculateNavigationCases(runtimeConfig);
1430 }
1431 return _navigationCases;
1432 }
1433 else
1434 {
1435 FacesContext facesContext = FacesContext.getCurrentInstance();
1436 ExternalContext externalContext = facesContext.getExternalContext();
1437 RuntimeConfig runtimeConfig = RuntimeConfig.getCurrentInstance(externalContext);
1438
1439 if (_navigationCases == null || runtimeConfig.isNavigationRulesChanged())
1440 {
1441 calculateNavigationCases(runtimeConfig);
1442 }
1443 return _navigationCases;
1444 }
1445 }
1446
1447 @Override
1448 public void inspectFlow(FacesContext context, Flow flow)
1449 {
1450 Map<String, Set<NavigationCase>> rules = flow.getNavigationCases();
1451 int rulesSize = rules.size();
1452
1453 Map<String, Set<NavigationCase>> cases = new HashMap<String, Set<NavigationCase>>(
1454 HashMapUtils.calcCapacity(rulesSize));
1455
1456 List<_WildcardPattern> wildcardPatterns = new ArrayList<_WildcardPattern>();
1457
1458 for (Map.Entry<String, Set<NavigationCase>> entry : rules.entrySet())
1459 {
1460 String fromViewId = entry.getKey();
1461
1462
1463 if (fromViewId == null)
1464 {
1465 fromViewId = ASTERISK;
1466 }
1467 else
1468 {
1469 fromViewId = fromViewId.trim();
1470 }
1471
1472 Set<NavigationCase> set = cases.get(fromViewId);
1473 if (set == null)
1474 {
1475 set = new HashSet<NavigationCase>(entry.getValue());
1476 cases.put(fromViewId, set);
1477 if (fromViewId.endsWith(ASTERISK))
1478 {
1479 wildcardPatterns.add(new _WildcardPattern(fromViewId));
1480 }
1481 }
1482 else
1483 {
1484 set.addAll(entry.getValue());
1485 }
1486 }
1487
1488 Collections.sort(wildcardPatterns, new KeyComparator());
1489
1490 _flowNavigationStructureMap.put(
1491 flow.getId(),
1492 new _FlowNavigationStructure(flow.getDefiningDocumentId(), flow.getId(), cases, wildcardPatterns) );
1493 }
1494
1495 private synchronized void calculateNavigationCases(RuntimeConfig runtimeConfig)
1496 {
1497 if (_navigationCases == null || runtimeConfig.isNavigationRulesChanged())
1498 {
1499 Collection<? extends NavigationRule> rules = runtimeConfig.getNavigationRules();
1500 int rulesSize = rules.size();
1501
1502 Map<String, Set<NavigationCase>> cases = new HashMap<String, Set<NavigationCase>>(
1503 HashMapUtils.calcCapacity(rulesSize));
1504
1505 List<_WildcardPattern> wildcardPatterns = new ArrayList<_WildcardPattern>();
1506
1507 for (NavigationRule rule : rules)
1508 {
1509 String fromViewId = rule.getFromViewId();
1510
1511
1512 if (fromViewId == null)
1513 {
1514 fromViewId = ASTERISK;
1515 }
1516 else
1517 {
1518 fromViewId = fromViewId.trim();
1519 }
1520
1521 Set<NavigationCase> set = cases.get(fromViewId);
1522 if (set == null)
1523 {
1524 set = new HashSet<NavigationCase>(convertNavigationCasesToAPI(rule));
1525 cases.put(fromViewId, set);
1526 if (fromViewId.endsWith(ASTERISK))
1527 {
1528 wildcardPatterns.add(new _WildcardPattern(fromViewId));
1529 }
1530 }
1531 else
1532 {
1533 set.addAll(convertNavigationCasesToAPI(rule));
1534 }
1535 }
1536
1537 Collections.sort(wildcardPatterns, new KeyComparator());
1538
1539 synchronized (cases)
1540 {
1541
1542
1543
1544
1545 _navigationCases = cases;
1546 _wildcardPatterns = wildcardPatterns;
1547
1548 runtimeConfig.setNavigationRulesChanged(false);
1549 }
1550 }
1551 }
1552
1553 private static final class KeyComparator implements Comparator<_WildcardPattern>
1554 {
1555 public int compare(_WildcardPattern s1, _WildcardPattern s2)
1556 {
1557 return -s1.getPattern().compareTo(s2.getPattern());
1558 }
1559 }
1560
1561 private Set<NavigationCase> convertNavigationCasesToAPI(NavigationRule rule)
1562 {
1563 Collection<? extends org.apache.myfaces.config.element.NavigationCase> configCases = rule.getNavigationCases();
1564 Set<NavigationCase> apiCases = new HashSet<NavigationCase>(configCases.size());
1565
1566 for(org.apache.myfaces.config.element.NavigationCase configCase : configCases)
1567 {
1568 if(configCase.getRedirect() != null)
1569 {
1570 String includeViewParamsAttribute = configCase.getRedirect().getIncludeViewParams();
1571 boolean includeViewParams = false;
1572 if (includeViewParamsAttribute != null)
1573 {
1574 includeViewParams = Boolean.valueOf(includeViewParamsAttribute);
1575 }
1576 apiCases.add(new NavigationCase(rule.getFromViewId(),configCase.getFromAction(),
1577 configCase.getFromOutcome(),configCase.getIf(),configCase.getToViewId(),
1578 configCase.getRedirect().getViewParams(),true,includeViewParams));
1579 }
1580 else
1581 {
1582 apiCases.add(new NavigationCase(rule.getFromViewId(),configCase.getFromAction(),
1583 configCase.getFromOutcome(),configCase.getIf(),
1584 configCase.getToViewId(),null,false,false));
1585 }
1586 }
1587
1588 return apiCases;
1589 }
1590
1591
1592
1593
1594
1595
1596
1597
1598 protected static class NavigationContext
1599 {
1600 private NavigationCase navigationCase;
1601 private List<Flow> sourceFlows;
1602 private List<Flow> targetFlows;
1603 private List<FlowCallNode> targetFlowCallNodes;
1604 private List<Flow> currentFlows;
1605 private int returnCount = 0;
1606
1607 public NavigationContext()
1608 {
1609 }
1610
1611 public NavigationContext(NavigationCase navigationCase)
1612 {
1613 this.navigationCase = navigationCase;
1614 }
1615
1616 public NavigationCase getNavigationCase()
1617 {
1618 return navigationCase;
1619 }
1620
1621 public void setNavigationCase(NavigationCase navigationCase)
1622 {
1623 this.navigationCase = navigationCase;
1624 }
1625
1626 public List<Flow> getSourceFlows()
1627 {
1628 return sourceFlows;
1629 }
1630
1631 public List<Flow> getTargetFlows()
1632 {
1633 return targetFlows;
1634 }
1635
1636 public List<FlowCallNode> getFlowCallNodes()
1637 {
1638 return targetFlowCallNodes;
1639 }
1640
1641 public void addTargetFlow(Flow sourceFlow, Flow targetFlow, FlowCallNode flowCallNode)
1642 {
1643 if (targetFlows == null)
1644 {
1645 sourceFlows = new ArrayList<Flow>(4);
1646 targetFlows = new ArrayList<Flow>(4);
1647 targetFlowCallNodes = new ArrayList<FlowCallNode>(4);
1648 }
1649 this.sourceFlows.add(sourceFlow);
1650 this.targetFlows.add(targetFlow);
1651 this.targetFlowCallNodes.add(flowCallNode);
1652 }
1653
1654 public Flow getCurrentFlow(FacesContext facesContext)
1655 {
1656 if (currentFlows != null && !currentFlows.isEmpty())
1657 {
1658 return currentFlows.get(currentFlows.size()-1);
1659 }
1660 else
1661 {
1662 FlowHandler flowHandler = facesContext.getApplication().getFlowHandler();
1663 return flowHandler.getCurrentFlow(facesContext);
1664 }
1665 }
1666
1667 public void finish(FacesContext facesContext)
1668 {
1669
1670 for (int i=0; i < returnCount; i++)
1671 {
1672 FlowHandler flowHandler = facesContext.getApplication().getFlowHandler();
1673 flowHandler.popReturnMode(facesContext);
1674 }
1675 returnCount = 0;
1676 }
1677
1678 public void popFlow(FacesContext facesContext)
1679 {
1680 if (currentFlows != null && !currentFlows.isEmpty())
1681 {
1682 currentFlows.remove(currentFlows.size()-1);
1683 }
1684 else
1685 {
1686 FlowHandler flowHandler = facesContext.getApplication().getFlowHandler();
1687 flowHandler.pushReturnMode(facesContext);
1688 returnCount++;
1689 }
1690 }
1691
1692 public void pushFlow(FacesContext facesContext, Flow flow)
1693 {
1694 if (currentFlows == null)
1695 {
1696 currentFlows = new ArrayList<Flow>();
1697 }
1698 currentFlows.add(flow);
1699 }
1700
1701 public String getLastDisplayedViewId(FacesContext facesContext, Flow flow)
1702 {
1703 FlowHandler flowHandler = facesContext.getApplication().getFlowHandler();
1704 return flowHandler.getLastDisplayedViewId(facesContext);
1705 }
1706 }
1707 }