in impl/src/main/java/org/apache/myfaces/application/NavigationHandlerImpl.java [121:368]
public void handleNavigation(FacesContext facesContext, String fromAction,
String outcome, String toFlowDocumentId)
{
NavigationContext navigationContext = new NavigationContext();
NavigationCase navigationCase = null;
try
{
navigationCase = getNavigationCommand(facesContext, navigationContext, fromAction, outcome,
toFlowDocumentId);
}
finally
{
navigationContext.finish(facesContext);
}
if (navigationCase != null)
{
if (log.isLoggable(Level.FINEST))
{
log.finest("handleNavigation fromAction=" + fromAction + " outcome=" + outcome +
" toViewId =" + navigationCase.getToViewId(facesContext) +
" redirect=" + navigationCase.isRedirect());
}
boolean isViewActionProcessingBroadcastAndRequiresRedirect = false;
if (UIViewAction.isProcessingBroadcast(facesContext))
{
// f:viewAction tag always triggers a redirect to enforce execution of
// the lifecycle again. Note this requires enables flash scope
// keepMessages automatically, because a view action can add messages
// and these ones requires to be renderer afterwards.
facesContext.getExternalContext().getFlash().setKeepMessages(true);
String fromViewId = (facesContext.getViewRoot() == null) ? null :
facesContext.getViewRoot().getViewId();
String toViewId = navigationCase.getToViewId(facesContext);
// A redirect is required only if the viewId changes. If the viewId
// does not change, section 7.4.2 says that a redirect/restart Faces
// lifecycle is not necessary.
if (fromViewId == null && toViewId != null)
{
isViewActionProcessingBroadcastAndRequiresRedirect = true;
}
else if (fromViewId != null && !fromViewId.equals(toViewId))
{
isViewActionProcessingBroadcastAndRequiresRedirect = true;
}
}
if (navigationCase.isRedirect() || isViewActionProcessingBroadcastAndRequiresRedirect)
{
// Need to add the FlowHandler parameters here.
FlowHandler flowHandler = facesContext.getApplication().getFlowHandler();
List<Flow> activeFlows = FlowHandlerImpl.getActiveFlows(facesContext, flowHandler);
Flow currentFlow = flowHandler.getCurrentFlow(facesContext);
Flow targetFlow = calculateTargetFlow(facesContext, outcome, flowHandler,
activeFlows, toFlowDocumentId);
Map<String, List<String>> navigationCaseParameters = navigationCase.getParameters();
// Spec: If this navigation is a flow transition (where current flow is not the same as the new flow)
// sourceFlow and targetFlow could both be null so need to have multiple checks here
if (currentFlow != targetFlow)
{
// Ensure that at least one has a value and check for equality
if ((currentFlow != null && !currentFlow.equals(targetFlow)) ||
(targetFlow != null && !targetFlow.equals(currentFlow)))
{
// MYFACES-4504: check isEmpty()
if (navigationCaseParameters == null || navigationCaseParameters.isEmpty())
{
navigationCaseParameters = new HashMap<>(5, 1f);
}
// If current flow (sourceFlow) is not null and new flow (targetFlow) is null,
// include the following entries:
if (currentFlow != null && targetFlow == null)
{
// Set the TO_FLOW_DOCUMENT_ID_REQUEST_PARAM_NAME parameter
navigationCaseParameters.put(FlowHandler.TO_FLOW_DOCUMENT_ID_REQUEST_PARAM_NAME,
Arrays.asList(FlowHandler.NULL_FLOW));
// Set the FLOW_ID_REQUEST_PARAM_NAME
navigationCaseParameters.put(FlowHandler.FLOW_ID_REQUEST_PARAM_NAME,
Arrays.asList(""));
}
else
{
// If current flow (sourceFlow) is null and new flow (targetFlow) is not null,
// include the following entries:
// If we make it this far we know the above statement is true due to the other
// logical checks we have hit to this point.
// Set the TO_FLOW_DOCUMENT_ID_REQUEST_PARAM_NAME parameter
navigationCaseParameters.put(FlowHandler.TO_FLOW_DOCUMENT_ID_REQUEST_PARAM_NAME,
Arrays.asList((toFlowDocumentId == null ? "" : toFlowDocumentId)));
// Set the FLOW_ID_REQUEST_PARAM_NAME
navigationCaseParameters.put(FlowHandler.FLOW_ID_REQUEST_PARAM_NAME,
Arrays.asList(targetFlow.getId()));
}
}
}
ExternalContext externalContext = facesContext.getExternalContext();
ViewHandler viewHandler = facesContext.getApplication().getViewHandler();
String toViewId = navigationCase.getToViewId(facesContext);
String redirectPath = viewHandler.getRedirectURL(
facesContext, toViewId,
NavigationUtils.getEvaluatedNavigationParameters(facesContext, navigationCaseParameters),
navigationCase.isIncludeViewParams());
// The spec doesn't say anything about how to handle redirect but it is
// better to apply the transition here where we have already calculated the
// route than add the parameters and delegate to
// FlowHandler.clientWindowTransition(facesContext)
applyFlowTransition(facesContext, navigationContext);
//Clear ViewMap if we are redirecting to other resource
UIViewRoot viewRoot = facesContext.getViewRoot();
if (viewRoot != null && !toViewId.equals(viewRoot.getViewId()))
{
//call getViewMap(false) to prevent unnecessary map creation
Map<String, Object> viewMap = viewRoot.getViewMap(false);
if (viewMap != null)
{
viewMap.clear();
}
}
// Faces 2.0 the javadoc of handleNavigation() says something like this
// "...If the view has changed after an application action, call
// PartialViewContext.setRenderAll(true)...". The effect is that ajax requests
// are included on navigation.
PartialViewContext partialViewContext = facesContext.getPartialViewContext();
String viewId = facesContext.getViewRoot() != null ? facesContext.getViewRoot().getViewId() : null;
if (partialViewContext.isPartialRequest()
&& !partialViewContext.isRenderAll()
&& toViewId != null
&& !toViewId.equals(viewId))
{
partialViewContext.setRenderAll(true);
}
// Dispose view if the view has been marked as disposable by default action listener
ViewPoolProcessor processor = ViewPoolProcessor.getInstance(facesContext);
if (processor != null &&
processor.isViewPoolEnabledForThisView(facesContext, facesContext.getViewRoot()))
{
processor.disposeView(facesContext, facesContext.getViewRoot());
}
// Faces 2.0 Spec call Flash.setRedirect(true) to notify Flash scope and take proper actions
externalContext.getFlash().setRedirect(true);
try
{
externalContext.redirect(redirectPath);
facesContext.responseComplete();
}
catch (IOException e)
{
throw new FacesException(e.getMessage(), e);
}
}
else
{
ViewHandler viewHandler = facesContext.getApplication().getViewHandler();
//create new view
String newViewId = navigationCase.getToViewId(facesContext);
// Faces 2.0 the javadoc of handleNavigation() says something like this
// "...If the view has changed after an application action, call
// PartialViewContext.setRenderAll(true)...". The effect is that ajax requests
// are included on navigation.
PartialViewContext partialViewContext = facesContext.getPartialViewContext();
String viewId = facesContext.getViewRoot() != null ? facesContext.getViewRoot().getViewId() : null;
if ( partialViewContext.isPartialRequest() &&
!partialViewContext.isRenderAll() &&
newViewId != null &&
!newViewId.equals(viewId))
{
partialViewContext.setRenderAll(true);
}
if (facesContext.getViewRoot() != null &&
facesContext.getViewRoot().getAttributes().containsKey(CALL_PRE_DISPOSE_VIEW))
{
try
{
facesContext.getAttributes().put(MyFacesVisitHints.SKIP_ITERATION_HINT, Boolean.TRUE);
VisitContext visitContext = VisitContext.createVisitContext(facesContext,
null, MyFacesVisitHints.SET_SKIP_ITERATION);
facesContext.getViewRoot().visitTree(visitContext, PreDisposeViewCallback.INSTANCE);
}
finally
{
facesContext.getAttributes().remove(MyFacesVisitHints.SKIP_ITERATION_HINT);
}
}
applyFlowTransition(facesContext, navigationContext);
// Dispose view if the view has been marked as disposable by default action listener
ViewPoolProcessor processor = ViewPoolProcessor.getInstance(facesContext);
if (processor != null &&
processor.isViewPoolEnabledForThisView(facesContext, facesContext.getViewRoot()))
{
processor.disposeView(facesContext, facesContext.getViewRoot());
}
// create UIViewRoot for new view
UIViewRoot viewRoot = null;
String derivedViewId = viewHandler.deriveViewId(facesContext, newViewId);
if (derivedViewId != null)
{
ViewDeclarationLanguage vdl = viewHandler.getViewDeclarationLanguage(facesContext, derivedViewId);
if (vdl != null)
{
ViewMetadata metadata = vdl.getViewMetadata(facesContext, newViewId);
if (metadata != null)
{
viewRoot = metadata.createMetadataView(facesContext);
}
}
}
// viewRoot can be null here, if ...
// - we don't have a ViewDeclarationLanguage (e.g. when using facelets-1.x)
// - there is no view metadata or metadata.createMetadataView() returned null
// - viewHandler.deriveViewId() returned null
if (viewRoot == null)
{
viewRoot = viewHandler.createView(facesContext, newViewId);
}
facesContext.setViewRoot(viewRoot);
facesContext.renderResponse();
}
}
else
{
// no navigationcase found, stay on current ViewRoot
if (log.isLoggable(Level.FINEST))
{
log.finest("handleNavigation fromAction=" + fromAction + " outcome=" + outcome +
" no matching navigation-case found, staying on current ViewRoot");
}
}
}