|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Objectorg.apache.myfaces.orchestra.conversation.jsf.AccessScopePhaseListener
public class AccessScopePhaseListener
Handle access-scoped conversations.
After a new view has been rendered, delete any access-scope conversations for which no bean in that scope has been accessed during the render phase of the request.
This allows a page which handles a postback to store data into beans in an access-scoped conversation, then navigate to a new page. That information is available for the new page during its rendering. And if that data is referenced, it will remain around until the user does a GET request, or a postback that causes navigation again. Then following the rendering of that new target page, any access-scoped conversations will be discarded except for those that the new target page references.
Any access-scoped conversations that a page was using, but which the new page does NOT use are therefore automatically cleaned up at the earliest possibility - after rendering of the new page has completed.
Note: When a "master" and "detail" page pair exist, that navigating master->detail->master->detail correctly uses a fresh conversation for the second call to the detail page (and not reuse the access-scoped data from the first call). By only counting accesses during the render phase, this works correctly.
Note: Access-scoped conversations must be preserved when AJAX calls cause only part of a page to be processed, and must be preserved when conversion/validation failure cause reads of the values of input components to be skipped. By deleting unaccessed conversations only after the first render, this happens automatically.
Note: If a view happens to want its postbacks handled by a bean in conversation A, but the render phase never references anything in that conversation, then the conversation will be effectively request-scoped. This is not expected to be a problem in practice as it would be a pretty odd view that has stateful event handling but either renders nothing or fetches its data from somewhere other than the same conversation. If such a case is necessary, the view can be modified to "ping" the conversation in order to keep it active via something like an h:outputText with rendered="#{backingBean.class is null}" (which always resolves to false, ie not rendered, but does force a method-invocation on the backingBean instance). Alternatively, a manual-scoped conversation can be used.
Note: If FacesContext.responseComplete is called during processing of a postback, then no phase-listeners for the RENDER_RESPONSE phase are executed. And any navigation rule that specifies "redirect" causes responseComplete to be invoked. Therefore access-scoped beans are not cleaned up immediately. However the view being redirected to always runs its "render" phase only, no postback. The effect, therefore, is exactly the same as when an internal forward is performed to the same view: in both cases, the access-scoped beans are kept if the next view refers to them, and discarded otherwise.
Note: Some AJAX libraries effectively do their own "rendering" pass from within a custom PhaseListener, during the beforePhase for RENDER_RESPONSE. This could have undesirable effects on Orchestra - except that for all AJAX requests, the viewRoot restored during RESTORE_VIEW will be the same viewRoot used during render phase - so this PhaseListener will ignore the request anyway.
Backwards-compatibility note: The behaviour of this class has changed between releases 1.2 and 1.3. In earlier releases, the access-scope checking ran on every request (not just GET or navigation). Suppose a bean is in its own access-scoped conversation, and the only reference to that bean is from a component that is rendered or not depending upon a checkbox editable by the user. In the old version, hiding the component would cause the access-scoped conversation to be discarded (not accessed), while the current code will not discard it. The new behaviour does fix a couple of bugs: access-scoped conversations discarded during AJAX requests and after conversion/validation failure.
Constructor Summary | |
---|---|
AccessScopePhaseListener()
|
Method Summary | |
---|---|
void |
afterPhase(javax.faces.event.PhaseEvent event)
|
void |
beforePhase(javax.faces.event.PhaseEvent event)
|
javax.faces.event.PhaseId |
getPhaseId()
|
protected void |
invalidateAccessScopedConversations(String viewId)
Invalidates any conversation with aspect ConversationAccessLifetimeAspect
which has not been accessed during a http request |
Methods inherited from class java.lang.Object |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Constructor Detail |
---|
public AccessScopePhaseListener()
Method Detail |
---|
public javax.faces.event.PhaseId getPhaseId()
getPhaseId
in interface javax.faces.event.PhaseListener
public void beforePhase(javax.faces.event.PhaseEvent event)
beforePhase
in interface javax.faces.event.PhaseListener
public void afterPhase(javax.faces.event.PhaseEvent event)
afterPhase
in interface javax.faces.event.PhaseListener
protected void invalidateAccessScopedConversations(String viewId)
ConversationAccessLifetimeAspect
which has not been accessed during a http request
|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |