The
DeltaSpike view access scope ensures beans
with a lifetime which is
as long as needed and as short as possible - which are terminated automatically (as soon as possible)
as long as needed and as short as possible - which are terminated automatically (as soon as possible)
The
DeltaSpike view scope provides a CDI context
for the JSF 2.0/2.1
The view scope is useful when you need to preserve data over multiple
requests without leaving the current JSF view by clicking on a link, returning
a different action outcome, or any other interaction that dumps the current
view. This means that such beans cannot live in a conversation which involves multiple
views (pages). By the other hand, when a conversation ends, the beans are not
destroyed immediately (by default, they will continue to exist until the
container decide to destroy them (e.g. timeout)). The DeltaSpike view access
scope increases the lifespan of the view scope to control beans lifespan over
multiple pages. Basically, this scope keeps a bean available as long as it is
referenced from a page and make it available for the next page. If the next
page doesn't use (access) this bean then it is destroyed. At a further use, it
will be recreated. Practically, as long as you keep a bean in a conversation it
will be alive. It is important that it is based on the view-id of a page, not
on the request.
View Access Scope Annotations
The DeltaSpike view access scope annotation is @ViewAccessScoped (org.apache.deltaspike.core.api.scope.ViewAccessScoped). A
bean with this scope should be annotated with @Named (javax.inject.Named).
Simple example
First we write a simple bean, DSViewScopedBean annotated with @ViewAccessScoped and with several
simple methods. Among this methods we have a @PostConstruct and a @PreDestroy methods that will signal
when instances of DSViewScopedBean
are created (initialized) and destroyed:
package beans;
import
java.io.Serializable;
import
java.util.logging.Logger;
import
javax.annotation.PostConstruct;
import
javax.annotation.PreDestroy;
import
javax.inject.Named;
import
org.apache.deltaspike.core.api.scope.ViewAccessScoped;
@Named(value =
"dsViewScoped")
@ViewAccessScoped
public class
DSViewScopedBean implements Serializable {
private static final Logger LOG =
Logger.getLogger(DSViewScopedBean.class.getName());
private final String done;
public DSViewScopedBean() {
done = "Done!";
}
@PostConstruct
public void init() {
LOG.info("DSViewScopedBean#init() invoked ...");
}
// forward to the same view
public void action() {
LOG.info("DSViewScopedBean#action()
invoked ...");
}
// forward to the done_static.xhtml page
public String actionStaticOutcome() {
LOG.info("DSViewScopedBean#actionStaticOutcome() invoked
...");
return "done_static";
}
// forward to the done_dynamic.xhtml page
public String actionDynamicOutcome() {
LOG.info("DSViewScopedBean#actionDynamicOutcome() invoked
...");
return "done_dynamic";
}
// redirect to the done_static.xhtml page
public String actionRedirectStaticOutcome() {
LOG.info("DSViewScopedBean#actionRedirectStaticOutcome() invoked
...");
return
"done_static?faces-redirect=true;";
}
// redirect to the done_dynamic.xhtml page
public String actionRedirectDynamicOutcome() {
LOG.info("DSViewScopedBean#actionRedirectDynamicOutcome() invoked
...");
return
"done_dynamic?faces-redirect=true;";
}
@PreDestroy
public void destroy() {
LOG.info("DSViewScopedBean#destroy() invoked ...");
}
public String getDone() {
return done;
}
}
Now, the done_static.xhtml
page is a very simple page that displays a static text - we will use this page to
break down the conversation that uses (access) the above bean. Practically,
when we navigate to this page the above bean should be destroyed immediately:
<?xml
version='1.0' encoding='UTF-8' ?>
<!DOCTYPE
html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ds="http://deltaspike.apache.org/jsf">
<h:head>
<title>DS @ViewAccessScoped</title>
</h:head>
<h:body>
<ds:windowId/>
Done!
</h:body>
</html>
Further, we have the done_dynamic.xhtml
page. This page uses the above bean, and it will be a part of our conversation.
So, when we navigate to this page, we expect to have the same instance of the
bean available (as long as the bean exist in the current page). In addition
this page has a link to the done_static.xhtml
page, which doesn't use (access) the bean. When this link is clicked we
practically end the conversation:
<?xml
version='1.0' encoding='UTF-8' ?>
<!DOCTYPE
html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ds="http://deltaspike.apache.org/jsf">
<h:head>
<title>DS @ViewAccessScoped</title>
</h:head>
<h:body>
<ds:windowId/>
#{dsViewScoped.done}<br/>
<h:link
outcome="done_static">Done static</h:link>
</h:body>
</html>
The current (start) page is index.xhtml, and is very simple:
<?xml
version='1.0' encoding='UTF-8' ?>
<!DOCTYPE
html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ds="http://deltaspike.apache.org/jsf"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>DS @ViewAccessScoped</title>
</h:head>
<h:body>
<ds:windowId/>
<h:form>
<h:panelGrid columns="1">
<h:commandButton value="DS View Access Scoped Bean" action="#{dsViewScoped.action()}"/>
<h:commandButton value="DS View Access Scoped Bean (Done static)"
action="#{dsViewScoped.actionStaticOutcome()}"/>
<h:commandButton value="DS View Access Scoped Bean (Done dynamic)" action="#{dsViewScoped.actionDynamicOutcome()}"/>
<h:commandButton value="DS View Access Scoped Bean (Redirect done static)"
action="#{dsViewScoped.actionRedirectStaticOutcome()}"/>
<h:commandButton value="DS View Access Scoped Bean (Redirect done dynamic)"
action="#{dsViewScoped.actionRedirectDynamicOutcome()}"/>
</h:panelGrid>
</h:form>
<h:link
outcome="done_static">Done static</h:link><br/>
<h:link
outcome="done_dynamic">Done dynamic</h:link>
</h:body>
</html>
Now, let's see what happens when we press each of these buttons and
links:
1. Press the button labeled
"DS View Access Scoped Bean" few
times
The application will navigate in the same page again and again and the
output reveals that JSF will create a single instance of DSViewScopedBean, which
is not destroyed during pressing this button:
INFO DSViewScopedBean#init() invoked ...
INFO DSViewScopedBean#action() invoked ...
INFO DSViewScopedBean#action() invoked ...
INFO DSViewScopedBean#action() invoked ...
...
2. Press the button labeled
"DS View Access Scoped Bean (Done static)"
once
The application will navigate to the done_static.xhtml, which doesn't use our
bean, so the bean instance created at this request will be destroyed
immediately (this is happening thanks to DeltaSpike!):
INFO DSViewScopedBean#init() invoked ...
INFO DSViewScopedBean#actionStaticOutcome()
invoked ...
INFO
DSViewScopedBean#destroy() invoked ...
3. Press the button labeled
"DS View Access Scoped Bean (Done dynamic)"
once
The application will navigate to the done_dynamic.xhtml, which uses (access) our
bean, so the bean instance created at this request should be available in done_dynamic.xhtml
also (this is happening thanks to DeltaSpike!):
INFO DSViewScopedBean#init() invoked ...
INFO DSViewScopedBean#actionDynamicOutcome()
invoked ...
Now, the flow is in done_dynamic.xhtml
page, and we can press the link labeled Done
static. The application will navigate to the done_static.xhtml page which doesn't use
(access) our bean, so the instance is destroyed (this is happening thanks to
DeltaSpike!):
INFO
DSViewScopedBean#destroy() invoked ...
4. Press the button labeled
"DS View Access Scoped Bean (Redirect done
static)" once
The application will navigate to the done_static.xhtml via redirect
(Post-Redirect-Get pattern), which doesn't use our bean, so the bean instance
created at this request will be destroyed immediately (this is happening thanks
to DeltaSpike!):
INFO
DSViewScopedBean#init() invoked ...
INFO
DSViewScopedBean#actionRedirectStaticOutcome() invoked ...
INFO DSViewScopedBean#destroy()
invoked ...
5. Press the button labeled
"DS View Access Scoped Bean (Redirect done
dynamic)" once
The application will navigate to the done_dynamic.xhtml via redirect
(Post-Redirect-Get pattern), which uses (access) our bean, so the bean instance
created at this request should be available in done_dynamic.xhtml even if this is an
redirect (this is happening thanks to DeltaSpike!):
INFO
DSViewScopedBean#init() invoked ...
INFO DSViewScopedBean#actionRedirectDynamicOutcome()
invoked ..
Now, the flow is in done_dynamic.xhtml
page, and we can press the link labeled Done
static. The application will navigate to the done_static.xhtml page which doesn't use
(access) our bean, so the instance is destroyed (this is happening thanks to
DeltaSpike!):
INFO DSViewScopedBean#destroy()
invoked ...
6. Press the link labeled "Done static" once
This is a <h:link>
so a GET request will be fired. The target page, done_static.xhtml doesn't use the bean, so,
if you press directly on this link, there is nothing to destroy. By the other
hand, if you "force" the creation of the bean by pressing the button
labeled "DS View Access Scoped Bean"
before the link, then you can notice how the bean instance is destroyed (this
is happening thanks to DeltaSpike!):
INFO
DSViewScopedBean#init() invoked ...
INFO
DSViewScopedBean#action() invoked ...
INFO DSViewScopedBean#destroy()
invoked ...
7. Press the link labeled "Done dynamic" once
This is a <h:link>
so a GET request will be fired. The target page, done_dynamic.xhtml uses (access) our bean, so
the bean instance will be created especially for done_dynamic.xhtml page. Further, if you
press on the link labeled Done static,
the bean instance will be destroyed (this is happening thanks to DeltaSpike!):
INFO
DSViewScopedBean#init() invoked ...
INFO DSViewScopedBean#destroy()
invoked ...
By the other hand, if in index.xhtml
you press the button labeled "DS
View Access Scoped Bean" before the link then the bean instance will be
created for being used in this page. When you press the link the same instance
will be available in done_dynamic.xhtml
page. Further, if you press on the link labeled Done static, the bean instance will be destroyed (this is happening
thanks to DeltaSpike!):
INFO
DSViewScopedBean#init() invoked ...
INFO
DSViewScopedBean#action() invoked ...
INFO DSViewScopedBean#destroy()
invoked ...
The complete application is available here.
Note 1
Ajax requests do not trigger a cleanup if the request does not access
all view-access scoped beans of the page. That’s also the reason for the name @ViewAccessScoped.
Note 2
The component <ds:windowId>
(xmlns:ds="http://deltaspike.apache.org/jsf")
is required to enable the full control of the DeltaSpike window handling;
basically, it will be useful to avoid exceptions that indicate that the windowId is not set in
the WindowContext).
Note 3
Closing the tab/window or browser will not destroy the beans
immediately. For such behavior use the OmniFaces
view scope.
Note 4
DeltaSpike view scope provides a CDI
context for the JSF 2.0/2.1.
See you in th next post about DeltaSpike window scope.
See you in th next post about DeltaSpike window scope.
Niciun comentariu :
Trimiteți un comentariu