My JSF Books/Videos My JSF Tutorials OmniFaces/JSF PPTs
JSF 2.3 Tutorial
JSF Caching Tutorial
JSF Navigation Tutorial
JSF Scopes Tutorial
JSF Page Author Beginner's Guide
OmniFaces 2.3 Tutorial Examples
OmniFaces 2.2 Tutorial Examples
JSF Events Tutorial
OmniFaces Callbacks Usages
JSF State Tutorial
JSF and Design Patterns
JSF 2.3 New Features (2.3-m04)
Introduction to OmniFaces
25+ Reasons to use OmniFaces in JSF
OmniFaces Validators
OmniFaces Converters
JSF Design Patterns
Mastering OmniFaces
Reusable and less-verbose JSF code

My JSF Resources ...

Java EE Guardian
Member of JCG Program
Member MVB DZone
Blog curated on ZEEF
OmniFaces is an utility library for JSF, including PrimeFaces, RichFaces, ICEfaces ...

[OmniFaces Utilities] - Find the right JSF OmniFaces 2 utilities methods/functions

Search on blog

Petition by Java EE Guardians

Twitter

joi, 12 noiembrie 2015

JSF Scopes Tutorial - DeltaSpike View Access Scope (and View Scope)

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)
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.

Niciun comentariu :

Trimiteți un comentariu

JSF BOOKS COLLECTION

Postări populare

OmniFaces/JSF Fans

Follow by Email

Visitors Starting 4 September 2015

Locations of Site Visitors