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