[jboss-user] [JBoss Seam] - Session context variable missing

gmarcus do-not-reply at jboss.com
Sat Jun 9 18:18:25 EDT 2007


I have an Entitiy called Category as defined here:

  | package com.mystuff.fresh.domain;
  | 
  | import static org.jboss.seam.ScopeType.SESSION;
  | import static org.jboss.seam.ScopeType.CONVERSATION;
  | 
  | import java.io.Serializable;
  | 
  | import javax.persistence.Entity;
  | import javax.persistence.GeneratedValue;
  | import javax.persistence.Id;
  | import javax.persistence.NamedQueries;
  | import javax.persistence.NamedQuery;
  | import javax.persistence.Transient;
  | 
  | 
  | import org.jboss.seam.annotations.Name;
  | import org.jboss.seam.annotations.Role;
  | import org.jboss.seam.annotations.Scope;
  | 
  | 
  | @Entity
  | @Name("category")
  | @Scope(CONVERSATION)
  | @Role(name = "currentCategory", scope=SESSION)
  | @NamedQueries( { 
  | 	@NamedQuery(name = "Category.findById", query = "SELECT c FROM Category c WHERE c.id=:id"), 
  | 	@NamedQuery(name = "Category.findAll", query = "SELECT c FROM Category c"),
  | 	@NamedQuery(name = "Category.findRoot", query = "SELECT c FROM Category c WHERE c.id=0"),
  | 	@NamedQuery(name = "Category.findByName", query = "SELECT c FROM Category c WHERE toupper(c.name)=toupper(:name)")})
  | public class Category implements Serializable
  | {
  | 	private static final long serialVersionUID = 1881413500711441952L;
  | 
  | 	@Id
  | 	@GeneratedValue
  | 	private long id;
  | 
  | 	// parent category
  | 	private long parentId;
  | 
  | 	private String name;
  | 
  | 	private String description;
  | 
  | 	private long numberOfEntries;
  | 
  | 	// TODO: keep a view count on categories to know which are the most popular
  | 	// private long numViews;
  | 
  | 	private Boolean visible;
  | 
  | 
  | 	public Category()
  | 	{
  | 	}
  | 
  | 	/**
  | 	 * @return the description
  | 	 */
  | 	public String getDescription()
  | 	{
  | 		return description;
  | 	}
  | 
  | 	/**
  | 	 * @param description
  | 	 *            the description to set
  | 	 */
  | 	public void setDescription(String description)
  | 	{
  | 		this.description = description;
  | 	}
  | 
  | 	/**
  | 	 * @return the id
  | 	 */
  | 	public long getId()
  | 	{
  | 		return id;
  | 	}
  | 
  | 	/**
  | 	 * @param id
  | 	 *            the id to set
  | 	 */
  | 	public void setId(long id)
  | 	{
  | 		this.id = id;
  | 	}
  | 
  | 	/**
  | 	 * @return the name
  | 	 */
  | 	public String getName()
  | 	{
  | 		return name;
  | 	}
  | 
  | 	/**
  | 	 * @param name
  | 	 *            the name to set
  | 	 */
  | 	public void setName(String name)
  | 	{
  | 		this.name = name;
  | 	}
  | 
  | 	/**
  | 	 * @return the numberOfEntries
  | 	 */
  | 	public long getNumberOfEntries()
  | 	{
  | 		return numberOfEntries;
  | 	}
  | 
  | 	/**
  | 	 * @param numberOfEntries
  | 	 *            the numberOfEntries to set
  | 	 */
  | 	public void setNumberOfEntries(long numberOfEntries)
  | 	{
  | 		this.numberOfEntries = numberOfEntries;
  | 	}
  | 
  | 	/**
  | 	 * @return the parentId
  | 	 */
  | 	public long getParentId()
  | 	{
  | 		return parentId;
  | 	}
  | 
  | 	/**
  | 	 * @param parentId
  | 	 *            the parentId to set
  | 	 */
  | 	public void setParentId(long parentId)
  | 	{
  | 		this.parentId = parentId;
  | 	}
  | 
  | 	/**
  | 	 * @return the visible
  | 	 */
  | 	public Boolean getVisible()
  | 	{
  | 		return visible;
  | 	}
  | 
  | 	/**
  | 	 * @param visible
  | 	 *            the visible to set
  | 	 */
  | 	public void setVisible(Boolean visible)
  | 	{
  | 		this.visible = visible;
  | 	}
  | 
  | 	/**
  | 	 * @return Boolean
  | 	 */
  | 	@Transient
  | 	public Boolean isVisible()
  | 	{
  | 		return getVisible();
  | 	}
  | 
  | 	@Override
  | 	public String toString()
  | 	{
  | 		return ("Category(id:" + id + ", parentId:" + parentId + ", name:" + name + ", description:" + description + ", numberOfEntries:" + numberOfEntries + ", visible:" + visible + ")");
  | 	}
  | 
  | }
  | 

