2 Replies Latest reply on Mar 4, 2008 11:55 AM by seammm

    turning seam generated home object to stateful home

    seammm

      hi - i basically made a STATEFUL class OrganizationHome extends EntityHome(Organization) implements OrganizationHomeLocal


      extra methods for @Destroy @Remove etc. are in place.


      when i call the page that refers to OrganizationHome, i get Could not instantiate Seam component: organizationHome Caused by: javax.naming.NameNotFoundException: OrganizationHome not bound.


      so the question is if turning seam generated home beans to stateful beans encouraged and how would you implement it?


      thanks.



        • 1. Re: turning seam generated home object to stateful home
          nickarls

          Show some code. Do you have a @Name annotation? Do you get any exceptions on deploy?

          • 2. Re: turning seam generated home object to stateful home
            seammm

            Nicklas Hi - I have the @Name annotation but I was missing the @Local annotation and bunch of other declarations in the interface and overrides in the bean. At 3am, one needs a fresh pair of eyeballs I guess.



                 public boolean isManaged();
                 public Organization getInstance();
                 public String remove();
            



            That took care of the xxx not bound error. But I have a different error now, which is EntityManager is closed.


            There are organizationList.xhtml and organization.xhtml as generated by Seam and hand modified back bean OrganizationHome and OrganizationHomeLocal.


            I browse organizations using organizationList.xhtml, edit an organization using organization.xhtml, and get out of edit mode using the untouched Done button.


            Upon second time I try to enter edit mode by clicking on any of the organizations results in EntityManager is closed.


            Actual code is below..


            Second thing that HALF works is that, if you look at the organization.xhtml, I am trying to implement a ui pattern to manage many-to-many relations with the extra complexity of categorization.


            So the user edits an Organization AND the Products it is allowed to see. Since the Products can be a lot, I categorize the products. User sees the Organization fields AND list of categories parent of which is hardcoded if not specified in the request parameter, AND the Products the category of which is the current category. User selects/unselects Product using the checkboxes and backing productSelection map.


            The problem is, Product selection hashmap is not passed the correct values from the checkboxes in the ui, if user ventured into sub categories. However it works if the user don't go into sub categories but select/unselect whatever products are under default category. I don't know how clear that was but it is in the code.


            I think once it works, it will be a nice ui pattern for managing large many-to-many relations.


            And yes, I tried RF ListShuttle but I couldn't add categorization to its left side so I gave up.


            Thanks.


            @Stateful
            @Scope(ScopeType.SESSION)
            @Name("organizationHome")
            public class OrganizationHome extends EntityHome<Organization> implements OrganizationHomeLocal
            {
                 static final Long DEFAULT_CATEGORY_ID = new Long(1);
                 
                @RequestParameter 
                Long organizationId;
            
                @RequestParameter 
                Long categoryId;
            
                private Map<Product, Boolean> productSelection = new HashMap<Product, Boolean>();
            
                @Logger
                Log log;
                
                @Override
                public Object getId() 
                { 
                    if (organizationId==null)
                    {
                        return super.getId();
                    }
                    else
                    {
                        return organizationId;
                    }
                }
                
                @Override @Begin
                public void create() 
                {
                    super.create();
                    productSelection = new HashMap<Product, Boolean>();
                }
                  
                private void persistProducts()
                {
                     getInstance().getProductList().clear();
                     
                     Set<Product> keys = productSelection.keySet();
                     for (Product p: keys)
                     {
                          log.info("key {0} value {1}", p.getName(), productSelection.get(p));
                          
                          if (productSelection.get(p))
                          {
                               getInstance().getProductList().add(p);
                               log.info("selected {0}", p.getName());
                          }
                     }
                     
                     getEntityManager().merge(getInstance());
                }
                
                @Override
                public String persist()
                {
                     attachInstanceToEntityManager();
                     String s = super.persist();
                     persistProducts();
                     return s;
                }
                
                @Override
                 public Organization getInstance() 
                {
                      return super.getInstance();
                 }
            
                 @Override
                 @Transactional
                public String update()
                {
                      attachInstanceToEntityManager();
                     persistProducts();
                     return super.update();
                }
            
                @Factory(value="productList", scope=ScopeType.EVENT)
                public List<Product> findProducts()
                {
                     if (categoryId == null)
                     {
                          categoryId = DEFAULT_CATEGORY_ID;
                     }
            
                     return getEntityManager().createQuery("select pc.product from ProductCategory pc where pc.category.id = :categoryId order by pc.product.name")
                            .setParameter("categoryId", categoryId)
                          .getResultList();
                }
                
            //    @Factory(value="categoryList", scope=ScopeType.EVENT)
            //    public List<Category> findCategories()
            //    {
            //         if (categoryId == null)
            //         {
            //              categoryId = DEFAULT_CATEGORY_ID;
            //         }
            //         
            //         return getEntityManager().createQuery("from Category where parent.id = :parentId order by name")
            //              .setParameter("parentId", categoryId)
            //                .getResultList();
            //    }
            
                @Remove @Destroy
                public void destroy() {}
            
                 public Map<Product, Boolean> getProductSelection() {
                      return productSelection;
                 }
            
                 public void setProductSelection(Map<Product, Boolean> productSelection) {
                      this.productSelection = productSelection;
                 }
            
                 @Override
                 @Transactional
                 public boolean isManaged() 
                 {
                      attachInstanceToEntityManager();
                      return super.isManaged();
                 }
            
                 @Override
                 protected Organization loadInstance() 
                 {
                      Organization o = super.loadInstance();
                      
                     for (Product p: o.getProductList())
                     {
                          productSelection.put(p, true);
                     }
                      
                      return o;
                 }
            
                 @Override
                 @Transactional
                 public String remove() 
                 {
                      attachInstanceToEntityManager();
                      return super.remove();
                 }
                 
                 /**
                 * if super.isManaged() returns false, but getInstance() has an Id, then
                 * instance needs to be re-attached to the entityManager in order to
                 * prevent "detached entity passed to persist" exceptions.
                 */
                private void attachInstanceToEntityManager() 
                {
                     log.info("** attach called");
                     
                    if (!super.isManaged() && getInstance().getId() != null) 
                    {
                         log.info("** attach " + getInstance());
                         
                        setInstance(getEntityManager().merge(getInstance()));
                    }
                }
                
                /**
                 * Need to null out entityManagers prior to passivation so that they'll get
                 * reinitialized upon subsequent reqests. Failing to do this in a clustered
                 * environment will result in "EntityManager is closed" error messages.
                 */
                @PrePassivate
                public void prePassivate() 
                {
                    setEntityManager(null);
                }
            }
            
            



            @Name("categoryList")
            public class CategoryList extends EntityQuery
            {
                 static final Long DEFAULT_CATEGORY_ID = new Long(1);
            
                 @RequestParameter 
                Long categoryId;
            
                 @Logger
                 Log log;
                 
                @Override
                public String getEjbql() 
                { 
                     if (categoryId == null)
                     {
                          categoryId = DEFAULT_CATEGORY_ID;
                     }
                     
                     log.info("** from Category where parent.id = " + categoryId + " order by name");
                     
                     return ("from Category where parent.id = " + categoryId + " order by name");
                }
            }
            
            



            <!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"
                            xmlns:rich="http://richfaces.org/rich"
                            template="layout/template.xhtml">
                                   
            <ui:define name="body">
                
                <h:messages globalOnly="true" styleClass="message"/>
                
                <h:form id="organizationForm">
            
                    <rich:panel>
                        <f:facet name="header">organization</f:facet>
                
                        <s:decorate id="nameDecoration" template="layout/edit.xhtml">
                            <ui:define name="label">Name</ui:define>
                            <h:inputText id="name" required="true"
                                         value="#{organizationHome.instance.name}"/>
                        </s:decorate>
                        
                        <div style="clear:both"/>
                        
                    </rich:panel>
            
                <rich:panel>
                    <f:facet name="header">productList</f:facet>
                    
                    <div class="results">
                                       
                        <h:dataTable id="categoryList" var="category"
                                  value="#{categoryList.resultList}" 
                               rendered="#{not empty categoryList.resultList}">
                            <h:column>
                                <s:link id="category" 
                                     value="#{category.name}" 
                                     view="/organization.xhtml">
                                    <f:param name="categoryId" 
                                            value="#{category.id}"/>
                                </s:link>
                            </h:column>
                        </h:dataTable>
            
                        <h:outputText value="No product exists" 
                                   rendered="#{empty productList}"/>
            
                        <h:dataTable id="productList" var="product"
                                  value="#{productList}" 
                               rendered="#{not empty productList}">
                            <h:column>
                                 <h:selectBooleanCheckbox value="#{organizationHome.productSelection[product]}"/>
                            </h:column>
                            <h:column>
                                <f:facet name="header">Name</f:facet>
                                <s:link id="product" 
                                     value="#{product.name}" 
                                     view="/product.xhtml">
                                    <f:param name="productId" 
                                            value="#{product.id}"/>
                                </s:link>
                            </h:column>
                        </h:dataTable>
                    
                    </div>
                    
                </rich:panel>
            
                    <div class="actionButtons">
                        <h:commandButton id="save" 
                                      value="Save" 
                                     action="#{organizationHome.persist}"
                                   rendered="#{!organizationHome.managed}"/>                   
                        <h:commandButton id="update" 
                                      value="Save" 
                                     action="#{organizationHome.update}"
                                   rendered="#{organizationHome.managed}"/>                  
                        <h:commandButton id="delete" 
                                      value="Delete" 
                                     action="#{organizationHome.remove}"
                                   rendered="#{organizationHome.managed}"/>
                        <s:button propagation="end" 
                                           id="done" 
                                        value="Done"
                                         view="/organizationList.xhtml"/>
                    </div>
            
            
                    
                </h:form>
                
            </ui:define>
            
            </ui:composition>
            



            @Entity
            public class Category implements Serializable {
                 
                 private Long id;
                 private String name;
                 private Category parent;
                 private List<Category> children;
            ...
            



            @Entity
            public class Organization implements Serializable {
                 
                 private Long id;
                 private String name;
            
                 private List<Product> productList;
            ...
            



            @Entity
            public class Product implements Serializable {
                 
                 private Long id;
                 private String name;
            ...
            



            @Entity
            public class OrganizationProduct implements Serializable {
                 
                 private Long id;
                 private Organization organization;
                 private Product product;
            ...
            



            @Entity
            public class ProductCategory implements Serializable {
                 
                 private Long id;
                 private Product product;
                 private Category category;
            ...