private NavigationCase getOutcomeNavigationCase()

in impl/src/main/java/org/apache/myfaces/application/NavigationHandlerImpl.java [1003:1168]


    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;
            }
            
            // If queryString contains "includeViewParams=true" or 
            // "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))
            {
                String[] splitQueryParams = AMP_PATTERN.split(queryString); // "&" or "&amp;"
                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;
    }