4 Replies Latest reply on Oct 1, 2006 6:22 PM by segue.guy

    DataModelSelection and Outjection confusion

    segue.guy

      I know I'm making some obvious mistake below, and it's driving me to distraction....

      I have a page which displays a list and allows selection to go to a detailed view of the selected item:

      @Stateful
      @Scope(SESSION)
      @Name("dataSourceList")
      @LoggedIn
      public class DataSourceListAction implements DataSourceList, Serializable
      {
       ...
      
       @DataModel
       private List<DataSource> dataSources;
       @DataModelSelection
       @In(required=false)
       @Out(scope=SESSION, required=false)
       private DataSource dataSource;
      
       @Factory
       @Observer("createDataSourceConfirmed")
       public void getDataSources()
       {
       dataSources = em.createQuery("from DataSource s where s.user.username = :username")
       .setParameter("username", user.getUsername())
       .getResultList();
       }
      
       public String selectDataSource()
       {
       log.info("get datasource: #0 for #{user.username}", dataSource.getId());
       dataSource = em.find(DataSource.class, dataSource.getId());
       log.info("got datasource: #0 for #{user.username}", dataSource.getName());
       events.raiseEvent("selectDataSource");
       return "datasource";
       }
      
       public void delete()
       {
       dataSources.remove(dataSource);
       em.remove(dataSource);
       dataSource=null;
       }
      
       @Destroy @Remove
       public void destroy() {}
      
      }
      


      I want the selection outjected to drive a detailed view page, which among other things displays an attribute which is a list of objects using a @DataModel and dataTable. The backing code looks like:

      @Stateful
      @Scope(SESSION)
      @Name("dataSourceView")
      @LoggedIn
      public class DataSourceViewAction implements DataSourceView, Serializable
      {
       ...
      
       @In(scope=SESSION, required=true)
       private DataSource dataSource;
      
       @DataModelSelection(value="dataFields")
       @Out(scope=SESSION, required=false)
       private DataField dataField;
      
       @DataModel(value="dataFields")
       @Observer("selectDataSource")
       public List<DataField> getDataFields()
       {
       log.info("in new getDataFields for #0", dataSource == null ? "null" : dataSource.getName());
       return dataSource.getDataFields();
       }
      
       public String selectDataField()
       {
       log.info("get dataField: #0", dataField.getName());
       return "dataviewer";
       }
      
       @Destroy @Remove
       public void destroy() {}
      
      }
      


      I'm confused over the behavior. I create two items in the list in other code. When I select the first item in the list, it shows the simple attributes of the first item, but the list attribute contains the values from the second, most recently created item. Similarly if I subsequently select the second item from the list, it shows the simple attributes from the second item, but the list attrbute from the first. If I select the second item again, everything looks fine. The debugging statements in the observer do show that the dataSource object I expect to be selected is the previously outjected one.

      I'm missing something clear and simple in the lifecycle here - anyone have any advice?

        • 1. Re: DataModelSelection and Outjection confusion
          gavin.king

          I doubt that this is the problem, but note that the combination of @DataModel and @Observer on the same method is very, very wierd and probably nonsensical.

          This makes more sense:

          @Stateful
          @Scope(SESSION)
          @Name("dataSourceView")
          @LoggedIn
          public class DataSourceViewAction implements DataSourceView, Serializable
          {
           ...
          
           @In(scope=SESSION, required=true)
           private DataSource dataSource;
          
           @DataModelSelection(value="dataFields")
           @Out(scope=SESSION, required=false)
           private DataField dataField;
          
           @DataModel
           private List<DataField>dataFields;
          
           @Observer("selectDataSource")
           public void initDataFields()
           {
           log.info("in new getDataFields for #0", dataSource == null ? "null" : dataSource.getName());
           dataFields = dataSource.getDataFields();
           }
          
           public String selectDataField()
           {
           log.info("get dataField: #0", dataField.getName());
           return "dataviewer";
           }
          
           @Destroy @Remove
           public void destroy() {}
          
          }



          Ah hah! Now I see the problem: you raise the event from the method that actually initializes the value of the dataSource context variable, which means is has not yet been outjected at that point.

          • 2. Re: DataModelSelection and Outjection confusion
            gavin.king

            By the way, your log messages should be written like this:

            log.info("in new getDataFields for #{datasource.name}");


            log.info("get dataField: #{dataField.name}");


            Much cleaner.

            • 3. Re: DataModelSelection and Outjection confusion
              gavin.king

              I just added an @RaiseEvent annotation. So you could write:


              @RaiseEvent("selectDataSource")
               public String selectDataSource()
               {
               log.info("get datasource: #0 for #{user.username}", dataSource.getId());
               dataSource = em.find(DataSource.class, dataSource.getId());
               log.info("got datasource: #0 for #{user.username}", dataSource.getName());
               return "datasource";
               }


              To solve your problem.

              Of course, another solution would be to use Contexts.getSessionContext().set("dataSource", dataSource) instead of outjection.

              • 4. Re: DataModelSelection and Outjection confusion
                segue.guy

                Gavin,

                Thanks for the cleanup. You can see I was hacking back and forth on this, even as I isolated the problem into something that someone else could follow.

                I worked around the problem with dedicated array attributes as you did, but with my observer setting the arrays to null. Factories for the arrays successfully populated the arrays later. Your init method (which I've also seen elsewhere) is cleaner still. And the Context class is exactly what I was looking for with my earlier approach.

                This make me think that the Seam commuity would benefit from patterns and best practices. I don't spend much time on the JBoss forums except for support in debugging. If the forums are meant to grow those best practices, ignore the comment. I've also seen earlier comments from the *@jboss.com staff that there's plenty on the todo lists.

                Seam is fantastic! I can program higher-level business logic about as fast as I can think of use cases, and get it right the first time so often that it's very empowering. Of course, that's keeping me from writing proper uses cases and design....

                Ron0