I have a SFSB defined here:

  | package com.mystuff.fresh.actions;
  | 
  | import static javax.persistence.PersistenceContextType.EXTENDED;
  | 
  | import java.util.List;
  | 
  | import javax.ejb.Remove;
  | import javax.ejb.Stateful;
  | import javax.persistence.EntityManager;
  | import javax.persistence.PersistenceContext;
  | 
  | import org.jboss.seam.annotations.Create;
  | import org.jboss.seam.annotations.Destroy;
  | import org.jboss.seam.annotations.Factory;
  | import org.jboss.seam.annotations.In;
  | import org.jboss.seam.annotations.Logger;
  | import org.jboss.seam.annotations.Name;
  | import org.jboss.seam.annotations.Out;
  | import org.jboss.seam.annotations.datamodel.DataModel;
  | import org.jboss.seam.annotations.datamodel.DataModelSelection;
  | import org.jboss.seam.log.Log;
  | 
  | import com.mystuff.fresh.domain.Category;
  | import com.mystuff.fresh.services.CategoryManager;
  | 
  | @Stateful
  | @Name("categoryManager")
  | public class CategoryManagerAction implements CategoryManager
  | {
  | 	@SuppressWarnings("unused")
  | 	@DataModel
  | 	private List<Category> categories;
  | 
  | 	@DataModelSelection
  | 	@In(required = false, create = false)
  | 	@Out(required = false)
  | 	private Category currentCategory;
  | 
  | 	@Out(required = false)
  | 	Category rootCategory;
  | 
  | 	@PersistenceContext(type = EXTENDED)
  | 	private EntityManager em;
  | 
  | 	@Logger
  | 	private static Log log;
  | 
  | 	@Factory("rootCategory")
  | 	public String findRoot()
  | 	{
  | 		log.trace("findRoot() called");
  | 		rootCategory = (Category) em.createNamedQuery("Category.findRoot").getSingleResult();
  | 		return "success";
  | 	}
  | 
  | 	@SuppressWarnings("unchecked")
  | 	@Factory("categories")
  | 	public String findCategories()
  | 	{
  | 		log.trace("findAll() called");
  | 		categories = em.createNamedQuery("Category.findAll").getResultList();
  | 		return "success";
  | 	}
  | 
  | 	// TODO: Need to find a way to initialize currentCategory at startup of the
  | 	// session so that
  | 	// It is available before any page loads. This is a current issue with the
  | 	// home.xhtml
  | 	// which wants to display the current category before referencing categories
  | 	@Create
  | 	public String init()
  | 	{
  | 		log.trace("init() called");
  | 
  | 		if (currentCategory == null)
  | 		{
  | 			log.warn("init() currentCategory is NULL");
  | 			currentCategory = (Category) em.createNamedQuery("Category.findRoot").getSingleResult();
  | 		}
  | 
  | 		log.info("init() - currentCategory: #0", currentCategory);
  | 		return "success";
  | 	}
  | 
  | 	public void select()
  | 	{
  | 		return;
  | 	}
  | 
  | 	@Remove
  | 	@Destroy
  | 	public void destroy()
  | 	{
  | 	}
  | }
  | 

On the homepage, I want to display the list of Categories, with the currentCategory displayed with a graphic (a bullet) next to it:

