1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.flow;
20
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.concurrent.ConcurrentHashMap;
27 import javax.faces.FacesWrapper;
28 import javax.faces.application.ConfigurableNavigationHandler;
29 import javax.faces.application.NavigationCase;
30 import javax.faces.application.NavigationHandler;
31 import javax.faces.application.NavigationHandlerWrapper;
32 import javax.faces.context.FacesContext;
33 import javax.faces.event.SystemEvent;
34 import javax.faces.event.SystemEventListener;
35 import javax.faces.flow.Flow;
36 import javax.faces.flow.FlowCallNode;
37 import javax.faces.flow.FlowHandler;
38 import javax.faces.flow.FlowNode;
39 import javax.faces.flow.Parameter;
40 import javax.faces.flow.ReturnNode;
41 import javax.faces.lifecycle.ClientWindow;
42 import org.apache.myfaces.event.PostClientWindowAndViewInitializedEvent;
43 import org.apache.myfaces.spi.FacesFlowProvider;
44 import org.apache.myfaces.spi.FacesFlowProviderFactory;
45
46
47
48
49
50
51 public class FlowHandlerImpl extends FlowHandler implements SystemEventListener
52 {
53 private final static String CURRENT_FLOW_STACK = "oam.flow.STACK.";
54 private final static String ROOT_LAST_VIEW_ID = "oam.flow.ROOT_LAST_VIEW_ID.";
55
56 private final static String RETURN_MODE = "oam.flow.RETURN_MODE";
57 private final static String FLOW_RETURN_STACK = "oam.flow.RETURN_STACK.";
58 private final static String CURRENT_FLOW_REQUEST_STACK = "oam.flow.REQUEST_STACK.";
59
60 private Map<String, Map<String, Flow>> _flowMapByDocumentId;
61 private Map<String, Flow> _flowMapById;
62
63 private FacesFlowProvider _facesFlowProvider;
64
65 public FlowHandlerImpl()
66 {
67 _flowMapByDocumentId = new ConcurrentHashMap<String, Map<String, Flow>>();
68 _flowMapById = new ConcurrentHashMap<String, Flow>();
69 }
70
71 @Override
72 public Flow getFlow(FacesContext context, String definingDocumentId, String id)
73 {
74 checkNull(context, "context");
75 checkNull(definingDocumentId, "definingDocumentId");
76 checkNull(id, "id");
77
78
79 Map<String, Flow> flowMap = _flowMapByDocumentId.get(definingDocumentId);
80 if (flowMap != null)
81 {
82 Flow flow = flowMap.get(id);
83 if (flow != null)
84 {
85 return flow;
86 }
87 }
88
89
90 if ("".equals(definingDocumentId))
91 {
92 return _flowMapById.get(id);
93 }
94 return null;
95 }
96
97 @Override
98 public void addFlow(FacesContext context, Flow toAdd)
99 {
100 checkNull(context, "context");
101 checkNull(toAdd, "toAdd");
102
103 String id = toAdd.getId();
104 String definingDocumentId = toAdd.getDefiningDocumentId();
105
106 if (id == null)
107 {
108 throw new IllegalArgumentException("Flow must have a non null id");
109 }
110 else if (id.length() == 0)
111 {
112 throw new IllegalArgumentException("Flow must have a non empty id");
113 }
114 if (definingDocumentId == null)
115 {
116 throw new IllegalArgumentException("Flow must have a non null definingDocumentId");
117 }
118
119 Map<String, Flow> flowMap = _flowMapByDocumentId.get(definingDocumentId);
120 if (flowMap == null)
121 {
122 flowMap = new ConcurrentHashMap<String, Flow>();
123 _flowMapByDocumentId.put(definingDocumentId, flowMap);
124 }
125 flowMap.put(id, toAdd);
126
127 Flow duplicateFlow = _flowMapById.get(id);
128 if (duplicateFlow != null)
129 {
130
131
132 if (toAdd.getDefiningDocumentId().equals(duplicateFlow.getDefiningDocumentId()))
133 {
134 throw new IllegalArgumentException("There cannot be multiple flows with both the"
135 + " same ID and the same definingDocumentId");
136 }
137
138 else if ("".equals(toAdd.getDefiningDocumentId()))
139 {
140 _flowMapById.put(id, toAdd);
141 }
142 else if ("".equals(duplicateFlow.getDefiningDocumentId()))
143 {
144
145 }
146 else
147 {
148
149 _flowMapById.put(id, toAdd);
150 }
151 }
152 else
153 {
154 _flowMapById.put(id, toAdd);
155 }
156
157
158
159
160
161
162
163 invokeInspectFlow(context, context.getApplication().getNavigationHandler(), toAdd);
164 }
165
166 @Override
167 public Flow getCurrentFlow(FacesContext context)
168 {
169 Object session = context.getExternalContext().getSession(false);
170 if (session == null)
171 {
172 return null;
173 }
174 ClientWindow clientWindow = context.getExternalContext().getClientWindow();
175 if (clientWindow == null)
176 {
177 return null;
178 }
179
180
181 _FlowContextualInfo info = getCurrentFlowReference(context, clientWindow);
182 if (info == null)
183 {
184 return null;
185 }
186 FlowReference flowReference = info.getFlowReference();
187 return getFlow(context, flowReference.getDocumentId(), flowReference.getId());
188 }
189
190 @Override
191 public void transition(FacesContext context, Flow sourceFlow, Flow targetFlow,
192 FlowCallNode outboundCallNode, String toViewId)
193 {
194 checkNull(context, "context");
195 checkNull(toViewId, "toViewId");
196 ClientWindow clientWindow = context.getExternalContext().getClientWindow();
197 boolean outboundCallNodeProcessed = false;
198 if (clientWindow == null)
199 {
200 return;
201 }
202
203 if (sourceFlow == null && targetFlow == null)
204 {
205 return;
206 }
207
208
209 FlowReference parentFlowReference = (outboundCallNode != null && sourceFlow != null) ?
210 new FlowReference(sourceFlow.getDefiningDocumentId(), sourceFlow.getId()) : null;
211
212 if (sourceFlow == null)
213 {
214
215 Map<String, Object> outboundParameters = doBeforeEnterFlow(context,
216 targetFlow, !outboundCallNodeProcessed ? outboundCallNode : null);
217 outboundCallNodeProcessed = true;
218 pushFlowReference(context, clientWindow,
219 new FlowReference(targetFlow.getDefiningDocumentId(), targetFlow.getId()),
220 toViewId, parentFlowReference);
221 doAfterEnterFlow(context, targetFlow, outboundParameters);
222 }
223 else if (targetFlow == null)
224 {
225
226
227 List<_FlowContextualInfo> currentFlowStack = getCurrentFlowStack(context, clientWindow);
228 if (currentFlowStack != null)
229 {
230 removeFlowFromStack(context, currentFlowStack, sourceFlow);
231 }
232 }
233 else
234 {
235
236
237
238
239 List<_FlowContextualInfo> currentFlowStack = getCurrentFlowStack(context, clientWindow);
240 if (currentFlowStack != null && outboundCallNode == null)
241 {
242 FlowReference targetFlowReference = new FlowReference(
243 targetFlow.getDefiningDocumentId(), targetFlow.getId());
244 int targetFlowIndex = -1;
245 for (int j = currentFlowStack.size()-1; j >= 0; j--)
246 {
247 if (targetFlowReference.equals(currentFlowStack.get(j).getFlowReference()))
248 {
249 targetFlowIndex = j;
250 break;
251 }
252 }
253 if (targetFlowIndex >= 0)
254 {
255
256 removeFlowFromStack(context, currentFlowStack, sourceFlow);
257 }
258 else
259 {
260
261 Map<String, Object> outboundParameters = doBeforeEnterFlow(context,
262 targetFlow, !outboundCallNodeProcessed ? outboundCallNode : null);
263 outboundCallNodeProcessed = true;
264 pushFlowReference(context, clientWindow,
265 new FlowReference(targetFlow.getDefiningDocumentId(), targetFlow.getId()), toViewId,
266 parentFlowReference);
267 doAfterEnterFlow(context, targetFlow, outboundParameters);
268 }
269 }
270 else
271 {
272
273
274 Map<String, Object> outboundParameters = doBeforeEnterFlow(context,
275 targetFlow, !outboundCallNodeProcessed ? outboundCallNode : null);
276 outboundCallNodeProcessed = true;
277 pushFlowReference(context, clientWindow,
278 new FlowReference(targetFlow.getDefiningDocumentId(), targetFlow.getId()), toViewId,
279 parentFlowReference);
280 doAfterEnterFlow(context, targetFlow, outboundParameters);
281 }
282 }
283 }
284
285 private void removeFlowFromStack(FacesContext context, List<_FlowContextualInfo> currentFlowStack, Flow sourceFlow)
286 {
287
288
289 int sourceFlowIndex = -1;
290 FlowReference sourceFlowReference = new FlowReference(sourceFlow.getDefiningDocumentId(),
291 sourceFlow.getId());
292 List<_FlowContextualInfo> flowsToRemove = new ArrayList<_FlowContextualInfo>();
293 for (int i = currentFlowStack.size()-1; i >= 0; i--)
294 {
295 _FlowContextualInfo fci = currentFlowStack.get(i);
296 if (fci.getFlowReference().equals(sourceFlowReference))
297 {
298 sourceFlowIndex = i;
299 flowsToRemove.add(fci);
300 break;
301 }
302 }
303
304 if (sourceFlowIndex != -1)
305 {
306
307 traverseDependantFlows(sourceFlowReference, sourceFlowIndex+1, currentFlowStack, flowsToRemove);
308
309
310 if (!flowsToRemove.isEmpty())
311 {
312 for (int i = flowsToRemove.size()-1; i >= 0; i--)
313 {
314 _FlowContextualInfo fci = flowsToRemove.get(i);
315 FlowReference fr = fci.getFlowReference();
316 doBeforeExitFlow(context, getFlow(context, fr.getDocumentId(), fr.getId()));
317
318
319
320 for (int j = currentFlowStack.size()-1; j >= 0; j--)
321 {
322 if (currentFlowStack.get(j) == fci)
323 {
324 currentFlowStack.remove(j);
325 break;
326 }
327 }
328 }
329 }
330
331 if (currentFlowStack.isEmpty())
332 {
333
334 context.getAttributes().put(ROOT_LAST_VIEW_ID,
335 context.getExternalContext().getSessionMap().remove(ROOT_LAST_VIEW_ID +
336 context.getExternalContext().getClientWindow().getId()));
337 }
338 }
339 }
340
341 private void traverseDependantFlows(FlowReference sourceFlowReference,
342 int index, List<_FlowContextualInfo> currentFlowStack, List<_FlowContextualInfo> flowsToRemove)
343 {
344 if (index < currentFlowStack.size())
345 {
346 for (int i = index; i < currentFlowStack.size(); i++)
347 {
348 _FlowContextualInfo info = currentFlowStack.get(i);
349 if (sourceFlowReference.equals(info.getSourceFlowReference()) &&
350 !flowsToRemove.contains(info))
351 {
352 flowsToRemove.add(info);
353 traverseDependantFlows(info.getFlowReference(), i+1, currentFlowStack, flowsToRemove);
354 }
355 }
356 }
357 }
358
359 private Map<String, Object> doBeforeEnterFlow(FacesContext context, Flow flow, FlowCallNode outboundCallNode)
360 {
361 Map<String, Object> outboundParameters = null;
362 if (outboundCallNode != null && !outboundCallNode.getOutboundParameters().isEmpty())
363 {
364 outboundParameters = new HashMap<String, Object>();
365 for (Map.Entry<String, Parameter> entry : outboundCallNode.getOutboundParameters().entrySet())
366 {
367 Parameter parameter = entry.getValue();
368 if (parameter.getValue() != null)
369 {
370 outboundParameters.put(entry.getKey(), parameter.getValue().getValue(context.getELContext()));
371 }
372 }
373 }
374 return outboundParameters;
375 }
376
377 private void doAfterEnterFlow(FacesContext context, Flow flow, Map<String, Object> outboundParameters)
378 {
379 getFacesFlowProvider(context).doAfterEnterFlow(context, flow);
380
381 if (outboundParameters != null)
382 {
383 for (Map.Entry<String, Parameter> entry : flow.getInboundParameters().entrySet())
384 {
385 Parameter parameter = entry.getValue();
386 if (parameter.getValue() != null && outboundParameters.containsKey(entry.getKey()))
387 {
388 parameter.getValue().setValue(context.getELContext(), outboundParameters.get(entry.getKey()));
389 }
390 }
391 }
392
393 if (flow.getInitializer() != null)
394 {
395 flow.getInitializer().invoke(context.getELContext(), null);
396 }
397 }
398
399 public FacesFlowProvider getFacesFlowProvider(FacesContext facesContext)
400 {
401 if (_facesFlowProvider == null)
402 {
403 FacesFlowProviderFactory factory =
404 FacesFlowProviderFactory.getFacesFlowProviderFactory(
405 facesContext.getExternalContext());
406 _facesFlowProvider = factory.getFacesFlowProvider(
407 facesContext.getExternalContext());
408
409 facesContext.getApplication().unsubscribeFromEvent(PostClientWindowAndViewInitializedEvent.class, this);
410 facesContext.getApplication().subscribeToEvent(PostClientWindowAndViewInitializedEvent.class, this);
411 }
412 return _facesFlowProvider;
413 }
414
415 private void doBeforeExitFlow(FacesContext context, Flow flow)
416 {
417 if (flow.getFinalizer() != null)
418 {
419 flow.getFinalizer().invoke(context.getELContext(), null);
420 }
421
422 getFacesFlowProvider(context).doBeforeExitFlow(context, flow);
423 }
424
425 @Override
426 public boolean isActive(FacesContext context, String definingDocumentId, String id)
427 {
428 checkNull(context, "context");
429 checkNull(definingDocumentId, "definingDocumentId");
430 checkNull(id, "id");
431
432 Object session = context.getExternalContext().getSession(false);
433 if (session == null)
434 {
435 return false;
436 }
437 ClientWindow clientWindow = context.getExternalContext().getClientWindow();
438 if (clientWindow == null)
439 {
440 return false;
441 }
442 Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
443 String currentFlowMapKey = CURRENT_FLOW_STACK + clientWindow.getId();
444
445 List<_FlowContextualInfo> currentFlowStack = (List<_FlowContextualInfo>) sessionMap.get(currentFlowMapKey);
446 if (currentFlowStack == null)
447 {
448 return false;
449 }
450 FlowReference reference = new FlowReference(definingDocumentId, id);
451
452 for (_FlowContextualInfo info : currentFlowStack)
453 {
454 if (reference.equals(info.getFlowReference()))
455 {
456 return true;
457 }
458 }
459 return false;
460 }
461
462 @Override
463 public Map<Object, Object> getCurrentFlowScope()
464 {
465 FacesContext facesContext = FacesContext.getCurrentInstance();
466 return getFacesFlowProvider(facesContext).getCurrentFlowScope(facesContext);
467 }
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499 @Override
500 public void clientWindowTransition(FacesContext context)
501 {
502 String flowDocumentIdRequestParam = (String) context.getExternalContext().
503 getRequestParameterMap().get(FlowHandler.TO_FLOW_DOCUMENT_ID_REQUEST_PARAM_NAME);
504
505 if (flowDocumentIdRequestParam != null)
506 {
507 String flowIdRequestParam = (String) context.getExternalContext().
508 getRequestParameterMap().get(FlowHandler.FLOW_ID_REQUEST_PARAM_NAME);
509
510 if (flowIdRequestParam == null)
511 {
512
513
514 return;
515 }
516
517 FlowHandler flowHandler = context.getApplication().getFlowHandler();
518 ConfigurableNavigationHandler nh =
519 (ConfigurableNavigationHandler) context.getApplication().getNavigationHandler();
520
521 if (FlowHandler.NULL_FLOW.equals(flowDocumentIdRequestParam))
522 {
523
524
525
526 String toFlowDocumentId = FlowHandler.NULL_FLOW;
527 String fromOutcome = flowIdRequestParam;
528
529 List<Flow> sourceFlows = null;
530 List<Flow> targetFlows = null;
531
532 boolean failed = false;
533 int i = 0;
534 while (FlowHandler.NULL_FLOW.equals(toFlowDocumentId) && !failed)
535 {
536 Flow currentFlow = flowHandler.getCurrentFlow(context);
537 if (currentFlow == null)
538 {
539 failed = true;
540 break;
541 }
542 String currentLastDisplayedViewId = flowHandler.getLastDisplayedViewId(context);
543 FlowNode node = currentFlow.getNode(fromOutcome);
544 if (node instanceof ReturnNode)
545 {
546 if (targetFlows == null)
547 {
548 sourceFlows = new ArrayList<Flow>(4);
549 targetFlows = new ArrayList<Flow>(4);
550 }
551
552 Flow sourceFlow = currentFlow;
553 flowHandler.pushReturnMode(context);
554 currentFlow = flowHandler.getCurrentFlow(context);
555 i++;
556
557 NavigationCase navCase = nh.getNavigationCase(context, null,
558 ((ReturnNode) node).getFromOutcome(context), FlowHandler.NULL_FLOW);
559
560 if (navCase == null)
561 {
562 if (currentLastDisplayedViewId != null)
563 {
564 sourceFlows.add(sourceFlow);
565 if (currentFlow != null)
566 {
567 toFlowDocumentId = currentFlow.getDefiningDocumentId();
568 targetFlows.add(currentFlow);
569 }
570 else
571 {
572
573 toFlowDocumentId = null;
574 targetFlows.add(null);
575 }
576 }
577 else
578 {
579
580
581 failed = true;
582 }
583 }
584 else
585 {
586 if (FlowHandler.NULL_FLOW.equals(navCase.getToFlowDocumentId()))
587 {
588 fromOutcome = navCase.getFromOutcome();
589 }
590 else
591 {
592 sourceFlows.add(sourceFlow);
593
594 if (currentFlow != null)
595 {
596 toFlowDocumentId = currentFlow.getDefiningDocumentId();
597 targetFlows.add(currentFlow);
598 }
599 else
600 {
601
602 toFlowDocumentId = null;
603 targetFlows.add(null);
604 }
605 }
606 }
607 }
608 else
609 {
610
611
612 flowHandler.pushReturnMode(context);
613 currentFlow = flowHandler.getCurrentFlow(context);
614 i++;
615 if (currentFlow == null)
616 {
617 failed = true;
618 }
619 }
620 }
621 for (int j = 0; j<i; j++)
622 {
623 flowHandler.popReturnMode(context);
624 }
625 if (!failed)
626 {
627
628 for (int j = 0; j < targetFlows.size(); j++)
629 {
630 Flow sourceFlow = sourceFlows.get(j);
631 Flow targetFlow = targetFlows.get(j);
632 flowHandler.transition(context,
633 sourceFlow,
634 targetFlow, null, context.getViewRoot().getViewId());
635
636 }
637 }
638 }
639 else
640 {
641
642
643
644
645 Flow targetFlow = flowHandler.getFlow(context, flowDocumentIdRequestParam, flowIdRequestParam);
646 Flow currentFlow = null;
647 FlowCallNode outboundCallNode = null;
648 FlowNode node = null;
649 if (targetFlow == null)
650 {
651
652 List<Flow> activeFlows = FlowHandlerImpl.getActiveFlows(context, flowHandler);
653 for (Flow activeFlow : activeFlows)
654 {
655 node = activeFlow != null ? activeFlow.getNode(flowIdRequestParam) : null;
656 if (node != null && node instanceof FlowCallNode)
657 {
658 outboundCallNode = (FlowCallNode) node;
659
660 String calledFlowDocumentId = outboundCallNode.getCalledFlowDocumentId(context);
661 if (calledFlowDocumentId == null)
662 {
663 calledFlowDocumentId = activeFlow.getDefiningDocumentId();
664 }
665 targetFlow = flowHandler.getFlow(context,
666 calledFlowDocumentId,
667 outboundCallNode.getCalledFlowId(context));
668 if (targetFlow == null && !"".equals(calledFlowDocumentId))
669 {
670 targetFlow = flowHandler.getFlow(context, "",
671 outboundCallNode.getCalledFlowId(context));
672 }
673 if (targetFlow != null)
674 {
675 currentFlow = activeFlow;
676 break;
677 }
678 }
679 }
680 }
681
682 if (targetFlow != null)
683 {
684 if (flowHandler.isActive(context, targetFlow.getDefiningDocumentId(), targetFlow.getId()))
685 {
686 Flow baseReturnFlow = flowHandler.getCurrentFlow();
687 if (!(baseReturnFlow.getDefiningDocumentId().equals(targetFlow.getDefiningDocumentId()) &&
688 baseReturnFlow.getId().equals(targetFlow.getId())))
689 {
690 flowHandler.transition(context,
691 baseReturnFlow, targetFlow, outboundCallNode, context.getViewRoot().getViewId());
692 }
693 flowHandler.pushReturnMode(context);
694 Flow previousFlow = flowHandler.getCurrentFlow(context);
695 flowHandler.popReturnMode(context);
696 flowHandler.transition(context,
697 targetFlow, previousFlow, outboundCallNode, context.getViewRoot().getViewId());
698 }
699
700 flowHandler.transition(context,
701 currentFlow, targetFlow, outboundCallNode, context.getViewRoot().getViewId());
702
703
704 boolean failed = false;
705
706 String startNodeId = targetFlow.getStartNodeId();
707 while (startNodeId != null && !failed)
708 {
709 NavigationCase navCase = nh.getNavigationCase(context, null,
710 startNodeId, targetFlow.getDefiningDocumentId());
711
712 if (navCase != null && navCase.getToFlowDocumentId() != null)
713 {
714 currentFlow = flowHandler.getCurrentFlow(context);
715 node = currentFlow.getNode(navCase.getFromOutcome());
716 if (node != null && node instanceof FlowCallNode)
717 {
718 outboundCallNode = (FlowCallNode) node;
719
720 String calledFlowDocumentId = outboundCallNode.getCalledFlowDocumentId(context);
721 if (calledFlowDocumentId == null)
722 {
723 calledFlowDocumentId = currentFlow.getDefiningDocumentId();
724 }
725 targetFlow = flowHandler.getFlow(context,
726 calledFlowDocumentId,
727 outboundCallNode.getCalledFlowId(context));
728 if (targetFlow == null && !"".equals(calledFlowDocumentId))
729 {
730 targetFlow = flowHandler.getFlow(context, "",
731 outboundCallNode.getCalledFlowId(context));
732 }
733 }
734 else
735 {
736 String calledFlowDocumentId = navCase.getToFlowDocumentId();
737 if (calledFlowDocumentId == null)
738 {
739 calledFlowDocumentId = currentFlow.getDefiningDocumentId();
740 }
741 targetFlow = flowHandler.getFlow(context,
742 calledFlowDocumentId,
743 navCase.getFromOutcome());
744 if (targetFlow == null && !"".equals(calledFlowDocumentId))
745 {
746 targetFlow = flowHandler.getFlow(context, "",
747 navCase.getFromOutcome());
748 }
749 }
750 if (targetFlow != null)
751 {
752 flowHandler.transition(context,
753 currentFlow, targetFlow, outboundCallNode, context.getViewRoot().getViewId());
754 startNodeId = targetFlow.getStartNodeId();
755 }
756 else
757 {
758 startNodeId = null;
759 }
760 }
761 else
762 {
763 startNodeId = null;
764 }
765 }
766 }
767
768 }
769 }
770 }
771
772 private void checkNull(final Object o, final String param)
773 {
774 if (o == null)
775 {
776 throw new NullPointerException(param + " can not be null.");
777 }
778 }
779
780 private void invokeInspectFlow(FacesContext context, NavigationHandler navHandler, Flow toAdd)
781 {
782 if (navHandler instanceof ConfigurableNavigationHandler)
783 {
784 ((ConfigurableNavigationHandler)navHandler).inspectFlow(context, toAdd);
785 }
786 else if (navHandler instanceof NavigationHandlerWrapper)
787 {
788 invokeInspectFlow(context, ((NavigationHandlerWrapper)navHandler).getWrapped(), toAdd);
789 }
790 }
791
792 private _FlowContextualInfo getCurrentFlowReference(FacesContext context, ClientWindow clientWindow)
793 {
794 if ( Boolean.TRUE.equals(context.getAttributes().get(RETURN_MODE)) )
795 {
796 List<_FlowContextualInfo> returnFlowList = getCurrentReturnModeFlowStack(
797 context, clientWindow, CURRENT_FLOW_REQUEST_STACK);
798 if (returnFlowList != null && !returnFlowList.isEmpty())
799 {
800 _FlowContextualInfo info = returnFlowList.get(returnFlowList.size()-1);
801 return info;
802 }
803 return null;
804 }
805 else
806 {
807 Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
808 String currentFlowMapKey = CURRENT_FLOW_STACK + clientWindow.getId();
809 List<_FlowContextualInfo> currentFlowStack =
810 (List<_FlowContextualInfo>) sessionMap.get(currentFlowMapKey);
811 if (currentFlowStack == null)
812 {
813 return null;
814 }
815 return currentFlowStack.size() > 0 ?
816 currentFlowStack.get(currentFlowStack.size()-1) : null;
817 }
818 }
819
820 private void pushFlowReference(FacesContext context, ClientWindow clientWindow, FlowReference flowReference,
821 String toViewId, FlowReference sourceFlowReference)
822 {
823 Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
824 String currentFlowMapKey = CURRENT_FLOW_STACK + clientWindow.getId();
825 List<_FlowContextualInfo> currentFlowStack = (List<_FlowContextualInfo>) sessionMap.get(currentFlowMapKey);
826 if (currentFlowStack == null)
827 {
828 currentFlowStack = new ArrayList<_FlowContextualInfo>(4);
829 sessionMap.put(currentFlowMapKey, currentFlowStack);
830 }
831 if (!currentFlowStack.isEmpty())
832 {
833 currentFlowStack.get(currentFlowStack.size()-1).setLastDisplayedViewId(context.getViewRoot().getViewId());
834 }
835 else
836 {
837
838 context.getExternalContext().getSessionMap().put(ROOT_LAST_VIEW_ID + clientWindow.getId(),
839 context.getViewRoot().getViewId());
840 }
841 currentFlowStack.add(new _FlowContextualInfo(flowReference, toViewId, sourceFlowReference));
842 }
843
844 private List<_FlowContextualInfo> getCurrentFlowStack(FacesContext context, ClientWindow clientWindow)
845 {
846 Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
847 String currentFlowMapKey = CURRENT_FLOW_STACK + clientWindow.getId();
848 List<_FlowContextualInfo> currentFlowStack = (List<_FlowContextualInfo>) sessionMap.get(currentFlowMapKey);
849 return currentFlowStack;
850 }
851
852 @Override
853 public String getLastDisplayedViewId(FacesContext context)
854 {
855 Object session = context.getExternalContext().getSession(false);
856 if (session == null)
857 {
858 return null;
859 }
860 ClientWindow clientWindow = context.getExternalContext().getClientWindow();
861 if (clientWindow == null)
862 {
863 return null;
864 }
865
866 _FlowContextualInfo info = getCurrentFlowReference(context, clientWindow);
867 if (info == null)
868 {
869 String lastDisplayedViewId = (String) context.getAttributes().get(ROOT_LAST_VIEW_ID);
870 if (lastDisplayedViewId == null)
871 {
872 lastDisplayedViewId = (String) context.getExternalContext().getSessionMap().
873 get(ROOT_LAST_VIEW_ID + clientWindow.getId());
874 }
875 return lastDisplayedViewId;
876 }
877 return info.getLastDisplayedViewId();
878 }
879
880 @Override
881 public void pushReturnMode(FacesContext context)
882 {
883
884
885
886
887
888
889
890
891
892
893
894 ClientWindow clientWindow = context.getExternalContext().getClientWindow();
895
896 if (clientWindow == null)
897 {
898 return;
899 }
900
901 if ( !Boolean.TRUE.equals(context.getAttributes().get(RETURN_MODE)) )
902 {
903
904 List<_FlowContextualInfo> currentFlowStack = getCurrentFlowStack(context, clientWindow);
905
906 Map<Object, Object> attributesMap = context.getAttributes();
907 String returnFlowMapKey = CURRENT_FLOW_REQUEST_STACK + clientWindow.getId();
908 List<_FlowContextualInfo> returnFlowStack = new ArrayList<_FlowContextualInfo>(currentFlowStack);
909 attributesMap.put(returnFlowMapKey, returnFlowStack);
910 context.getAttributes().put(RETURN_MODE, Boolean.TRUE);
911 }
912
913 _FlowContextualInfo flowReference = popFlowReferenceReturnMode(context,
914 clientWindow, CURRENT_FLOW_REQUEST_STACK);
915 pushFlowReferenceReturnMode(context, clientWindow, FLOW_RETURN_STACK, flowReference);
916 }
917
918 @Override
919 public void popReturnMode(FacesContext context)
920 {
921 ClientWindow clientWindow = context.getExternalContext().getClientWindow();
922
923 if (clientWindow == null)
924 {
925 return;
926 }
927
928 _FlowContextualInfo flowReference = popFlowReferenceReturnMode(context, clientWindow, FLOW_RETURN_STACK);
929 pushFlowReferenceReturnMode(context, clientWindow, CURRENT_FLOW_REQUEST_STACK, flowReference);
930
931 Map<Object, Object> attributesMap = context.getAttributes();
932 String returnFlowMapKey = FLOW_RETURN_STACK + clientWindow.getId();
933 List<_FlowContextualInfo> returnFlowStack = (List<_FlowContextualInfo>) attributesMap.get(returnFlowMapKey);
934 if (returnFlowStack != null && returnFlowStack.isEmpty())
935 {
936 context.getAttributes().put(RETURN_MODE, Boolean.FALSE);
937 }
938 }
939
940 public List<Flow> getActiveFlows(FacesContext context)
941 {
942 Object session = context.getExternalContext().getSession(false);
943 if (session == null)
944 {
945 return Collections.emptyList();
946 }
947 ClientWindow clientWindow = context.getExternalContext().getClientWindow();
948 if (clientWindow == null)
949 {
950 return Collections.emptyList();
951 }
952 if ( Boolean.TRUE.equals(context.getAttributes().get(RETURN_MODE)) )
953 {
954
955 FlowHandler fh = context.getApplication().getFlowHandler();
956 Flow curFlow = fh.getCurrentFlow(context);
957 if (curFlow != null)
958 {
959 List<Flow> activeFlows = new ArrayList<Flow>();
960 while (curFlow != null)
961 {
962 activeFlows.add(curFlow);
963 fh.pushReturnMode(context);
964 curFlow = fh.getCurrentFlow(context);
965 }
966
967 for (int i = 0; i < activeFlows.size(); i++)
968 {
969 fh.popReturnMode(context);
970 }
971 return activeFlows;
972 }
973 else
974 {
975 return Collections.emptyList();
976 }
977 }
978 else
979 {
980 Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
981 String currentFlowMapKey = CURRENT_FLOW_STACK + clientWindow.getId();
982
983 List<_FlowContextualInfo> currentFlowStack = (List<_FlowContextualInfo>) sessionMap.get(currentFlowMapKey);
984 if (currentFlowStack == null)
985 {
986 return Collections.emptyList();
987 }
988
989 if (!currentFlowStack.isEmpty())
990 {
991 List<Flow> activeFlows = new ArrayList<Flow>();
992 for(_FlowContextualInfo info : currentFlowStack)
993 {
994 activeFlows.add(0, getFlow(context,
995 info.getFlowReference().getDocumentId(),
996 info.getFlowReference().getId()));
997 }
998 return activeFlows;
999 }
1000
1001 return Collections.emptyList();
1002 }
1003 }
1004
1005 private void pushFlowReferenceReturnMode(FacesContext context, ClientWindow clientWindow,
1006 String stackKey, _FlowContextualInfo flowReference)
1007 {
1008 Map<Object, Object> attributesMap = context.getAttributes();
1009 String currentFlowMapKey = stackKey + clientWindow.getId();
1010 List<_FlowContextualInfo> currentFlowStack = (List<_FlowContextualInfo>) attributesMap.get(currentFlowMapKey);
1011 if (currentFlowStack == null)
1012 {
1013 currentFlowStack = new ArrayList<_FlowContextualInfo>(4);
1014 attributesMap.put(currentFlowMapKey, currentFlowStack);
1015 }
1016 currentFlowStack.add(flowReference);
1017 }
1018
1019 private _FlowContextualInfo popFlowReferenceReturnMode(FacesContext context, ClientWindow clientWindow,
1020 String stackKey)
1021 {
1022 Map<Object, Object> attributesMap = context.getAttributes();
1023 String currentFlowMapKey = stackKey + clientWindow.getId();
1024 List<_FlowContextualInfo> currentFlowStack = (List<_FlowContextualInfo>) attributesMap.get(currentFlowMapKey);
1025 if (currentFlowStack == null)
1026 {
1027 return null;
1028 }
1029 return currentFlowStack.size() > 0 ? currentFlowStack.remove(currentFlowStack.size()-1) : null;
1030 }
1031
1032 private List<_FlowContextualInfo> getCurrentReturnModeFlowStack(FacesContext context, ClientWindow clientWindow,
1033 String stackKey)
1034 {
1035 Map<Object, Object> attributesMap = context.getAttributes();
1036 String currentFlowMapKey = stackKey + clientWindow.getId();
1037 List<_FlowContextualInfo> currentFlowStack = (List<_FlowContextualInfo>) attributesMap.get(currentFlowMapKey);
1038 return currentFlowStack;
1039 }
1040
1041 public static List<Flow> getActiveFlows(FacesContext facesContext, FlowHandler fh)
1042 {
1043 FlowHandler flowHandler = fh;
1044 while (flowHandler != null)
1045 {
1046 if (flowHandler instanceof FlowHandlerImpl)
1047 {
1048 break;
1049 }
1050 else if (flowHandler instanceof FacesWrapper)
1051 {
1052 flowHandler = ((FacesWrapper<FlowHandler>)flowHandler).getWrapped();
1053 }
1054 else
1055 {
1056 flowHandler = null;
1057 }
1058 }
1059 if (flowHandler == null)
1060 {
1061
1062 Flow curFlow = fh.getCurrentFlow(facesContext);
1063 if (curFlow != null)
1064 {
1065 List<Flow> activeFlows = new ArrayList<Flow>();
1066 while (curFlow != null)
1067 {
1068 activeFlows.add(curFlow);
1069 fh.pushReturnMode(facesContext);
1070 curFlow = fh.getCurrentFlow(facesContext);
1071 }
1072
1073 for (int i = 0; i < activeFlows.size(); i++)
1074 {
1075 fh.popReturnMode(facesContext);
1076 }
1077 return activeFlows;
1078 }
1079 else
1080 {
1081 return Collections.emptyList();
1082 }
1083 }
1084 else
1085 {
1086 FlowHandlerImpl flowHandlerImpl = (FlowHandlerImpl) flowHandler;
1087 return flowHandlerImpl.getActiveFlows(facesContext);
1088 }
1089 }
1090
1091 @Override
1092 public boolean isListenerForSource(Object source)
1093 {
1094 return source instanceof ClientWindow;
1095 }
1096
1097 @Override
1098 public void processEvent(SystemEvent event)
1099 {
1100
1101 FacesContext facesContext = FacesContext.getCurrentInstance();
1102 FacesFlowProvider provider = getFacesFlowProvider(facesContext);
1103 provider.refreshClientWindow(facesContext);
1104 }
1105
1106 }