Details
Description
When Seam jBPM does page navigation using redirects, there's a mismatch in Pageflow.validatePageflow(Seam code)
//now check that the restored view id matches what we expect
//from the pageflow node
//TODO: we need some way to disable this check, since users
// might want some adhoc nav in and out of a pageflow?
String viewId = Pages.getViewId(facesContext);
if ( !viewId.equals( getPage().getViewId() ) )
{
illegalNavigationError();
}
In my example, the viewId from the facesContext object is pageD.seam, whereas the viewId from getPage().getViewId() is pageD.xhtml. This mismatch causes illegalNavigationError to be called, which does page navigation to the current page (in my case) which causes the redirection loop.
We need to understand why the difference in page viewID representation.
//now check that the restored view id matches what we expect
//from the pageflow node
//TODO: we need some way to disable this check, since users
// might want some adhoc nav in and out of a pageflow?
String viewId = Pages.getViewId(facesContext);
if ( !viewId.equals( getPage().getViewId() ) )
{
illegalNavigationError();
}
In my example, the viewId from the facesContext object is pageD.seam, whereas the viewId from getPage().getViewId() is pageD.xhtml. This mismatch causes illegalNavigationError to be called, which does page navigation to the current page (in my case) which causes the redirection loop.
We need to understand why the difference in page viewID representation.
This appears to be a bit of left over hack-ness related to the viewId.
The JSF spec states the following:
Derive the view identifier that corresponds to this request, as follows:
? If prefix mapping (such as "/faces/*") is used for FacesServlet, the viewId is set
from the extra path information of the request URI.
? If suffix mapping (such as "*.faces") is used for FacesServlet, the viewId is set
from the servlet path information of the request URI, after replacing the suffix with the
value of the context initialization parameter named by the symbolic constant
ViewHandler.DEFAULT_SUFFIX_PARAM_NAME (if no such context initialization
parameter is present, use the value of the symbolic constant
ViewHandler.DEFAULT_SUFFIX as the replacement suffix).
? If no view identifier can be derived, throw an exception.
The viewId is being set on the viewRoot in two places in ICEfaces code. Namely, in the D2DViewHandler in createView(), and in the D2DFaceletViewHandler in renderView().
It looks as if recent check ins to the D2DFaceletView handler have it correct. The code that determines the suffix is:
protected String getRenderedViewId(FacesContext context, String actionId) {
{ log.error( "The " + ViewHandler.DEFAULT_SUFFIX_PARAM_NAME + " context parameter is not set in web.xml. " + "Please define the filename extension used for " + "your source JSF pages. Example:\n" + "<context-param>\n" + " <param-name>javax.faces.DEFAULT_SUFFIX</param-name>\n" + " <param-value>.xhtml</param-value>\n" + "</context-param>"); }ExternalContext extCtx = context.getExternalContext();
String viewId = actionId;
if (extCtx.getRequestPathInfo() == null) {
String viewSuffix = context.getExternalContext().getInitParameter(
ViewHandler.DEFAULT_SUFFIX_PARAM_NAME);
if (viewSuffix == null) {
if (log.isErrorEnabled())
} else {
{ viewId = actionId + viewSuffix; }int lastPeriod = actionId.lastIndexOf('.');
if (lastPeriod < 0)
else
{ viewId = actionId.substring(0, lastPeriod) + viewSuffix; }}
}
return viewId;
}
But the code in the createView method is using the viewId obtained by this code:
viewId = facesContext.getExternalContext().getRequestPathInfo();
There was some legacy code added early on to get Seam to work, stuff to do with the ActionURLParam parameter in web.xml. This is probably redundant now that the D2DFaceletViewHandler is doing the right thing. This code meant that all pages requested in a Seam environment would be terminated by a .seam suffix (in most examples that is, it was configurable) hence the mismatch.
Replacing the code in D2DViewHandler.createView with a call to setViewId(mungeView(viewID)) causes the viewId with the correct suffix to wind up in the viewRoot, and redirection with jBPM works properly at this point, but I think the correct thing to do is to completely strip out the ActionURLSuffix code and servlet-param and to strictly operate according to the JSF parameters, as in the spec.