use of jakarta.faces.application.NavigationCase in project myfaces by apache.
the class NavigationHandlerImpl method getNavigationCommandFromGlobalNavigationCases.
public NavigationCase getNavigationCommandFromGlobalNavigationCases(FacesContext facesContext, String viewId, NavigationContext navigationContext, String fromAction, String outcome) {
Map<String, Set<NavigationCase>> casesMap = getNavigationCases();
NavigationCase navigationCase = null;
Set<? extends NavigationCase> casesSet;
if (viewId != null) {
casesSet = casesMap.get(viewId);
if (casesSet != null) {
// Exact match?
navigationCase = calcMatchingNavigationCase(facesContext, casesSet, fromAction, outcome);
}
}
if (navigationCase == null) {
// Wildcard match?
List<_WildcardPattern> wildcardPatterns = getSortedWildcardPatterns();
for (int i = 0; i < wildcardPatterns.size(); i++) {
_WildcardPattern wildcardPattern = wildcardPatterns.get(i);
if (wildcardPattern.match(viewId)) {
casesSet = casesMap.get(wildcardPattern.getPattern());
if (casesSet != null) {
navigationCase = calcMatchingNavigationCase(facesContext, casesSet, fromAction, outcome);
if (navigationCase != null) {
break;
}
}
}
}
}
return navigationCase;
}
use of jakarta.faces.application.NavigationCase in project myfaces by apache.
the class NavigationHandlerImpl method handleNavigation.
@Override
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);
// 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();
// 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))) {
if (navigationCaseParameters == null) {
navigationCaseParameters = new HashMap<>(5, 1f);
}
// 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();
}
}
// JSF 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());
}
// JSF 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);
// JSF 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);
}
}
}
// - 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");
}
}
}
use of jakarta.faces.application.NavigationCase in project myfaces by apache.
the class NavigationHandlerImpl method getOutcomeNavigationCase.
/**
* Performs the algorithm specified in 7.4.2 for situations where no navigation cases are defined and instead
* the navigation case is to be determined from the outcome.
*
* TODO: cache results?
*/
private NavigationCase getOutcomeNavigationCase(FacesContext facesContext, String fromAction, String outcome) {
String implicitViewId = null;
boolean includeViewParams = false;
int index;
boolean isRedirect = false;
String queryString = null;
NavigationCase result = null;
String viewId = facesContext.getViewRoot() != null ? facesContext.getViewRoot().getViewId() : null;
StringBuilder viewIdToTest = SharedStringBuilder.get(facesContext, OUTCOME_NAVIGATION_SB);
viewIdToTest.append(outcome);
// If viewIdToTest contains a query string, remove it and set queryString with that value.
index = viewIdToTest.indexOf("?");
if (index != -1) {
queryString = viewIdToTest.substring(index + 1);
viewIdToTest.setLength(index);
// If queryString contains "faces-redirect=true", set isRedirect to true.
if (queryString.contains("faces-redirect=true")) {
isRedirect = true;
}
// "faces-include-view-params=true", set includeViewParams to true.
if (queryString.contains("includeViewParams=true") || queryString.contains("faces-include-view-params=true")) {
includeViewParams = true;
}
}
// If viewIdToTest does not have a "file extension", use the one from the current viewId.
index = viewIdToTest.indexOf(".");
if (index == -1) {
if (viewId != null) {
index = viewId.lastIndexOf('.');
if (index != -1) {
viewIdToTest.append(viewId.substring(index));
}
} else {
// This case happens when for for example there is a ViewExpiredException,
// and a custom ExceptionHandler try to navigate using implicit navigation.
// In this case, there is no UIViewRoot set on the FacesContext, so viewId
// is null.
// In this case, it should try to derive the viewId of the view that was
// not able to restore, to get the extension and apply it to
// the implicit navigation.
String tempViewId = getViewIdSupport().calculateViewId(facesContext);
if (tempViewId != null) {
index = tempViewId.lastIndexOf('.');
if (index != -1) {
viewIdToTest.append(tempViewId.substring(index));
}
}
}
if (log.isLoggable(Level.FINEST)) {
log.finest("getOutcomeNavigationCase -> viewIdToTest: " + viewIdToTest);
}
}
// If viewIdToTest does not start with "/", look for the last "/" in viewId. If not found, simply prepend "/".
// Otherwise, prepend everything before and including the last "/" in viewId.
boolean startWithSlash = false;
if (viewIdToTest.length() > 0) {
startWithSlash = viewIdToTest.charAt(0) == '/';
}
if (!startWithSlash) {
index = -1;
if (viewId != null) {
index = viewId.lastIndexOf('/');
}
if (index == -1) {
viewIdToTest.insert(0, '/');
} else {
viewIdToTest.insert(0, viewId, 0, index + 1);
}
}
// Apply normalization
String viewIdToTestString = null;
boolean applyNormalization = false;
for (int i = 0; i < viewIdToTest.length() - 1; i++) {
if (viewIdToTest.charAt(i) == '.' && viewIdToTest.charAt(i + 1) == '/') {
applyNormalization = true;
break;
}
}
if (applyNormalization) {
viewIdToTestString = FilenameUtils.normalize(viewIdToTest.toString(), true);
} else {
viewIdToTestString = viewIdToTest.toString();
}
// Call ViewHandler.deriveViewId() and set the result as implicitViewId.
implicitViewId = facesContext.getApplication().getViewHandler().deriveViewId(facesContext, viewIdToTestString);
if (implicitViewId != null) {
// Append all params from the queryString
// (excluding faces-redirect, includeViewParams and faces-include-view-params)
Map<String, List<String>> params = null;
if (StringUtils.isNotBlank(queryString)) {
// "&" or "&"
String[] splitQueryParams = AMP_PATTERN.split(queryString);
params = new HashMap<>(splitQueryParams.length, 1f);
for (String queryParam : splitQueryParams) {
String[] splitParam = StringUtils.splitShortString(queryParam, '=');
if (splitParam.length == 2) {
// valid parameter - add it to params
if ("includeViewParams".equals(splitParam[0]) || "faces-include-view-params".equals(splitParam[0]) || "faces-redirect".equals(splitParam[0])) {
// ignore includeViewParams, faces-include-view-params and faces-redirect
continue;
}
List<String> paramValues = params.get(splitParam[0]);
if (paramValues == null) {
paramValues = new ArrayList<>(5);
params.put(splitParam[0], paramValues);
}
paramValues.add(splitParam[1]);
} else {
// invalid parameter
throw new FacesException("Invalid parameter \"" + queryParam + "\" in outcome " + outcome);
}
}
}
// Finally, create the NavigationCase.
result = new NavigationCase(viewId, fromAction, outcome, null, implicitViewId, params, isRedirect, includeViewParams);
}
return result;
}
use of jakarta.faces.application.NavigationCase in project myfaces by apache.
the class NavigationHandlerImpl method calcMatchingNavigationCase.
private NavigationCase calcMatchingNavigationCase(FacesContext context, Set<? extends NavigationCase> casesList, String actionRef, String outcome) {
NavigationCase noConditionCase = null;
NavigationCase firstCase = null;
NavigationCase firstCaseIf = null;
NavigationCase secondCase = null;
NavigationCase secondCaseIf = null;
NavigationCase thirdCase = null;
NavigationCase thirdCaseIf = null;
NavigationCase fourthCase = null;
NavigationCase fourthCaseIf = null;
for (NavigationCase caze : casesList) {
String cazeOutcome = caze.getFromOutcome();
String cazeActionRef = caze.getFromAction();
Boolean cazeIf = caze.getCondition(context);
boolean ifMatches = cazeIf == null ? false : cazeIf;
if (outcome == null && (cazeOutcome != null || cazeIf == null) && actionRef == null) {
// To match an outcome value of null, the <from-outcome> must be absent and the <if> element present.
continue;
}
// If there are no conditions on navigation case save it and return as last resort
if (cazeOutcome == null && cazeActionRef == null && cazeIf == null && noConditionCase == null && outcome != null) {
noConditionCase = caze;
}
if (cazeActionRef != null) {
if (cazeOutcome != null) {
if (actionRef != null && outcome != null && cazeActionRef.equals(actionRef) && cazeOutcome.equals(outcome)) {
if (cazeIf != null) {
if (ifMatches) {
firstCaseIf = caze;
// return caze;
}
continue;
} else {
firstCase = caze;
}
}
} else {
if ((actionRef != null) && cazeActionRef.equals(actionRef)) {
// Caveat: if <if> is available, evaluate. If not, only match if outcome is not null.
if (cazeIf != null) {
if (ifMatches) {
thirdCaseIf = caze;
}
continue;
} else {
if (outcome != null) {
thirdCase = caze;
}
continue;
}
} else {
// it cazeActionRef match.
continue;
}
}
} else {
if (cazeOutcome != null && (outcome != null) && cazeOutcome.equals(outcome)) {
if (cazeIf != null) {
if (ifMatches) {
secondCaseIf = caze;
}
continue;
} else {
secondCase = caze;
}
}
}
// Fourth case: anything else matches if outcome is not null or <if> is specified.
if (outcome != null && cazeIf != null) {
// Again, if <if> present, evaluate.
if (ifMatches) {
fourthCaseIf = caze;
}
continue;
}
if ((cazeIf != null) && ifMatches) {
fourthCase = caze;
}
}
if (firstCaseIf != null) {
return firstCaseIf;
} else if (firstCase != null) {
return firstCase;
} else if (secondCaseIf != null) {
return secondCaseIf;
} else if (secondCase != null) {
return secondCase;
} else if (thirdCaseIf != null) {
return thirdCaseIf;
} else if (thirdCase != null) {
return thirdCase;
} else if (fourthCaseIf != null) {
return fourthCaseIf;
} else if (fourthCase != null) {
return fourthCase;
}
return noConditionCase;
}
use of jakarta.faces.application.NavigationCase in project myfaces by apache.
the class FlowHandlerImpl method clientWindowTransition.
/**
* The interpretation done for this issue is this:
*
* There are two basic cases: Enter into a flow and return from a flow.
*
* - FlowHandler.TO_FLOW_DOCUMENT_ID_REQUEST_PARAM_NAME : value of the toFlowDocumentId property
* of the navigation case when enter into a flow OR FlowHandler.NULL_FLOW when return from a flow.
*
* - FlowHandler.FLOW_ID_REQUEST_PARAM_NAME : value of the fromOutcome property of the navigation case.
* According to the intention it has multiple options:
*
* 1. It can be a flowId, which means enter into a flow.
* 2. It can be a flow call id, which means enter into a flow.
* 3. It can be a flow return id, which means return from a flow.
*
* - The javadoc of NavigationCase.getToFlowDocumentId() says this:
* "... If this navigation case represents a flow invocation, this property is the documentId in
* which the flow whose id is given by the return from getFromOutcome() is defined. Implementations
* must override this method to return the value defined in the corresponding application
* configuration resources element. The base implementation returns the empty string. ..."
*
* This is consistent with the previous interpretation, but we need to include the case where
* toFlowDocumentId is FlowHandler.NULL_FLOW too, which is derived implicitly. The key of the trick
* is override fromOutcome / toFlowDocumentId in the navigation algorithm to indicate when the
* navigation case is entering into a flow or return from a flow. In that way, it is possible
* to use ConfigurableNavigationHandler.getNavigationCase(...) to know the "route" using the
* initial fromOutcome given in FLOW_ID_REQUEST_PARAM_NAME.
*
* @param context
*/
@Override
public void clientWindowTransition(FacesContext context) {
String flowDocumentIdRequestParam = (String) context.getExternalContext().getRequestParameterMap().get(FlowHandler.TO_FLOW_DOCUMENT_ID_REQUEST_PARAM_NAME);
if (flowDocumentIdRequestParam != null) {
String flowIdRequestParam = (String) context.getExternalContext().getRequestParameterMap().get(FlowHandler.FLOW_ID_REQUEST_PARAM_NAME);
if (flowIdRequestParam == null) {
// involved.
return;
}
FlowHandler flowHandler = context.getApplication().getFlowHandler();
ConfigurableNavigationHandler nh = (ConfigurableNavigationHandler) context.getApplication().getNavigationHandler();
if (FlowHandler.NULL_FLOW.equals(flowDocumentIdRequestParam)) {
// It is a return node. The trick here is we need to calculate
// where the flow should return, because that information was not passed
// in the parameters of the link.
String toFlowDocumentId = FlowHandler.NULL_FLOW;
String fromOutcome = flowIdRequestParam;
// Flow sourceFlow = null;
List<Flow> sourceFlows = null;
List<Flow> targetFlows = null;
boolean failed = false;
int i = 0;
while (FlowHandler.NULL_FLOW.equals(toFlowDocumentId) && !failed) {
Flow currentFlow = flowHandler.getCurrentFlow(context);
if (currentFlow == null) {
failed = true;
break;
}
String currentLastDisplayedViewId = flowHandler.getLastDisplayedViewId(context);
FlowNode node = currentFlow.getNode(fromOutcome);
if (node instanceof ReturnNode) {
if (targetFlows == null) {
sourceFlows = new ArrayList<Flow>(4);
targetFlows = new ArrayList<Flow>(4);
}
// Get the navigation case using the outcome
Flow sourceFlow = currentFlow;
flowHandler.pushReturnMode(context);
currentFlow = flowHandler.getCurrentFlow(context);
i++;
NavigationCase navCase = nh.getNavigationCase(context, null, ((ReturnNode) node).getFromOutcome(context), FlowHandler.NULL_FLOW);
if (navCase == null) {
if (currentLastDisplayedViewId != null) {
sourceFlows.add(sourceFlow);
if (currentFlow != null) {
toFlowDocumentId = currentFlow.getDefiningDocumentId();
targetFlows.add(currentFlow);
} else {
// No active flow
toFlowDocumentId = null;
targetFlows.add(null);
}
} else {
// Invalid state because no navCase and
// no saved lastDisplayedViewId into session
failed = true;
}
} else {
if (FlowHandler.NULL_FLOW.equals(navCase.getToFlowDocumentId())) {
fromOutcome = navCase.getFromOutcome();
} else {
sourceFlows.add(sourceFlow);
// The absence of FlowHandler.NULL_FLOW means the return went somewhere else.
if (currentFlow != null) {
toFlowDocumentId = currentFlow.getDefiningDocumentId();
targetFlows.add(currentFlow);
} else {
// No active flow
toFlowDocumentId = null;
targetFlows.add(null);
}
}
}
} else {
// No return node found in current flow, push it and check
// the next flow
flowHandler.pushReturnMode(context);
currentFlow = flowHandler.getCurrentFlow(context);
i++;
if (currentFlow == null) {
failed = true;
}
}
}
for (int j = 0; j < i; j++) {
flowHandler.popReturnMode(context);
}
if (!failed) {
// Call transitions.
for (int j = 0; j < targetFlows.size(); j++) {
Flow sourceFlow = sourceFlows.get(j);
Flow targetFlow = targetFlows.get(j);
flowHandler.transition(context, sourceFlow, targetFlow, null, context.getViewRoot().getViewId());
}
}
} else {
// This transition is for start a new flow. In this case
// FlowHandler.FLOW_ID_REQUEST_PARAM_NAME could be the flow name to enter
// or the flow call node to activate.
// 1. check if is a flow
Flow targetFlow = flowHandler.getFlow(context, flowDocumentIdRequestParam, flowIdRequestParam);
Flow currentFlow = null;
FlowCallNode outboundCallNode = null;
FlowNode node = null;
if (targetFlow == null) {
// Check if is a call flow node
List<Flow> activeFlows = FlowHandlerImpl.getActiveFlows(context, flowHandler);
for (Flow activeFlow : activeFlows) {
node = activeFlow != null ? activeFlow.getNode(flowIdRequestParam) : null;
if (node != null && node instanceof FlowCallNode) {
outboundCallNode = (FlowCallNode) node;
String calledFlowDocumentId = outboundCallNode.getCalledFlowDocumentId(context);
if (calledFlowDocumentId == null) {
calledFlowDocumentId = activeFlow.getDefiningDocumentId();
}
targetFlow = flowHandler.getFlow(context, calledFlowDocumentId, outboundCallNode.getCalledFlowId(context));
if (targetFlow == null && !"".equals(calledFlowDocumentId)) {
targetFlow = flowHandler.getFlow(context, "", outboundCallNode.getCalledFlowId(context));
}
if (targetFlow != null) {
currentFlow = activeFlow;
break;
}
}
}
}
if (targetFlow != null) {
if (flowHandler.isActive(context, targetFlow.getDefiningDocumentId(), targetFlow.getId())) {
Flow baseReturnFlow = flowHandler.getCurrentFlow();
if (!(baseReturnFlow.getDefiningDocumentId().equals(targetFlow.getDefiningDocumentId()) && baseReturnFlow.getId().equals(targetFlow.getId()))) {
flowHandler.transition(context, baseReturnFlow, targetFlow, outboundCallNode, context.getViewRoot().getViewId());
}
flowHandler.pushReturnMode(context);
Flow previousFlow = flowHandler.getCurrentFlow(context);
flowHandler.popReturnMode(context);
flowHandler.transition(context, targetFlow, previousFlow, outboundCallNode, context.getViewRoot().getViewId());
}
// Invoke transition
flowHandler.transition(context, currentFlow, targetFlow, outboundCallNode, context.getViewRoot().getViewId());
// Handle 2 or more flow consecutive start.
boolean failed = false;
String startNodeId = targetFlow.getStartNodeId();
while (startNodeId != null && !failed) {
NavigationCase navCase = nh.getNavigationCase(context, null, startNodeId, targetFlow.getDefiningDocumentId());
if (navCase != null && navCase.getToFlowDocumentId() != null) {
currentFlow = flowHandler.getCurrentFlow(context);
node = currentFlow.getNode(navCase.getFromOutcome());
if (node != null && node instanceof FlowCallNode) {
outboundCallNode = (FlowCallNode) node;
String calledFlowDocumentId = outboundCallNode.getCalledFlowDocumentId(context);
if (calledFlowDocumentId == null) {
calledFlowDocumentId = currentFlow.getDefiningDocumentId();
}
targetFlow = flowHandler.getFlow(context, calledFlowDocumentId, outboundCallNode.getCalledFlowId(context));
if (targetFlow == null && !"".equals(calledFlowDocumentId)) {
targetFlow = flowHandler.getFlow(context, "", outboundCallNode.getCalledFlowId(context));
}
} else {
String calledFlowDocumentId = navCase.getToFlowDocumentId();
if (calledFlowDocumentId == null) {
calledFlowDocumentId = currentFlow.getDefiningDocumentId();
}
targetFlow = flowHandler.getFlow(context, calledFlowDocumentId, navCase.getFromOutcome());
if (targetFlow == null && !"".equals(calledFlowDocumentId)) {
targetFlow = flowHandler.getFlow(context, "", navCase.getFromOutcome());
}
}
if (targetFlow != null) {
flowHandler.transition(context, currentFlow, targetFlow, outboundCallNode, context.getViewRoot().getViewId());
startNodeId = targetFlow.getStartNodeId();
} else {
startNodeId = null;
}
} else {
startNodeId = null;
}
}
}
}
}
}
Aggregations