home.xhtml

  | <!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
  |                       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  | <ui:composition xmlns="http://www.w3.org/1999/xhtml"
  |                 xmlns:s="http://jboss.com/products/seam/taglib"
  |                 xmlns:ui="http://java.sun.com/jsf/facelets"
  |                 xmlns:f="http://java.sun.com/jsf/core"
  |                 xmlns:h="http://java.sun.com/jsf/html"
  |                 template="/layout/template.xhtml">
  | 
  | <ui:define name="body">
  | 
  |     <h:messages globalOnly="true" styleClass="message"/>
  |     <h:outputText value="CurrentCategory: #{currentCategory.name}"/>
  | 
  | 	<table class="standard">
  | 		<tr>
  | 			<td width="18%">
  | 				<ui:include src="/layout/categories.xhtml"/>
  | 			</td>
  | 		</tr>
  | 	</table>
  | 
  | 	
  | 	
  | </ui:define> 
  | </ui:composition>
  | 

which includes the following xhtml snippet:
categories.xhtml

  | <div class="category" 
  |      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"
  |      xmlns:s="http://jboss.com/products/seam/taglib">
  | <h:form id="categorylistform">
  | <h:outputText value="No categories to display" rendered="#{categories.rowCount==0}"/>
  | <h:dataTable styleclass="category" value="#{categories}" var="cat" rendered="#{categories.rowCount>0}">
  |     <h:column>
  |     	<h:graphicImage styleClass="vcenter" id="selectedcategoryimage" alt="selected category" url="/img/pic_selected_dot_9x9.gif" rendered="#{cat.id==currentCategory.id}"/>
  |    	</h:column>
  |     <h:column>
  |         <h:commandLink styleClass="topcategory" value="#{cat.name}" title="#{cat.description}" action="#{categoryManager.select}" rendered="#{cat.parentId == rootCategory.id}"/>
  |         <h:commandLink styleClass="childcategory" value="#{cat.name}" title="#{cat.description}" action="#{categoryManager.select}" rendered="#{cat.parentId != rootCategory.id}"/>
  |         <h:outputText value="   (#{cat.numberOfEntries})"/>
  |     </h:column>
  | </h:dataTable>
  | </h:form>
  | </div>
  | 

here is a sample of the data loaded by import.sql:

  | insert into Category (id, parentId, name, description, visible, numberOfEntries) values (0, 0, 'All', 'All description', true, 0)
  | insert into Category (id, parentId, name, description, visible, numberOfEntries) values (1, 0, 'Arts', 'Arts description', true, 0)
  | insert into Category (id, parentId, name, description, visible, numberOfEntries) values (2, 1, 'Art', 'Arts | Art description', true, 0)
  | insert into Category (id, parentId, name, description, visible, numberOfEntries) values (3, 1, 'Books', 'Arts | Books description', true, 2)
  | insert into Category (id, parentId, name, description, visible, numberOfEntries) values (4, 1, 'Movies', 'Arts | Movies description', true, 0)
  | insert into Category (id, parentId, name, description, visible, numberOfEntries) values (5, 1, 'Music', 'Arts | Music description', true, 0)
  | insert into Category (id, parentId, name, description, visible, numberOfEntries) values (6, 1, 'Television', 'Arts | Television description', true, 0)
  | insert into Category (id, parentId, name, description, visible, numberOfEntries) values (7, 1, 'Theater', 'Arts | Theater description', true, 0)
  | insert into Category (id, parentId, name, description, visible, numberOfEntries) values (8, 0, 'Business', 'Business description', true, 0)
  | 


Again, my goal is to remember what category the user has selected.  I made currentCategory a SESSION scoped context variable.  CategoryManagerAction is CONVERSATION component.

When I first load up home.xhtml, currentCategory is set to the Root Category result returned from entitymanager and the bullet appears next to the root category (All in this case).

When I click on a another category, the page refreshes and the bullet appears on the newly selected category (Books for example).

My issue is that if I refresh the page (using the browser refresh), the bullet disappears (I would expect it to be drawn next to Books).

If I hit refresh a second time, a bullet appears next to All.

It is as if the currentCategory is lost after the response is written.  I checked debug.seam after clicking hitting refresh, and I see currentCategory in the SESSION, and it has the correct Book value.

Am I correct in defining currentCategory to be SESSION scoped in the entity, and setting it from the CONVERSATION scoped SFSB?

Is there a better way to organize this?  Do I need @Factory("currentCategory") on a method on the SFSB to make this all work?



View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4052845#4052845

Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4052845




More information about the jboss-user mailing list