1 Reply Latest reply on Jul 20, 2006 4:36 AM by bfo81

    Getting the Update part of CRUD to work

    metaman

      Hello there.

      I am currently evaluating the use of JBoss Seam for my organization.

      After getting a Seam skeleton app to successfully start (generated with SeamGen), I implemented the create, read and delete parts of a very simple and primtive CRUD use case for a single entity bean.

      But now I am struck, because I cant find a way to update an entity bean with new values. After looking at the code which is generated by the hibernate reverse engineering tool, I took my inspiration from the EntitySelector pattern (if I may call it so).

      It works like this:

      Ingredients:
      Entity
      listEntityAction stateful session bean
      editEntityAction stateful session bean
      EntitySelector stateless session bean


      1.) An listEntity.xhtml page is backed by the listEntityAction SFSB. The Data is displayed in a DataTable, and after selecting something from the data table, a button on the editEntity page, has to be pressed.

      2.) Pressing the button calls a method of the EntitySelector, which mediates between the two SFSB. It has references injected for listEntityAction and editEntityAction. Right now all that the EntitySelector has to do, is ask the listEntityAction.getSelection() and pass it over to editEntityAction.initEdit()

      3.) Then editEntity.xhtml is displayed with the contents of the selected entity, the user can change the values, and after pressing a button, the backing editEntityAction merges the entity back to the persistence layer.

      Below is the code.

      Sadly, it just does not work, because the EntitySelector SLSB can`t seem to call a method from the injected SFSB`s. (My guess is that somehow the injection does not work.)

      It would be really great if somebody could tell me why my code does not work, or if there is an easier pattern to achive the whole CRUD work. (after all, I am not the only person wanting to write this code manually.)

      My Entity is called "Ware.java":

      import java.io.Serializable;
      import javax.persistence.Entity;
      import javax.persistence.GeneratedValue;
      import javax.persistence.Id;
      import javax.persistence.Lob;
      
      import org.hibernate.validator.Length;
      import org.hibernate.validator.NotNull;
      import org.hibernate.validator.Range;
      import org.jboss.seam.annotations.Name;
      
      @Entity
      @Name("ware")
      public class Ware implements Serializable{
      
       private Long id;
       private String name;
       private String beschreibung;
       private int bewertung;
       private float gewicht;
      
       public Ware() {}
      
       @Id @GeneratedValue
       public Long getId()
       {
       return id;
       }
       public void setId(Long id)
       {
       this.id = id;
       }
      
       @NotNull
       @Lob
       public String getBeschreibung() {
       return beschreibung;
       }
       public void setBeschreibung(String beschreibung) {
       this.beschreibung = beschreibung;
       }
      
       @NotNull
       @Range(min=1, max=5)
       public int getBewertung() {
       return bewertung;
       }
       public void setBewertung(int bewertung) {
       this.bewertung = bewertung;
       }
      
       @NotNull
       public float getGewicht() {
       return gewicht;
       }
       public void setGewicht(float gewicht) {
       this.gewicht = gewicht;
       }
      
       @NotNull
       @Length(min=0, max=40)
       public String getName() {
       return name;
       }
       public void setName(String name) {
       this.name = name;
       }
      
       public String toString()
       {
       return "Ware( Id: " + id + " )";
       }
      }
      


      The listWaren local interface:
      import javax.ejb.Local;
      
      @Local
      public interface ListWaren
      {
       public String deleteWare();
       public void findWare();
       public void refresh();
       public Ware getSelection();
       public void destroy();
      }
      


      This is the listWarenAction statefull session bean:
      import static javax.persistence.PersistenceContextType.EXTENDED;
      import static org.jboss.seam.ScopeType.SESSION;
      import java.io.Serializable;
      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.Destroy;
      import org.jboss.seam.annotations.Factory;
      import org.jboss.seam.annotations.In;
      import org.jboss.seam.annotations.Name;
      import org.jboss.seam.annotations.Out;
      import org.jboss.seam.annotations.Scope;
      import org.jboss.seam.annotations.datamodel.DataModel;
      import org.jboss.seam.annotations.datamodel.DataModelSelection;
      import org.jboss.seam.annotations.Logger;
      import org.jboss.seam.log.Log;
      
      @Stateful
      @Scope(SESSION)
      @Name("listWaren")
      public class ListWarenAction implements ListWaren, Serializable
      {
      
       @Logger private Log log;
       @PersistenceContext(type=EXTENDED)
       private EntityManager em;
      
       @In(create=true)
       EditWaren editWaren;
      
       @DataModel
       private List<Ware> allWaren;
      
       @DataModelSelection
       @In(required=false) @Out(required=false)
      
       private Ware oneWare;
      
       @Factory("allWaren")
       public void findWare()
       {
       executeQuery();
       }
      
       public void refresh()
       {
       executeQuery();
       }
      
       private void executeQuery()
       {
       allWaren = em.createQuery("from Ware e").getResultList();
       }
      
       public String deleteWare()
       {
       allWaren.remove(oneWare);
       em.remove(oneWare);
       oneWare=null;
       return "Usecase-Manager.seam";
       }
      
      
      
       public Ware getSelection()
       {
       return em.merge(oneWare);
       }
      
       @Remove @Destroy
       public void destroy() {}
      }
      


      The editWaren local interface:
      import javax.ejb.Local;
      @Local
      public interface EditWaren
      {
       public boolean isNew();
       public void setNew(boolean isNew);
       public void initCreate();
       public String createWare();
       public void initEdit(Ware editThisWare);
       public String editWare();
       public void destroy();
      }
      


      Then there is the editWarenAction statefull session bean:
      import static javax.persistence.PersistenceContextType.EXTENDED;
      import static org.jboss.seam.ScopeType.SESSION;
      import java.io.Serializable;
      import javax.ejb.Remove;
      import javax.ejb.Stateful;
      import javax.persistence.EntityManager;
      import javax.persistence.PersistenceContext;
      import org.jboss.seam.annotations.Destroy;
      import org.jboss.seam.annotations.End;
      import org.jboss.seam.annotations.In;
      import org.jboss.seam.annotations.Name;
      import org.jboss.seam.annotations.Logger;
      import org.jboss.seam.annotations.Scope;
      import org.jboss.seam.log.Log;
      
      @Stateful
      @Scope(SESSION)
      @Name("editWaren")
      public class EditWarenAction implements EditWaren, Serializable
      {
       @Logger private Log log;
      
       @PersistenceContext(type=EXTENDED)
       private EntityManager em;
      
       @In
       private Ware ware;
      
       @In(required = false)
       private transient ListWaren listWaren;
      
       private boolean isNew;
       public boolean isNew() {
       return isNew;
       }
       public void setNew(boolean isNew) {
       this.isNew = isNew;
       }
      
       public void initCreate()
       {
       isNew = true;
       ware = new Ware();
       }
      
       public String createWare()
       {
       em.persist(ware);
       listWaren.refresh();
       return "/listWare.seam";
       }
      
       public void initEdit(Ware editThisWare)
       {
       isNew = false;
       ware = editThisWare;
       }
      
       public String editWare()
       {
       em.merge(ware);
       listWaren.refresh();
       return "/listWare.seam";
       }
      
       @Remove @Destroy
       public void destroy() {}
      }
      


      And finaly the WarenSelector stateless session bean and its local interface:
      import javax.ejb.Local;
      
      @Local
      public interface WarenSelector {
       public String callCreate();
       public String callEdit();
      }
      


      import static org.jboss.seam.ScopeType.SESSION;
      import javax.ejb.Remove;
      import javax.ejb.Stateless;
      import org.jboss.seam.annotations.Begin;
      import org.jboss.seam.annotations.Destroy;
      import org.jboss.seam.annotations.In;
      import org.jboss.seam.annotations.Name;
      import org.jboss.seam.annotations.Scope;
      
      @Stateless
      @Scope(SESSION)
      @Name("warenSelector")
      
      public class DefaultWarenSelector implements WarenSelector {
       @In(create=true)
       private transient EditWaren editWaren;
      
       @In(create=true)
       private transient ListWaren listWaren;
      
       public String callCreate()
       {
       editWaren.initCreate();
       return "/editWaren.jsp";
       }
      
       public String callEdit()
       {
       editWaren.initEdit(listWaren.getSelection());
       return "/editWaren.jsp";
       }
      
       @Remove @Destroy
       public void destroy() {}
      
      }
      


      Here are the two xhtml Pages:

      listWare.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:s="http://jboss.com/products/seam/taglib"
       xmlns:ui="http://java.sun.com/jsf/facelets"
       xmlns:f="http://java.sun.com/jsf"
       xmlns:h="http://java.sun.com/jsf/html">
      <body>
      
       <f:view>
       <h:outputText value="Keine Waren existieren" rendered="#{allWaren != null and allWaren.rowCount==0}"/>
       <h:dataTable value="#{allWaren}" var="oneWare" rendered="#{allWaren.rowCount>0}">
       <h:column>
       <f:facet name="header">
       <h:outputText value="ID der Ware"/>
       </f:facet>
       <h:outputText value="#{oneWare.id}"/>
       </h:column>
       <h:column>
       <f:facet name="header">
       <h:outputText value="Name der Ware"/>
       </f:facet>
       <h:outputText value="#{oneWare.name}"/>
       </h:column>
       <h:column>
       <f:facet name="header">
       <h:outputText value="Beschreibung der Ware"/>
       </f:facet>
       <h:outputText value="#{oneWare.beschreibung}"/>
       </h:column>
      
       <h:column>
       <f:facet name="header">
       <h:outputText value="Bewertung der Ware"/>
       </f:facet>
       <h:outputText value="#{oneWare.bewertung}">
       <f:convertNumber type="number" integerOnly="true"/>
       </h:outputText>
       </h:column>
       <h:column>
       <f:facet name="header">
       <h:outputText value="Gewicht der Ware"/>
       </f:facet>
       <h:outputText value="#{oneWare.gewicht}">
       <f:convertNumber type="number" integerOnly="false"/>
       </h:outputText>
       </h:column>
      
       <h:column>
       <s:link value="Delete!" action="#{listWaren.deleteWare}"/>
       </h:column>
      
       <h:column>
       <s:link value="Edit!" action="#{warenSelector.callEdit}"/>
       </h:column>
      
      
       </h:dataTable>
      
      
       <s:link value="Create!" action="#{warenSelector.callCreate}"/>
      
       </f:view>
      
      </body>
      </html>
      


      And editWare.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:s="http://jboss.com/products/seam/taglib"
       xmlns:ui="http://java.sun.com/jsf/facelets"
       xmlns:f="http://java.sun.com/jsf"
       xmlns:h="http://java.sun.com/jsf/html">
      <body>
      
      <f:view>
       <h:form>
       <table border="0">
       <s:validateAll>
       <tr>
       <td>ID</td>
       <td><h:outputText value="#{ware.id}"/></td>
       </tr>
       <tr>
       <td>Name</td>
       <td><h:inputText id="warename" value="#{ware.name}" required="true"/></td>
       <td><h:message for="warename"/></td>
       </tr>
       <tr>
       <td>Beschreibung</td>
       <td><h:inputText id="warebeschreibung" value="#{ware.beschreibung}" required="true"/></td>
       <td><h:message for="warebeschreibung"/></td>
       </tr>
       <tr>
       <td>Bewertung</td>
       <td>
       <h:inputText id="warebewertung" value="#{ware.bewertung}" required="true">
       <f:convertNumber integerOnly="true"/>
       </h:inputText>
       </td>
       <td><h:message for="warebewertung"/></td>
       </tr>
       <tr>
       <td>Gewicht</td>
       <td>
       <h:inputText id="waregewicht" value="#{ware.gewicht}" required="true">
       <f:convertNumber type="number" integerOnly="false"/>
       </h:inputText>
       </td>
       <td><h:message for="waregewicht"/></td>
       </tr>
      
       </s:validateAll>
       </table>
       <h:messages/>
       <h:commandButton type="submit" value="Create it" action="#{editWaren.createWare}" rendered="#{editWaren.isNew}"/>
       <h:commandButton type="submit" value="Edit it" action="#{editWaren.editWare}" rendered="#{!editWaren.isNew}"/>
      
       </h:form>
       </f:view>
      
      
      </body>
      </html>
      



      If the configuration files are necessary, then I will post them as well.


      Thanks for any help, in advance !

        • 1. Re: Getting the Update part of CRUD to work
          bfo81

          Your navigation outcomes contain *.seam and *.jsp, but it should be *.xhtml. But I don't know if this is the problem.

          Well, in my opinion it's not that nice to have a selector. I prefer injecting the list directly into the edit bean and unpacking it in an action method. But that's something you can argue about ;).

          However, something else: In the edit bean the ware needs to be outjected, too. Otherwise you cannot access the ware in your edit jsf page. Or am I off the track here?

          PS: When reading posts like yours I'd really like to write in our native language since that would be easier ;).