
| Key: |
SHALE-30
|
| Type: |
Bug
|
| Status: |
Resolved
|
| Resolution: |
Fixed
|
| Priority: |
Major
|
| Assignee: |
Unassigned
|
| Reporter: |
Darren Boyd
|
| Votes: |
0
|
| Watchers: |
0
|
|
If you were logged in you would be able to see more operations.
|
|
|
|
File Attachments:
|
|
|
Environment:
|
Operating System: other
Platform: Other
Operating System: other
Platform: Other
|
|
Issue Links:
|
Dependency
|
|
|
|
This issue blocks:
|
|
SHALE-125
[Shale][View] Devise coherent exception handling strategy
|
|
|
|
|
|
|
|
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().
|
|
Description
|
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(). |
Show » |
|
Possible fix.
I've attached a diff of the fix I've used in my current project.