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();
}
}
}