JSF 2 @ConversationScoped Example

JavaServer Faces has been coming with different kinds of scopes; scopes that already used for defining the Managed Beans. Most of the JSF developers were familiar with scopes like Request, View, Session & Application, but newly added scopes such Conversation, View, Custom and newly for JSF 2.2 Flow haven’t gained a widely range of discussion on the internet and specifically on the JSF blogs for a one reason; it’s rarely used.

The conversation scope ranges over a set of related pages, by that the data has persisted until a particular goal has been reached without needs for using the session scope. That is, a single session can have multiple conversations in different pages.

Also Read:

Using of the conversation scope requires you do the following steps:

  • Use a Contexts and Dependency Injection for Java EE (CDI) bean, cause this feature is a CDI-based not based on JSF.
  • Use the @ConversationScoped annotation.
  • Add instance variable private @Inject Conversation conversation. This instance variable will be automatically initialized with a Conversation object when the bean is constructed.
  • Call the conversation.begin() to evaluate the scope of the bean from request scope to conversation scope.
  • Call the conversation.end() to remove the bean from the conversation scope.

This tutorial will use the CDI implementation of JBoss integrated with the Tomcat 7 for achieving the conjunction between jsf and CDI context.

1. Managed Bean

IndexBean.java

package net.javabeat.jsf;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.inject.Inject;
import javax.inject.Named;

@Named(value="indexBean")
@ConversationScoped
public class IndexBean implements Serializable{

	private static final long serialVersionUID = 1L;
	private int index = 1;
	private String answer;
	private String question;
	private Map<String,String> questions = new HashMap<String,String>();
	private Map<String,String> answers = new HashMap<String,String>();
	private @Inject Conversation conversation;
	private boolean transientVal = true;

	public IndexBean(){
		this.questions.put("1", "What's the most tutorial that you loved on the JavaBeat site ?");
		this.questions.put("2", "What's the most example that you loved on the JavaBeat site ?");
		this.question = this.questions.get("1");
	}

	public int getIndex() {
		return index;
	}

	public void setIndex(int index) {
		this.index = index;
	}

	public String getAnswer() {
		return answer;
	}

	public void setAnswer(String answer) {
		if(this.index == 1){
			this.answers.put(String.valueOf(index), this.answer);
			this.question = questions.get(String.valueOf(index));
			this.answer = "";
		}
		else if(this.index == 2){
			this.answers.put(String.valueOf(index), this.answer);
			this.question = questions.get(String.valueOf(index));
			this.answer = "";
		}
		this.answer = answer;
	}

	public String getQuestion() {
		return question;
	}

	public void setQuestion(String question) {
		this.question = question;
	}

	public Map<String, String> getQuestions() {
		return questions;
	}

	public void setQuestions(Map<String, String> questions) {
		this.questions = questions;
	}

	public Map<String, String> getAnswers() {
		return answers;
	}

	public void setAnswers(Map<String, String> answers) {
		this.answers = answers;
	}

	public Conversation getConversation() {
		return conversation;
	}

	public void setConversation(Conversation conversation) {
		this.conversation = conversation;
	}

	public boolean isTransientVal() {
		return transientVal;
	}

	public void setTransientVal(boolean transientVal) {
		this.transientVal = transientVal;
	}

	public String next(){
		if(index != 2){
			index++;
			return null;
		}
		else{
			this.conversation.end();
			this.transientVal = this.conversation.isTransient();
			this.question = "Thanks For Your Time";
			return "";
		}

	}

	public String stopQuestionare(){
		this.question = "Thanks For Your Time";
		this.conversation.end();
		this.transientVal = this.conversation.isTransient();
		return "questionare";
	}

	public String startQuestionare(){
		this.conversation.begin();
		this.transientVal = this.conversation.isTransient();
		return "questionare";
	}
}

2. The Views

index.xhtml

<!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:ui="http://java.sun.com/jsf/facelets"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">
	<f:view>
		<h:form>
			<h1>JavaBeat JSF 2.2 Examples</h1>
			<h2>JSF2 ConversationScoped Example</h2>
			<h:commandButton value="Start New Questionare"
					action="#{indexBean.startQuestionare}"
						disabled="#{!indexBean.transientVal}"/>
		</h:form>
	</f:view>
</html>

questionare.xhtml

<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">
<h:head>
	<h:outputScript library="javax.faces" name="jsf.js"/>
