1 Reply Latest reply on Mar 5, 2009 7:05 PM by jguglielmin

    Problem with inter portlet communication and seam

    sey
      Hi

      We are trying to develop a simple scenario with two portlets which communicate with each other. In the first portlet there is a list with customers. If a customer gets selected (over ice:rowSelector), the second portlet should display detailed information about this customer.

      We are using the latest version of JBoss Seam and tried ICEfaces 1.7.2 as well as 1.8.0RC1. As portal we are using the JBoss Portal 2.7.1 (running on JBoss AS 4.2.3).

      Each portlet is backed by a Seam Bean. The first portlet by CustomerListAction and the second portlet by CustomerDetailsAction.

      [b]CustomerListAction[/b]
      [quote]
      @Stateful
      @Scope(org.jboss.seam.ScopeType.SESSION)
      @Name("customerList")
      public class CustomerListAction implements CustomerList {
           @PersistenceContext
           private EntityManager em;

           @DataModel("customers")
           private List<Customer> customers;

           @Out(required=false)
           private Customer selectedCustomer;

           @SuppressWarnings("unchecked")
           @Factory("customers")
           public void getCustomers() {
                System.out.print("CustomerListAction / getCustomers = getCustomers called");
                System.out.println("CustomerListAction / getCustomers = sessionId: " + ((InterceptingPortletSession) FacesContext.getCurrentInstance().getExternalContext().getSession(true)).getId());

                customers = (List<Customer>) em.createQuery("from Customer").getResultList();
           }

           public void select(Customer c) {
                System.out.print("CustomerListAction / getCustomers = select called (customer name -> " + c.getName() + ")");
                selectedCustomer = c;

                System.out.println("CustomerListAction / getCustomers = sessionId: " + ((InterceptingPortletSession) FacesContext.getCurrentInstance().getExternalContext().getSession(true)).getId());


                Context ctx = Contexts.getSessionContext();
                ctx.set("customer", c);

                Events.instance().raiseEvent("showCustomerDetails");
           }

           @Remove
           public void remove() {}
      }
      [/quote]

      [b]CustomerDetailsAction[/b]
      [quote]
      @Stateful
      @Scope(ScopeType.SESSION)
      @Name("customerDetails")
      public class CustomerDetailsAction implements CustomerDetails {
           @Out
           private int tempInt;

           @Out(required = false)
           private Customer customerToDisplay;

           @Factory("tempInt")
           public void initTempInt() {
                tempInt = 1000;

                System.out.println("CustomerDetailsAction / initTempInt = tempIntInit called");
                System.out.println("CustomerDetailsAction / initTempInt = instance:  " + this.hashCode());
                System.out.println("CustomerDetailsAction / initTempInt = sessionId: " + ((InterceptingPortletSession) FacesContext.getCurrentInstance().getExternalContext().getSession(true)).getId());
           }

           @Observer("showCustomerDetails")
           public void getCustomer() {
                System.out.println("CustomerDetailsAction / getCustomer = getCustomer called");
                
                customerToDisplay = (Customer) Contexts.getSessionContext().get("customer");

                tempInt++;
                System.out.println("CustomerDetailsAction / getCustomer = tmpInt: " + tempInt);
                System.out.println("CustomerDetailsAction / getCustomer = instance: " + this.hashCode());
                System.out.println("CustomerDetailsAction / getCustomer = sessionId: " + ((InterceptingPortletSession) FacesContext.getCurrentInstance().getExternalContext().getSession(true)).getId());

                if(customerToDisplay != null)
                     System.out.println("CustomerDetailsAction / getCustomer = customerToDisplay.name: " + customerToDisplay.getName());

                // Didn't change anything
                //SessionRenderer.addCurrentSession("test");
                //SessionRenderer.render("test");
           }

           @Remove
           public void remove() {}
      }
      [/quote]

      The xhtml files:

      [b]customerList.xhtml[/b]
      [quote]
      <f:view xmlns:h="http://java.sun.com/jsf/html"
                xmlns:f="http://java.sun.com/jsf/core"
                xmlns:ui="http://java.sun.com/jsf/facelets"
                xmlns:ice="http://www.icesoft.com/icefaces/component">

           <ice:outputDeclaration doctypeRoot="HTML"
                                       doctypePublic="-//W3C//DTD HTML 4.01 Transitional//EN"
                                       doctypeSystem="http://www.w3.org/TR/html4/transitional.dtd"/>

           <ice:portlet styleClass="componentBoxPortlet">
                <ice:outputStyle href="/xmlhttp/css/rime/rime-portlet.css"/>

                <ice:form>
                <ice:dataTable var="cust" value="#{customers}" rows="15" columnClasses="tableCol">
                     <ice:column>
                          <ice:rowSelector value="#{cust.selected}"  
                                               selectedClass="tableRowSelected" mouseOverClass="tableRowMouseOver"
                                               selectionAction="#{customerList.select(cust)}"
                                    />

                          <f:facet name="header">Customer</f:facet>
                          <ice:outputText value="#{cust.name}"/>
                     </ice:column>
                     <ice:column>
                          <f:facet name="header">City</f:facet>
                          <ice:outputText value="#{cust.city}" />
                     </ice:column>
                </ice:dataTable>
                </ice:form>

                <ice:panelGrid columns="2"
                                  styleClass="exampleBox buttonsAndLinksContainer"
                                  rowClasses="textFieldNameRow">

                     <ice:outputLabel for="txtCustomerName">Name</ice:outputLabel>
                     <ice:outputText id="txtCustomerName" value="#{selectedCustomer.name}" />

                </ice:panelGrid>

           </ice:portlet>
      </f:view>
      [/quote]

      [b]customerDetails.xhtml[/b]
      [quote]
      <f:view xmlns:h="http://java.sun.com/jsf/html"
                xmlns:f="http://java.sun.com/jsf/core"
                xmlns:ui="http://java.sun.com/jsf/facelets"
                xmlns:ice="http://www.icesoft.com/icefaces/component">

           <ice:outputDeclaration doctypeRoot="HTML"
                                       doctypePublic="-//W3C//DTD HTML 4.01 Transitional//EN"
                                       doctypeSystem="http://www.w3.org/TR/html4/transitional.dtd"/>

           <ice:portlet styleClass="componentBoxPortlet">
                <ice:outputStyle href="/xmlhttp/css/rime/rime-portlet.css"/>

                <ice:messages/>

                <ice:outputText value="#{tempInt}" />

                <ice:form>
                <ice:panelGrid columns="2"
                                  styleClass="exampleBox buttonsAndLinksContainer"
                                  rowClasses="textFieldNameRow">

                     <ice:outputLabel for="txtCustomerName1">Int</ice:outputLabel>
                     <ice:outputText id="txtCustomerName1" value="#{tempInt}" />

                     <ice:outputLabel for="txtCustomerName">Name</ice:outputLabel>
                     <ice:outputText id="txtCustomerName" value="#{customerToDisplay.name}" />

                     <ice:outputLabel for="txtCustomerStreet">Street</ice:outputLabel>
                     <ice:outputText id="txtCustomerStreet" value="#{customerToDisplay.street}" />

                     <ice:outputLabel for="txtCustomerCity">City</ice:outputLabel>
                     <ice:outputText id="txtCustomerCity" value="#{customerToDisplay.city}" />

                     <ice:outputLabel for="txtCustomerZip">Zip</ice:outputLabel>
                     <ice:outputText id="txtCustomerZip" value="#{customerToDisplay.zip}" />

                     <ice:outputLabel for="txtCustomerContactPerson">Contact Person</ice:outputLabel>
                     <ice:outputText id="txtCustomerContactPerson" value="#{customerToDisplay.contactPerson}" />

                     <ice:outputLabel for="txtCustomerPhone">Phone</ice:outputLabel>
                     <ice:outputText id="txtCustomerPhone" value="#{customerToDisplay.phone}" />

                     <ice:outputLabel for="txtCustomerWebsite">Website</ice:outputLabel>
                     <ice:outputText id="txtCustomerWebsite" value="#{customerToDisplay.website}" />
                </ice:panelGrid>
                </ice:form>

           </ice:portlet>
      </f:view>
      [/quote]

      The problem is that the second portlet doesn't update its content over the Ajax Push mechanism provided by ICEfaces. We added for debuging purposes the "tempInt" value. If the example gets executed the following console output appears:

      [quote]
      18:19:44,533 INFO  [STDOUT] CustomerListAction / getCustomers = getCustomers called
      18:19:44,533 INFO  [STDOUT] CustomerListAction / getCustomers = sessionId: AB17EE2E6060B1373B969F0A6FB7959E
      18:19:44,533 INFO  [STDOUT] Hibernate: select customer0_.id as id390_, customer0_.name as name390_, customer0_.street as street390_, customer0_.city a
      s city390_, customer0_.zip as zip390_, customer0_.contactPerson as contactP6_390_, customer0_.phone as phone390_, customer0_.website as website390_ fr
      om Customer customer0_
      18:19:44,626 INFO  [STDOUT] CustomerDetailsAction / initTempInt = tempIntInit called
      18:19:44,642 INFO  [STDOUT] CustomerDetailsAction / initTempInt = instance:  24848986
      18:19:44,642 INFO  [STDOUT] CustomerDetailsAction / initTempInt = sessionId: AB17EE2E6060B1373B969F0A6FB7959E
      18:19:49,501 INFO  [STDOUT] CustomerListAction / getCustomers = select called (customer name -> coresystems1)
      18:19:49,501 INFO  [STDOUT] CustomerListAction / getCustomers = sessionId: AB17EE2E6060B1373B969F0A6FB7959E
      18:19:49,501 INFO  [STDOUT] CustomerDetailsAction / getCustomer = getCustomer called
      18:19:49,501 INFO  [STDOUT] CustomerDetailsAction / getCustomer = tmpInt: 1
      18:19:49,501 INFO  [STDOUT] CustomerDetailsAction / getCustomer = instance: 25697662
      18:19:49,501 INFO  [STDOUT] CustomerDetailsAction / getCustomer = sessionId: AB17EE2E6060B1373B969F0A6FB7959E
      18:19:49,501 INFO  [STDOUT] CustomerDetailsAction / getCustomer = customerToDisplay.name: coresystems1
      [/quote]

      This indicates the problem: The first time the second portlet loads its xhtml, Seam associates a different CustomerDetailsAction-Bean to the portlet than in the following requests. The tempInt variable gets initialized over the factory method with the value 1000. When now a customer gets selected in the first portlet, the event gets to the CustomerDetailsAction-Bean but on a different instance than it is associated with the portlet.