6 Replies Latest reply on Jan 21, 2008 5:51 PM by bludginozzie

    Seam component not getting called when in default conversati

    bludginozzie

      I am having a problem with what I would have thought would be a very simple use of seam. I have a Stateful component (using ejb's) and when I put the component in default scope it doesn't work however in session scope it does. Here is the code;

      Stateful
      //@Scope(ScopeType.SESSION)
      @Name("userList")
      @Restrict("#{identity.loggedIn}")
      public class UserListImpl implements UserList {
       private static final int PAGESIZE = 10;
      
       @PersistenceContext
       private EntityManager em;
      
       private String searchUsername;
       private int pageNo = 0;
      
       @DataModel
       private List<User> users;
      
       public void findUsers() {
       System.out.println("findUsers:" + pageNo);
       pageNo = 0;
       loadCurrentPage();
       }
      
       private void loadCurrentPage() {
       System.out.println("loadCurrentPage:" + pageNo);
       String searchPattern;
       if (searchUsername == null) {
       searchPattern = "%";
       } else {
       searchPattern = '%' + searchUsername.toLowerCase().replace('*', '%') + '%';
       }
       users = em.createQuery("from User where lower(username) like :searchPattern")
       .setParameter("searchPattern", searchPattern)
       .setMaxResults(PAGESIZE)
       .setFirstResult(pageNo * PAGESIZE)
       .getResultList();
       }
      
       public String getSearchUsername() {
       return searchUsername;
       }
      
       public void setSearchUsername(String searchUsername) {
       this.searchUsername = searchUsername;
       }
      
       public boolean isNextPageAvailable() {
       return ((users != null) && (users.size() == PAGESIZE));
       }
      
       public boolean isPrevPageAvailable() {
       return (pageNo > 0);
       }
      
       public void nextPage() {
       System.out.println("nextPage:" + pageNo);
       pageNo++;
       loadCurrentPage();
       }
      
       public void prevPage() {
       System.out.println("prevPage:" + pageNo);
       pageNo--;
       if (pageNo < 0) {
       pageNo = 0;
       }
       loadCurrentPage();
       }
      
       public int getPageNo() {
       System.out.println("getPageNo:" + pageNo);
       return pageNo;
       }
      
       public void setPageNo(int pageNo) {
       System.out.println("setPageNo:" + pageNo);
       this.pageNo = pageNo;
       }
      
       @Create
       public void create() {
       System.out.println("create:" + pageNo);
       }
      
       @Remove
       @Destroy
       public void destroy() {
       System.out.println("destroy:" + pageNo);
       }
      }
      

      <!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"
       xmlns:a="http://richfaces.org/a4j"
       template="layout/template.xhtml">
      <ui:define name="body">
      
       <h:messages globalOnly="true" styleClass="message"/>
      
       <rich:panel>
       <f:facet name="header">User List</f:facet>
      
       <h:form id="searchCriteria">
       <h:inputHidden id="pageNo" value="#{userList.pageNo}"/>
       <table>
       <tr>
       <td>
       <h:outputLabel for="searchUsername">Username:</h:outputLabel>
       </td>
       <td>
       <h:inputText id="searchUsername" value="#{userList.searchUsername}" size="15" />
       </td>
       <td>
       <h:commandButton id="findUsers" value="Find Users" action="#{userList.findUsers}" reRender="searchResults"/>
       </td>
       <td style="width: 100%" align="center">
       <a href="usermaint.seam?userid=0">
       <img style="border: none" src="img/adduser32.gif" width="32" height="32" /><br />
       Add a new User</a>
       </td>
       </tr>
       </table>
       <rich:separator height="2" style="padding:10px 0" />
      
       <div class="section">
       <s:div rendered="#{users != null and users.rowCount==0}">
       <table>
       <tr>
       <td><img src="img/warn48.png" width="48" height="48" /></td>
       <td valign="middle"><span class="">No Users Found</span></td>
       </tr>
       </table>
       </s:div>
       <rich:dataTable id="users" value="#{users}" var="u" rows="20" rendered="#{users.rowCount>0}">
       <rich:column>
       <f:facet name="header">User Name</f:facet>
       #{u.username}
       </rich:column>
       <rich:column>
       <f:facet name="header">Full Name</f:facet>
       #{u.fullName}
       </rich:column>
       <rich:column>
       <f:facet name="header">Action</f:facet>
       <a href="usermaint.seam?userid=#{u.userId}"><img style="border: none" src="img/edit15.gif" width="15" height="15" /></a> 
       <a href="#"><img style="border: none" src="img/delete15.gif" width="15" height="15" /></a>
       </rich:column>
       </rich:dataTable>
       <h:commandButton value="Previous Page" action="#{userList.prevPage}" rendered="#{userList.prevPageAvailable}"/>
       <h:commandButton value="Next Page" action="#{userList.nextPage}" rendered="#{userList.nextPageAvailable}"/>
       </div>
      
       </h:form>
       </rich:panel>
      
      </ui:define>
      </ui:composition>
      

      The problem arises when I attempt to use the "Next Page" button. With the component in session scope it works fine however with the component in default conversation scope the userList.nextPage method is never called. Here is a copy of the sysout;
      18:29:16,234 INFO [STDOUT] create:0
      18:29:16,265 INFO [STDOUT] getPageNo:0
      18:29:16,281 INFO [STDOUT] setPageNo:0
      18:29:16,343 INFO [STDOUT] getPageNo:0
      18:29:16,359 INFO [STDOUT] destroy:0
      

      Has anyone got any ideas as to why this occurs? I will be creating heaps of these components and I don't want to have to stick them all in the users session since that would be a waste of server resources.

      Thanks in advance

      -Mark

        • 1. Re: Seam component not getting called when in default conver
          nickarls

          Hmmm, I can't tell how the @Scope makes the difference between nextPage() being called or not. Hope you have a long-running-conversation anyway, otherwise the pageNo will be mostly 0(?) Tried POJO as backing bean? Does changing the signature to public String and returning null affect the outcome?

          • 2. Re: Seam component not getting called when in default conver
            bludginozzie

            Thanks for the prompt response. The pageNo is being stored in the page as a hidden input so that I can avoid a long running conversation or session beans. I can't actually try it as a pojo since it requires the entityManager.

            Since I posted this I had an idea. I copied most of the concepts used from the booking example so I thought why not see if it works with that code. So I modified the booking example and guess what. It behaves exactly the same in that example. So I can only assume it must be a bug. I am using 2.0.0GA so I will download 2.0.1CR1 and see if it's fixed.

            Thanks again for your help.

            • 3. Re: Seam component not getting called when in default conver
              pmuir

              Why not use the Page scope.

              Use of a hidden form field is not really the way you do things in Seam.

              • 4. Re: Seam component not getting called when in default conver
                bludginozzie

                Thanks, but the actions are Stateful which is not applicable/permitted in Page scope.

                A hidden field is probably not the best way to do things in any frameworks but unfortunately I think it's my best option.

                I have heaps of these glorified crud pages of which this example is a very simple one. Most of them have a more complex filter feature that allows the user to filter the list using anything up 5 or 6 fields. Unfortunately the idea of creating these as entity-queries in components.xml doesn't scale. Since all the queries differ (i.e. different order by and where clauses).

                If there is another way of doing this I am all ears!!

                • 5. Re: Seam component not getting called when in default conver
                  pmuir

                   

                  Thanks, but the actions are Stateful which is not applicable/permitted in Page scope


                  What does this mean? I didn't mean put the action in the page scope, just the data you put in the hidden form field (you also can't put a stateful bean in a hidden form field ;)

                  Unfortunately the idea of creating these as entity-queries in components.xml doesn't scale. Since all the queries differ (i.e. different order by and where clauses).


                  Why not? You just mean you don't want to type all that? But want to type lots of Java instead?

                  • 6. Re: Seam component not getting called when in default conver
                    bludginozzie

                    My problem is that nextPage() is not getting called when I put the action in default conversation scope. The scope of the pageNo (or use as a hidden field) shouldn't make a difference to this but I tried it just to make sure. Do you have any ideas as to why nextPage() is not getting called? It does if I put the action is session scope.

                    Why not? You just mean you don't want to type all that? But want to type lots of Java instead?


                    My pages allow the user to filter the list by several ManyToOne entities. Things like State, Country, City all of which are entities and not strings. The filter dropdowns on the page allow a null value which indicates that they want "All", (eg: "All States", "All Countries" etc.). To do this using entity-query in components.xml I would need lots of quiries (i.e: usersByState, usersByStateAndCountry, usersByStateAndCountryAndCity, usersByCountryAndCity usersByStateAndCity etc...) and then I somehow have to bind these queries to the page.

                    The solution was to use a single action (like the search page in the booking example) with a query builder class. With the exception of the problem above it works great and only has a small amount of Java code.