</h:head>
<h:body>
	<f:view afterPhase="#{indexBean.phaseListener}">
		<h1>JavaBeat JSF 2.2 Examples</h1>
		<h2>JSF2 ConversationScoped Example</h2>
		<h:form prependId="false">
			<h:outputText value="JavaBeat Questionare"/>
			<br/>
			<br/>
			<h:outputText value="Please Answer Questions Below:"
					rendered="#{indexBean.transientVal == false}"/>
			<br/>
			<br/>
			<h:outputText value="Question #"
					rendered="#{indexBean.transientVal == false}"/>
			#{' '}
			<h:outputText value="#{indexBean.index}"
					rendered="#{indexBean.transientVal == false}"/>
			<br/>
			<br/>
			<h:outputText value="#{indexBean.question}"/>
			<br/>
			<br/>
			<h:inputText value="#{indexBean.answer}"/>
			<h:commandButton value="Next Question" action="#{indexBean.next}"
				disabled="#{indexBean.transientVal}"/>
			<h:commandButton value="End Questionare"
				action="#{indexBean.stopQuestionare}"
					disabled="#{indexBean.transientVal}"/>
			<h:commandButton value="Start New Questionare"
				action="#{indexBean.startQuestionare}"
				disabled="#{indexBean.transientVal == false}"/>
		</h:form>
	</f:view>
</h:body>
</html>

3. Faces Configuration File

faces-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
	version="2.2">
<application>
	<resource-bundle>
		<base-name>net.javabeat.jsf.application</base-name>
		<var>msg</var>
	</resource-bundle>
</application>
</faces-config>

4. webapp/META-INF/context.xml

context.xml

<Context>
   <Resource name="BeanManager"
      auth="Container"
      type="javax.enterprise.inject.spi.BeanManager"
      factory="org.jboss.weld.resources.ManagerObjectFactory"/>
</Context>

5. webapp/WEB-INF/beans.xml

beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="

http://java.sun.com/xml/ns/javaee


http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"></beans>

  • Even the beans.xml is empty, but it’s mandatory for initializing the CDI context

6. Dependency for Weld Implementation

Dependency Add To pom.xml

<dependency>
 <groupId>org.jboss.weld.servlet</groupId>
 <artifactId>weld-servlet</artifactId>
 <version>1.1.18.Final</version>
</dependency>

7. The Directory Structure

JSF 2 Conversation Scope Example 1

8. The Deployment Descriptor

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

	id="WebApp_ID" version="2.5" metadata-complete="true">
	<context-param>
		<description>State saving method: 'client' or 'server'
						(=default). See JSF Specification 2.5.2
		</description>
		<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
		<param-value>server</param-value>
	</context-param>
	<context-param>
		<param-name>javax.faces.application.CONFIG_FILES</param-name>
		<param-value>/WEB-INF/faces-config.xml</param-value>
	</context-param>
	<servlet>
		<servlet-name>Faces Servlet</servlet-name>
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>/faces/*</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.xhtml</url-pattern>
	</servlet-mapping>
	<listener>
		<listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
	</listener>
	<listener>
		<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
	</listener>
	<resource-env-ref>
	   <resource-env-ref-name>BeanManager</resource-env-ref-name>
	   <resource-env-ref-type>
	      javax.enterprise.inject.spi.BeanManager
	   </resource-env-ref-type>
	</resource-env-ref>
</web-app>
  • Note adding the weld listener before the faces listener (This arrangement mandatory)

9. JSF 2 ConversationScoped Demo

The below snapshots show you the full scenario of questionare for a JavaBeat site, in which the user has started the questionare by clicking on the Start New Questionare that shown at the index.xhtml view. Once the questionare has been started the conversation scope has been initialized for holding the required data. The user has the option of ending the questionare at any time it required, or finishing the questionare into the end. Either the user has clicked the Stop Questionare or finish it, the conversation scope will be ended and so the managed beans are destroyed.

JSF 2 Conversation Scope Example 2

  • Staring the questiuonare means the conversation scope has begun (Conversation Scope is long-running).

JSF 2 Conversation Scope Example 3

  • The questionare has been started and the questions could be navigated through Next Question.
  • End questionare will end the conversation scope, so all beans that are located inside that scope will be destroyed eventually.
  • Note the way that the Start New Questionare has disabled (Using conversation.isTransient).

JSF 2 Conversation Scope Example 4

  • The second question has bee shown by using the Next Question.
  • If you’ve ended the questionare, the thanks message should be displayed rather displaying question.
  • Once the questionare has been ended the Start New Questionare has been enabled.

JSF 2 Conversation Scope Example 5

  • You have the ability to reach this stage by navigating the whole questions or by using End Questionare.
  • Start New Questionare has been enabled, once the user has activated it, a new conversation has been begun.

Comments

comments

About Amr Mohammed

Speak Your Mind

*