Details
-
Bug
-
Status: Open
-
Major
-
Resolution: Unresolved
-
None
-
None
-
None
-
MyFaces JSF 1.2 and Vignette Portal
Description
We have a Vignette / MyFaces 1.2 / portlet-bridge-1.0.0-beta based web application. When the development had started we've downloaded the latest version of the bridge at the time (roughly 08-2009) and still using this version.
After we started testing in a multi-user environment it had become clear that the bridge periodically corrupts incoming action (but not render) portal requests. The corresponding buggy code and fixes are described below.
1. Defective code
The following 2 methods wrongly assume that temporary registration of the bridge instance as a phase listerner while executing a render request doesn't affect concurrent action request (s) execution through the same instance. In reality a concurrent action request can sneak in between the lifecycle.addPhaseListener(this) and lifecycle.removePhaseListener(this) calls and end prematuraly just after the RESTORE_VIEW JSF phase (because of the context.renderResponse() call).
private void doFacesRender(
RenderRequest request,
RenderResponse response,
FacesContext context,
Lifecycle lifecycle,
String scopeId,
List <String> preExistingAttributes
)
throws BridgeException, BridgeUninitializedException, NullPointerException
{
...
if (context.getViewRoot() == null)
{
...
lifecycle.addPhaseListener(this);
try
catch (Exception e)
{ ... }
finally
{ lifecycle.removePhaseListener(this); }
}
...
}
public void afterPhase(PhaseEvent event)
{
// only set renderresponse if in RESTORE_VIEW phase
if (event.getPhaseId() == PhaseId.RESTORE_VIEW)
{ FacesContext context = event.getFacesContext(); // Now restore the Faces Messages restoreFacesMessageState(context); context.renderResponse(); }
}
2. Fixed code
We've implemented and successfully tested the following fixes.
private void doFacesRender(
RenderRequest request,
RenderResponse response,
FacesContext context,
Lifecycle lifecycle,
String scopeId,
List <String> preExistingAttributes
)
throws BridgeException, BridgeUninitializedException, NullPointerException
{
...
if (context.getViewRoot() == null)
{
...
//lifecycle.addPhaseListener(this);
try
{ lifecycle.execute(context); }
catch (Exception e)
{ ... }finally
{ //lifecycle.removePhaseListener(this); }...
}
private synchronized Lifecycle getLifecycle()
throws BridgeException
{
try
{
if (mLifecycle == null)
{
LifecycleFactory lifecycleFactory =
(LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
String lifecycleId =
mPortletConfig.getPortletContext().getInitParameter(FacesServlet.LIFECYCLE_ID_ATTR);
if (lifecycleId == null)
mLifecycle = lifecycleFactory.getLifecycle(lifecycleId);
mLifecycle.addPhaseListener(this);
}
return mLifecycle;
}
catch (FacesException e)
}
public void afterPhase(PhaseEvent event)
{
if (BridgeUtil.getPortletRequestPhase().toString().contains("ACTION_PHASE"))
if (event.getPhaseId() == PhaseId.RESTORE_VIEW)
{ FacesContext context = event.getFacesContext(); // Now restore the Faces Messages restoreFacesMessageState(context); context.renderResponse(); }}