Issue Details (XML | Word | Printable)

Key: SHALE-30
Type: Bug Bug
Status: Resolved Resolved
Resolution: Fixed
Priority: Major Major
Assignee: Unassigned
Reporter: Darren Boyd
Votes: 0
Watchers: 0
Operations

If you were logged in you would be able to see more operations.
Shale

ShalePhaseListener executes ViewController.prerender twice after exception

Created: 22/Dec/05 08:08 AM   Updated: 21/Aug/06 11:28 PM
Return to search
Component/s: None
Affects Version/s: None
Fix Version/s: 1.0.3

File Attachments:
  Size
Text File patchfile.txt 2005-12-22 08:11 AM Darren Boyd 0.5 kB
Text File view.patch 2006-03-30 06:51 AM Gary VanMatre 2 kB
Environment:
Operating System: other
Platform: Other
Issue Links:
Dependency
 

Bugzilla Id: 38000


 Description  « Hide
In some situations when an exception is thrown from the prerender() call of a
ViewController the call will be made twice in the same request. I've come
across this when the application container is configured to forward to a JSF
page when encountering an error.

In my situation, I have configured Tomcat (in web.xml) to forward to an error
page for any '500' error. When a ViewController throws an exception from
prerender() the exception finds its way to the container which then forwards to
the error page. Since the error page is a JSF page, the JSF lifecycle is
processed for this new 'view'. There is no ViewController mapped to the error
page. However, due to the exception previously, the ViewController.prerender()
that was previously called gets called again.

After looking at the code I found a simple reason as to why this is happening.

The ShalePhaseListener.beforeRenderResponse(PhaseEvent) method is responsible
for calling the prerender(). This is what it looks like...

    private void beforeRenderResponse(PhaseEvent event) {
        Map map = event.getFacesContext().getExternalContext().getRequestMap();
        ViewController vc = (ViewController)
          map.get(ShaleConstants.VIEW_RENDERED);
        if (vc == null) {
            return;
        }
        vc.prerender();
        map.remove(ShaleConstants.VIEW_RENDERED);
    }

Since the exception is being thrown from the vc.prerender() call, the
ViewController is never removed from the faces request map. Therefore, after
the forward happens and the PhaseListener gets called again, there's still a
ViewController in the request which gets called again.

I checked out the source from the repository and made a very small change to fix
this. I basically removed the ViewController from the map before calling
prerender(). This may not be the best way to deal with this issue, but I think
it does better represent the intention of the code (especially given the
'contract' of ViewController).

To reproduce this, add something like the following to your web.xml file...

<error-page>
    <error-code>500</error-code>
    <location>/error.jsf</location>
</error-page>

Add to this whatever configuration is required to get error.jsf to work as a JSF
page. Make sure there is no shale ViewController mapped to /error.jsf.

On a different page (make sure it is a different JSF ViewID) add a
ViewController, appropriately mapped in Shale and throw an exception from
prerender().

 All   Comments   Change History   Subversion Commits      Sort Order: Ascending order - Click to sort in descending order
Darren Boyd added a comment - 22/Dec/05 08:11 AM
Created an attachment (id=17255)
Possible fix.

I've attached a diff of the fix I've used in my current project.

Craig McClanahan added a comment - 22/Dec/05 08:56 AM
Boy I'm glad that I am only asking for a vote of "alpha" quality on a 1.0.0 test
build of Shale :-). This kind of thing is pretty nasty.

As I mentioned on the user mailing list, I think this particular use case is the
tip of the iceberg on rationally dealing with exceptions in event handlers
called by the ViewController callbacks. As such, I'll evaluate the proposed bug
fix as a hack around this particular scenario, but we've got a bigger set of
issues here as well.

Gary VanMatre added a comment - 30/Mar/06 06:51 AM
Created an attachment (id=18002)
another approach

I was looking at the sequence of events that are fired on a postback or
invoking a command (button or link).

VewHandler.restoreView() --> ViewController.init();
ViewHandler.createView() --> ViewController.init();

The logic that tucks away the view controller for the phase listener is invoked
twice and two references to the view controller are added to the list. This
patch checks to see if a reference exists before it's added. This would happen
when the target navigation was back to the same page.

Since this is such a core part of Shale, I would like for some feedback before
going further.

Craig McClanahan added a comment - 26/May/06 11:22 AM
Resolved in nightly build 20060526, by caching exceptions from calls to prerender() or preprocess() in a manner that will be consistent with the final solution to a "coherent exception handling" RFE (SHALE-125).