4 Replies Latest reply on Mar 9, 2006 2:54 AM by Jens Weintraut

    Problem with bijecting

    Jens Weintraut Apprentice

      Hi,

      I'm encountering a problem with bijecting and don't know how to solve it. I think for you it's an obvious mistake I made, but I don't have any idea.

      Like the hotel list in the booking example I've a list of elements in my application. Each of them has an ID, which is clickable. After a click on an elements ID, the user is navigated to a page (let's call it detailPage) which shows the details of the selected element. This works fine.
      I've a class (Seam component) for each one of the two pages, ShowList and ShowElement. The ShowList class keeps the DataModel and DataModelSelection. Clicking on an element the DataModelSelection is passed to detailPage. The element is injected in the ShowElement class, where I use it to show some additional information related to this element.

      Now I want to add the possibility to change some details. After saving the changes the next element should be shown to the user.
      Therefore I added a commandButton (submit) which calls a method in ShowElement, which saves the changes. Then I want to get the next element of the list and outject it to the same page. But as soon as the user clicks the submit button, the element is nulled. I would expect that the changed element is injected, which then could be saved.

      There is some code, which hopefully explains my problem:

      The component keeping the list:

      @Stateful
      @Scope(ScopeType.SESSION)
      @LoggedIn
      @Name("showListForDevelopers")
      @Interceptors(SeamInterceptor.class)
      public class ShowListForDevelopers implements IShowListForDevelopers, Serializable {
       @PersistenceContext(unitName = "aresDatabase", type=PersistenceContextType.EXTENDED)
       private EntityManager em;
      
       @In @Valid
       private User user;
      
       @DataModel
       private List<Testaction> testactions;
      
       @DataModelSelection
       @Out(required = false)
       private Testaction currentTestaction;
      
       @Factory("testactions")
       public void getTestactions() {
       testactions = em.createQuery(
       "from Testaction where TACT_DEV_USR_ID=:dev order by TACT_ID asc"
       ).setParameter("dev", user.getID()).getResultList();
       }
      
       public String select() {
       return "selected";
       }
      
       @Remove @Destroy
       public void destroy() {
       }
      }


      I skip the page displaying the list, it's a simple dataTable.
      The page showing the element (not the complete page):
      <h:form>
       <div class="errors">
       <h:messages globalOnly="true" />
       </div>
       <div class="buttonBox">
       <h:commandButton action="#{showTestactionForDevelopers.saveTestaction}"
       value="Save and Next" class="button" type="submit"
       immediate="true" />
       </div>
       <table cellpadding="0" cellspacing="0" border="0">
       <tr>
       <th><h:outputText value="#{ares_messages.label_testaction_ID}" /></th>
       <th><h:outputText value="#{ares_messages.label_testaction_TDate}" /></th>
       <th><h:outputText value="#{ares_messages.label_testaction_TCaseID}" /></th>
       <th><h:outputText value="#{ares_messages.label_testaction_TesterUsrID}" /></th>
       <th><h:outputText value="#{ares_messages.label_testaction_EnvID}" /></th>
       <th><h:outputText value="#{ares_messages.label_testaction_SevID}" /></th>
       <th><h:outputText value="#{ares_messages.label_testaction_EditorUsrID}" /></th>
       <th><h:outputText value="#{ares_messages.label_testaction_DevUsrID}" /></th>
       <th><h:outputText value="#{ares_messages.label_testaction_RevID}" /></th>
       <th><h:outputText value="#{ares_messages.label_testaction_ChnglistID}" /></th>
       <th><h:outputText value="#{ares_messages.label_testaction_ValidatorUsrID}" /></th>
       <th> </th>
       </tr>
       <tr>
       <td><h:outputText value="#{currentTestaction.ID}" /></td>
       <td><h:outputText value="#{currentTestaction.TDate}" /></td>
       <td>
       <h:selectOneMenu value="#{currentTestaction.TCaseID}">
       <f:selectItems value="#{showTestactionForDevelopers.testcases}" />
       </h:selectOneMenu>
       </td>
       <td><h:outputText value="#{currentTestaction.testerUsrID}" /></td>
       <td><h:outputText value="#{currentTestaction.envID}" /></td>
       <td><h:outputText value="#{currentTestaction.sevID}" /></td>
       <td><h:outputText value="#{currentTestaction.editorUsrID}" /></td>
       <td>
       <h:selectOneMenu value="#{currentTestaction.devUsrID}">
       <f:selectItems value="#{showTestactionForDevelopers.developers}" />
       </h:selectOneMenu>
       </td>
       <td>
       <h:selectOneMenu value="#{currentTestaction.revID}">
       <f:selectItems value="#{showTestactionForDevelopers.revisions}" />
       </h:selectOneMenu>
       </td>
       <td><h:inputText value="#{currentTestaction.chnglistID}" /></td>
       <td><h:outputText value="#{currentTestaction.validatorUsrID}" /></td>
       <td> </td>
       </tr>
       </table>
      </h:form>


      The component which should save the element:
      @Stateful
      @Scope(ScopeType.SESSION)
      @LoggedIn
      @Name("showTestactionForDevelopers")
      @Interceptors(SeamInterceptor.class)
      public class ShowTestactionForDevelopers implements IShowTestactionForDevelopers{
       @PersistenceContext(unitName = "aresDatabase", type = PersistenceContextType.EXTENDED)
       private EntityManager em;
      
       @In(required=false) @Out(scope=ScopeType.EVENT)
       //@In(required=false) just for test purposes
       @Valid
       private Testaction currentTestaction;
      
       @In
       @Valid
       private User user;
      
       private List<Testcase> testcases;
       private List<User> developers;
       private List<Revisionclass> revisions;
       private List<Testaction> testactions;
      
       public String saveTestaction() {
       System.out.println("Saving testaction " + currentTestaction.getID());
       if(testactions == null) {
       testactions = em.createQuery(
       "from Testaction where TACT_DEV_USR_ID=:dev order by TACT_ID asc"
       ).setParameter("dev", user.getID()).getResultList();
       }
       ListIterator<Testaction> testactionsIter = testactions.listIterator(testactions.indexOf(currentTestaction));
       if(testactionsIter.hasNext()) {
       currentTestaction = testactionsIter.next();
       return "next";
       }
       return "noMore";
       }
      
       public SelectItem[] getTestcases() {
       List<Testcase> testcasesFromDB;
       if(testcases == null || testcases.get(0).getTObjID() != currentTestaction.getTObjID()) {
       testcasesFromDB = em.createQuery(
       "from Testcase where TCASE_TOBJ_ID=:tobj order by TCASE_ID asc"
       ).setParameter("tobj", currentTestaction.getTObjID()).getResultList();
       } else {
       testcasesFromDB = testcases;
       }
       SelectItem[] result = new SelectItem[testcasesFromDB.size()];
       for(int i = 0; i < testcasesFromDB.size(); i++) {
       Testcase testcase = testcasesFromDB.get(i);
       result = new SelectItem(testcase.getID(), testcase.getID() + " - " + testcase.getToken());
       }
       return result;
       }
      
       public SelectItem[] getDevelopers() {
       if(developers == null) {
       developers = em.createQuery(
       "from User where USR_ISDEVELOPER=-1 order by USR_NAME asc"
       ).getResultList();
       }
      
       SelectItem[] result = new SelectItem[developers.size()];
       for(int i = 0; i < developers.size(); i++) {
       User user = developers.get(i);
       result = new SelectItem(user.getID(), user.getID() + " - " + user.getName());
       }
       return result;
       }
      
       public SelectItem[] getRevisions() {
       if(revisions == null) {
       revisions = em.createQuery(
       "from Revisionclass order by REV_ID asc"
       ).getResultList();
       }
      
       SelectItem[] result = new SelectItem[revisions.size()];
       for(int i = 0; i < revisions.size(); i++) {
       Revisionclass revision = revisions.get(i);
       result = new SelectItem(revision.getID(), revision.getID() + " - " + revision.getDescr());
       }
       return result;
       }
      
       public Long getSelectedTestcase() {
       if(currentTestaction == null) {
       return new Long(-1);
       }
       return currentTestaction.getTCaseID();
       }
      
       public String getSelectedDeveloper() {
       if(currentTestaction == null) {
       return "";
       }
       return currentTestaction.getDevUsrID();
       }
      
       public Integer getSelectedRevision() {
       if(currentTestaction == null) {
       return new Integer(-1);
       }
       return currentTestaction.getRevID();
       }
      
       @Destroy @Remove
       public void destroy() {
       }
       }


      Please let me know if there are some questions left.

      Thanks
      Newlukai

        • 1. Re: Problem with bijecting
          Jens Weintraut Apprentice

           

          public class ShowTestactionForDevelopers implements IShowTestactionForDevelopers{
           @PersistenceContext(unitName = "aresDatabase", type = PersistenceContextType.EXTENDED)
           private EntityManager em;
          
           @In(required=false) @Out(scope=ScopeType.EVENT)
           //@In(required=false) just for test purposes


          The EVENT Scope for outjecting was added for test purposes only.

          • 2. Re: Problem with bijecting
            Jens Weintraut Apprentice

            Perhaps it gives you a hint: If I move all the functions from ShowElement to ShowList, it works ...
            Any idea?

            • 3. Re: Problem with bijecting
              Gavin King Master

              Sorry, your example code is simply too complicated. Try and massively simplify it down to the bare concepts, and if it is not then obvious what the problem is, post the simplified code.

              • 4. Re: Problem with bijecting
                Jens Weintraut Apprentice

                OK. I try to simplify it. Perhaps my description is too complex for my simple problem.

                I've two classes. The first has a factory method for a DataModel.

                @Stateful
                @Scope(ScopeType.SESSION)
                @LoggedIn
                @Name("showListForDevelopers")
                @Interceptors(SeamInterceptor.class)
                public class ShowListForDevelopers implements IShowListForDevelopers, Serializable {
                 @PersistenceContext(unitName = "aresDatabase", type=PersistenceContextType.EXTENDED)
                 private EntityManager em;
                
                 @DataModel
                 private List<Testaction> testactions;
                
                 @DataModelSelection
                 @Out(required = false)
                 private Testaction currentTestaction;
                
                 @Factory("testactions")
                 public void getTestactions() {
                 //create a list of testactions
                 }
                
                 public String select() {
                 //user selects an element
                 return "selected";
                 }
                
                 @Remove @Destroy
                 public void destroy() {
                 }
                }


                The DataModel is displayed on the first page as a simple dataTable. As the user selects an item from the dataTable, the items details are displayed on a second page.

                (simplified it)
                <h:form>
                 <div class="buttonBox">
                 <h:commandButton action="#{showTestactionForDevelopers.saveTestaction}"
                 value="Save and Next" class="button" type="submit"
                 immediate="true" />
                 </div>
                 <table cellpadding="0" cellspacing="0" border="0">
                 <tr>
                 <th><h:outputText value="#{ares_messages.label_testaction_ID}" /></th>
                 </tr>
                 <tr>
                 <td><h:outputText value="#{currentTestaction.ID}" /></td>
                 </tr>
                 </table>
                </h:form>


                Now the user enters some additional information or changes something, then he hits a save button.
                The save button invokes a method of a second class, which should save the chosen element with the changes made. But the element (currentTestaction) is not injected.

                @Stateful
                @Scope(ScopeType.SESSION)
                @LoggedIn
                @Name("showTestactionForDevelopers")
                @Interceptors(SeamInterceptor.class)
                public class ShowTestactionForDevelopers implements IShowTestactionForDevelopers{
                 @PersistenceContext(unitName = "aresDatabase", type = PersistenceContextType.EXTENDED)
                 private EntityManager em;
                
                 @In @Out
                 @Valid
                 private Testaction currentTestaction;
                
                 public String saveTestaction() {
                 //do something with the injected currentTestaction
                 //and return an outcome
                 }
                
                 @Destroy @Remove
                 public void destroy() {
                 }
                }


                After saving the element, the next one should be displayed. This is the reason why I want the currentTestaction and the list of testactions being injected into my second class.

                I hope I could describe my problem.

                Regards