7 Replies Latest reply on Nov 10, 2005 5:44 PM by christian.bauer

    The solution for GET requests

    gavin.king

      We've discussed the problem of fetching data and DataModels for a page that is accessed via a direct GET (non-faces) request several times. I spent a lot of time thinking about this and came up with a solution. I just committed to CVS the @Factory annotation.

      The idea is that you can specify that a component is a "factory" for a named context variable. So, when faces tries to resolve the variable, and it is empty, the factory method of the component will be invoked (after creating the component, if necessary), and the component is responsible for outjecting the value of the context variable. The factory method may even start a long-running conversation or whatever.

      For example, the "bookingManager" component is a factory for "bookingList":

      
      @Stateful
      @Name("bookingManager")
      @Interceptor(SeamInterceptor.class)
      public class BookingListBean {
      
       @In EntityManager em;
      
       @DataModel List<Booking> bookingList;
       @DataModelSelection Booking booking;
      
       @Factory("bookingList")
       @Begin
       public void find() {
       bookingList = em.createQuery("..").list();
       }
      
       public String cancel() {
       booking.cancel();
       return null;
       }
      
       @Destroy @Remove
       public void destroy() {}
      
      }
      
      


        • 1. Re: The solution for GET requests

          if find() is dependent on other inputs, then the expectation is that the component is fully populated based on the current Contextual state before invoking find() ?

          • 2. Re: The solution for GET requests
            gavin.king

            Sure. the @Factory method functions pretty much just like an event listener method.

            • 3. Re: The solution for GET requests
              christian.bauer

              Stupid question:

              "So, when faces tries to resolve the variable, and it is empty, the factory method of the component will be invoked "

              Which component?

              • 4. Re: The solution for GET requests
                christian.bauer

                This feature doesn't seem to work for non-datamodel factory variables:

                @Out(scope = EVENT, required = false)
                public TreeNode categoryTree;

                @Out(scope = EVENT, required = false)
                public TreeNode node;

                @Factory("categoryTree")
                public void initializeTree() { ... }

                Caused by: java.lang.NoSuchMethodException: org.hibernate.ce.auction.seam.noejb.BrowseCategories$$EnhancerByCGLIB$$d5838cdf.initializeTree()
                at java.lang.Class.getMethod(Class.java:1581)
                at org.jboss.seam.Component.callComponentMethod(Component.java:926)
                at org.jboss.seam.Component.getInstanceFromFactory(Component.java:887)
                at org.jboss.seam.Component.getInstance(Component.java:850)
                at org.jboss.seam.jsf.SeamVariableResolver.resolveVariable(SeamVariableResolver.java:43)

                Maybe it shouldn't use instance.getClass().getMethod() to resolve the factory method, but somehow consider the proxy.

                • 5. Re: The solution for GET requests
                  gavin.king

                  Presumably some kind of problem with JavaBean components, though I don't quite understand it. Should work using instance.getClass().getMethod().

                  • 6. Re: The solution for GET requests
                    renspr

                    @Factory works for me on non-datamodel factory variables:

                     @PersistenceContext
                     private EntityManager em;
                    
                     @Out
                     private List<Post> posts;
                    
                     @Factory("posts")
                     public void find() {
                     posts = em.createQuery("from Post").getResultList();
                     log.info(posts.size() + " posts found");
                     }
                    




                    @Factory("categoryTree")
                    public void initializeTree() { ... }
                    
                    Caused by: java.lang.NoSuchMethodException: org.hibernate.ce.auction.seam.noejb.BrowseCategories$$EnhancerByCGLIB$$d5838cdf.initializeTree()
                    at java.lang.Class.getMethod(Class.java:1581)
                    at org.jboss.seam.Component.callComponentMethod(Component.java:926)
                    at org.jboss.seam.Component.getInstanceFromFactory(Component.java:887)
                    at org.jboss.seam.Component.getInstance(Component.java:850)
                    at org.jboss.seam.jsf.SeamVariableResolver.resolveVariable(SeamVariableResolver.java:43)
                    



                    I think you have to specify initializeTree() in the local interface of your session bean.

                    • 7. Re: The solution for GET requests
                      christian.bauer

                      The problem seems to be with JavaBean components, not EJB components. There is an open JIRA issue.