dev@javaserverfaces.java.net

INVOKE_APPLICATION PhaseListener with redirect

From: <gudnabrsam_at_gmail.com>
Date: Fri, 14 Oct 2011 21:38:20 +0000 (GMT)

Hi all,
  After spending the past couple of days researching these concepts I
have reached the opinion that I have detected a suboptimal condition
enforced by the JSF specification (v2.1), and wanted to sound off.
Since I do not have a direct conduit to the EG as a whole, I'm airing
my concern here in the hope of starting a discussion and seeing where
that leads.

Facts:
 A: Per the javadoc of Application#getActionListener(), the default
ActionListener implementation should implement #processAction() such
that #handleNavigation() is called against the available
NavigationHandler.
 B: Per section 7.4.2 of the specification, it is the responsibility
of the default NavigationHandler implementation to call
ExternalContext#redirect() when the resulting navigation is marked as
<redirect>true</redirect>, and subsequently to call
FacesContext#responseComplete().
 C: Per section 12.3 of the specification: for a given PhaseId,
#afterPhase() should be invoked against any PhaseListener against which
#beforePhase() was also invoked.

By merging these bits of information together, one may deduce that when
the navigation implied by a given action results in a redirect, the
#afterPhase() invocations for the current phase (typically
INVOKE_APPLICATION) are made in the context of a response that has
already been completed. This is indeed my experience in the nontrivial
application I am building as well as in the distilled test app which
behaves consistently with the spec both on Mojarra and MyFaces. This
situation makes certain crosscutting logic difficult at best to
implement and thus makes me wonder if it has been considered by the EG.
 Would it not be better to revise the behavior of the various
cooperating components such that the redirect is performed *after* the
current phase has completed, making up simply an alternative path in
the implementation of RENDER_RESPONSE? If not, why not? As yet the
most straightforward workaround I have come up with is an
ExternalContextWrapper that intercepts the #redirect() call to do the
necessary cleanup.

Thanks,
Matt