private boolean notifyListeners()

in api/src/main/java/jakarta/faces/component/UIViewRoot.java [1006:1194]


    private boolean notifyListeners(FacesContext context, PhaseId phaseId, MethodExpression listener,
                                    boolean beforePhase)
    {
        List<PhaseListener> phaseListeners = (List<PhaseListener>) getStateHelper().get(PropertyKeys.phaseListeners);
        // Check if any listener was called
        boolean listenerCalled = false;
        if (listener != null || (phaseListeners != null && !phaseListeners.isEmpty()))
        {
            // how many listeners do we have? (the MethodExpression listener is counted in either way)
            // NOTE: beforePhaseSuccess[0] always refers to the MethodExpression listener
            int listenerCount = (phaseListeners != null ? phaseListeners.size() + 1 : 1);

            boolean[] beforePhaseSuccess;
            if (beforePhase)
            {
                beforePhaseSuccess = new boolean[listenerCount];
                _getListenerSuccessMap().put(phaseId, beforePhaseSuccess);
            }
            else
            {
                // afterPhase - get beforePhaseSuccess from the Map
                beforePhaseSuccess = _getListenerSuccessMap().get(phaseId);
                if (beforePhaseSuccess == null)
                {
                    // no Map available - assume that everything went well
                    beforePhaseSuccess = new boolean[listenerCount];
                    Arrays.fill(beforePhaseSuccess, true);
                }
            }

            PhaseEvent event = createEvent(context, phaseId);

            // only invoke the listener if we are in beforePhase
            // or if the related before PhaseListener finished without an Exception
            if (listener != null && (beforePhase || beforePhaseSuccess[0]))
            {
                listenerCalled = true;
                try
                {
                    listener.invoke(context.getELContext(), new Object[] { event });
                    beforePhaseSuccess[0] = true;
                }
                catch (Throwable t)
                {
                    beforePhaseSuccess[0] = false; // redundant - for clarity
                    _getLogger().log(Level.SEVERE, "An Exception occurred while processing " +
                            listener.getExpressionString() +
                            " in Phase " + phaseId, t);
                    if (beforePhase)
                    {
                        return context.getResponseComplete() ||
                                (context.getRenderResponse() && !PhaseId.RENDER_RESPONSE.equals(phaseId));
                    }
                }
            }
            else if (beforePhase)
            {
                // there is no beforePhase MethodExpression listener
                beforePhaseSuccess[0] = true;
            }

            if (phaseListeners != null && !phaseListeners.isEmpty())
            {
                if (beforePhase)
                {
                    // process listeners in ascending order
                    for (int i = 0; i < beforePhaseSuccess.length - 1; i++)
                    {
                        PhaseListener phaseListener;
                        try
                        {
                            phaseListener = phaseListeners.get(i);
                        }
                        catch (IndexOutOfBoundsException e)
                        {
                            // happens when a PhaseListener removes another PhaseListener 
                            // from UIViewRoot in its beforePhase method
                            throw new IllegalStateException("A PhaseListener must not remove " +
                                    "PhaseListeners from UIViewRoot.");
                        }
                        PhaseId listenerPhaseId = phaseListener.getPhaseId();
                        if (phaseId.equals(listenerPhaseId) || PhaseId.ANY_PHASE.equals(listenerPhaseId))
                        {
                            listenerCalled = true;
                            try
                            {
                                phaseListener.beforePhase(event);
                                beforePhaseSuccess[i + 1] = true;
                            }
                            catch (Throwable t)
                            {
                                beforePhaseSuccess[i + 1] = false; // redundant - for clarity
                                _getLogger().log(Level.SEVERE, "An Exception occurred while processing the " +
                                        "beforePhase method of PhaseListener " + phaseListener +
                                        " in Phase " + phaseId, t);
                                if (shouldViewRootPhaseListenerQueuesExceptions(context))
                                {
                                    publishException (context, t, phaseId,
                                            ExceptionQueuedEventContext.IN_BEFORE_PHASE_KEY);
                                }
                                return context.getResponseComplete() ||
                                        (context.getRenderResponse() && !PhaseId.RENDER_RESPONSE.equals(phaseId));
                            }
                        }
                    }
                }
                else
                {
                    // afterPhase
                    // process listeners in descending order
                    for (int i = beforePhaseSuccess.length - 1; i > 0; i--)
                    {
                        PhaseListener phaseListener;
                        try
                        {
                            phaseListener = phaseListeners.get(i - 1);
                        }
                        catch (IndexOutOfBoundsException e)
                        {
                            // happens when a PhaseListener removes another PhaseListener 
                            // from UIViewRoot in its beforePhase or afterPhase method
                            throw new IllegalStateException("A PhaseListener must not remove " +
                                    "PhaseListeners from UIViewRoot.");
                        }
                        PhaseId listenerPhaseId = phaseListener.getPhaseId();
                        if ((phaseId.equals(listenerPhaseId) || PhaseId.ANY_PHASE.equals(listenerPhaseId))
                                && beforePhaseSuccess[i])
                        {
                            listenerCalled = true;
                            try
                            {
                                phaseListener.afterPhase(event);
                            }
                            catch (Throwable t)
                            {
                                logger.log(Level.SEVERE, "An Exception occurred while processing the " +
                                        "afterPhase method of PhaseListener " + phaseListener +
                                        " in Phase " + phaseId, t);
                                if (shouldViewRootPhaseListenerQueuesExceptions(context))
                                {
                                    publishException (context, t, phaseId,
                                            ExceptionQueuedEventContext.IN_AFTER_PHASE_KEY);
                                }
                            }
                        }
                    }
                }
            }
        }

        // The spec javadoc says "... Upon return from the listener, call FacesContext.getResponseComplete() 
        // and FacesContext.getRenderResponse(). If either return true set the internal state flag to true. ..."
        // and later it says:
        // "... Execute any processing for this phase if the internal state flag was not set. ..."
        // But after some testing it seems if the internal state flag is not set, the check is not done and the
        // phase is not skipped. The only exception is in render response phase.
        if (listenerCalled)
        {
            if (beforePhase)
            {
                return context.getResponseComplete() ||
                        (context.getRenderResponse() && !PhaseId.RENDER_RESPONSE.equals(phaseId));
            }
            else
            {
                return context.getResponseComplete() || context.getRenderResponse();
            }
        }
        else
        {
            if (beforePhase)
            {
                if (PhaseId.RENDER_RESPONSE.equals(phaseId))
                {
                    return context.getResponseComplete();
                }
                else
                {
                    // Don't check and don't skip
                    return false;
                }
            }
            else
            {
                // Note if is afterPhase the return value is not relevant.
                return context.getResponseComplete() || context.getRenderResponse();
            }
        }
    }