Problem with inter portlet communication (ipc)
[Logo]
ICEsoft.org Forums: ICEfaces, ICEmobile, ICEpdf
[Search] Search   [Recent Topics] Recent Topics   [Groups] Home Page | www.icefaces.org  [Register] Register  [Login] Login 
Problem with inter portlet communication (ipc)  XML
Forum Index -> JBoss Seam Integration Go to Page: 1, 2 Next 
Author Message
thierry.rietsch

Joined: 28/10/2008 00:00:00
Messages: 19
Offline


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.

CustomerListAction

@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() {}
}
 


CustomerDetailsAction

@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() {}
}
 


The xhtml files:

customerList.xhtml

<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>
 


customerDetails.xhtml

<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>
 


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:


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
 


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.
judy.guglielmin

Joined: 20/02/2007 00:00:00
Messages: 1196
Offline


Are these portlets within the same application (war? or ear? deployment?)?

Can you put an annotated method @Create to see where it is creating the second copy of the bean? (and put a logging message in the remove to see if it is being destroyed before the second is created). You could also try just using getters and setters for a List instead of @Datamodel annotation as the seam contexts are not always available when using ajax-enabled components like the row selector.

On the bean you have posted, the SessionRenderer info is commented out. (am assuming that you ran it with this code in) Also, you should put the SessionRenderer.removeCurrentSession("test") in the @Remove method.
In the @Create method, add your bean to the SessionRenderer, then when you trigger the row selection, do the push.

thierry.rietsch

Joined: 28/10/2008 00:00:00
Messages: 19
Offline


@Create method added
@Remove method extended with Sysout to see if it is destroyed


07:05:04,064 INFO [STDOUT] CustomerListAction / getCustomers = getCustomers called
07:05:04,064 INFO [STDOUT] CustomerListAction / getCustomers = sessionId: 1600110A483B4314A09E23B206E6C275
07:05:04,064 INFO [STDOUT] Hibernate: select customer0_.id as id336_, customer0_.name as name336_, customer0_.street as street336_, cust
s city336_, customer0_.zip as zip336_, customer0_.contactPerson as contactP6_336_, customer0_.phone as phone336_, customer0_.website as w
om Customer customer0_
07:05:04,142 INFO [STDOUT] CustomerDetailsAction / create = instance: 18873862
07:05:04,142 INFO [STDOUT] CustomerDetailsAction / initTempInt = tempIntInit called
07:05:04,142 INFO [STDOUT] CustomerDetailsAction / initTempInt = instance: 18873862
07:05:04,142 INFO [STDOUT] CustomerDetailsAction / initTempInt = sessionId: 1600110A483B4314A09E23B206E6C275
07:05:07,251 INFO [STDOUT] CustomerListAction / getCustomers = select called (customer name -> ice cream company)
07:05:07,251 INFO [STDOUT] CustomerListAction / getCustomers = sessionId: 1600110A483B4314A09E23B206E6C275
07:05:07,251 INFO [STDOUT] CustomerDetailsAction / create = instance: 6072
07:05:07,251 INFO [STDOUT] CustomerDetailsAction / getCustomer = getCustomer called
07:05:07,251 INFO [STDOUT] CustomerDetailsAction / getCustomer = tmpInt: 1
07:05:07,251 INFO [STDOUT] CustomerDetailsAction / getCustomer = instance: 6072
07:05:07,251 INFO [STDOUT] CustomerDetailsAction / getCustomer = sessionId: 1600110A483B4314A09E23B206E6C275
07:05:07,251 INFO [STDOUT] CustomerDetailsAction / getCustomer = customerToDisplay.name: ice cream company
07:05:19,861 INFO [STDOUT] CustomerListAction / getCustomers = select called (customer name -> company 1)
07:05:19,861 INFO [STDOUT] CustomerListAction / getCustomers = sessionId: 1600110A483B4314A09E23B206E6C275
07:05:19,861 INFO [STDOUT] CustomerDetailsAction / getCustomer = getCustomer called
07:05:19,861 INFO [STDOUT] CustomerDetailsAction / getCustomer = tmpInt: 2
07:05:19,861 INFO [STDOUT] CustomerDetailsAction / getCustomer = instance: 6072
07:05:19,861 INFO [STDOUT] CustomerDetailsAction / getCustomer = sessionId: 1600110A483B4314A09E23B206E6C275
07:05:19,861 INFO [STDOUT] CustomerDetailsAction / getCustomer = customerToDisplay.name: company 1
 


As the output shows, two instances are created and not one of them is destroyed.

The @Datamodel annotation works. Any reason to change that?

In the second bean there is the right customer set, but what we don't understand is the creation of the second bean instance of CustomersDetailAction or even why are not both of this instances registered observers?

Thanks for any help ;)
judy.guglielmin

Joined: 20/02/2007 00:00:00
Messages: 1196
Offline


Did you add the bean to the group "test" of the SessionRenderer in the @Create annotated method? I'm not sure I totally understand your use-case, but from what I have read it looks like one portlet will select a certain record. That record is then "pushed" in the second portlet...is this correct?

So...the second portlet should be added to the SessionRenderer's group in an @Create method. (am assuming that you have a default record for before a row is actually selected?)

The row is selected in the first bean and triggers the event for the update to the second bean. The second bean observes the event (is the entity passed as a parameter to the observer method?), and if the entity is not null or whatever other problems could occur, then you are pushing the update? Did you say this is a single war but with 2 portlets defined?
thierry.rietsch

Joined: 28/10/2008 00:00:00
Messages: 19
Offline


Hi Judy

Thank you for your help! We haven't added the bean to the SessionRenderer "test" group. I will try that.

Yes this is the use case. The first portlet has a table of customer records. If the user selects a record from the table, the second portlet shows all the details from the record.

Will the SessionRenderer change the problem with the different seam bean in the background? As we see in the console output, the first output shows that the CustomerDetailsAction-Bean (which is responsible for the second portlet) gets instantiated twice (altough it has a SessionScope).

The customer record gets passed to the second bean over the SessionContext of Seam.

Yes it is a single war file with two portlets.

Again thank you very much for your help!

Thierry
judy.guglielmin

Joined: 20/02/2007 00:00:00
Messages: 1196
Offline


Seam is dependent on javaassist.jar and for some reason, if you use a constructor in your bean, you can get 2 versions instantiated. Could this be what you are seeing?
thierry.rietsch

Joined: 28/10/2008 00:00:00
Messages: 19
Offline


No we don't have any constructor in any of the beans.
thierry.rietsch

Joined: 28/10/2008 00:00:00
Messages: 19
Offline


Hey Judy!

I have changed the whole situation and I think there is a bug. Either in Seam or in the ICEfaces portlet bridge. I think it is in the ICEfaces portlet bridge.

I removed the second bean and the use case is handled now by one bean -> CustomerListAction. It populates the data from the database into the datatable and handles the select from a user.


@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;

@Create
public void createCustomerListAction() {
SessionRenderer.addCurrentSession("customerListAction");
}

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

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

@Factory("selectedCustomer")
public void initSelectedCustomer() {
System.out.println("CustomerListAction / initSelectedCustomer = called");
System.out.println("CustomerListAction / initSelectedCustomer = bean hash code: " + this.hashCode());

selectedCustomer = new Customer();

selectedCustomer.setName("Company Inc");
selectedCustomer.setStreet("foostreet 10");
selectedCustomer.setZip("1234");
selectedCustomer.setCity("foo city");
selectedCustomer.setContactPerson("mr. foo bar");
selectedCustomer.setWebsite("www.foo.com");
selectedCustomer.setPhone("123456");
}

public void select(Customer c) {
System.out.println("CustomerListAction / select = called (customer name -> " + c.getName() + ")");
System.out.println("CustomerListAction / select = bean hash code: " + this.hashCode());

selectedCustomer = c;

SessionRenderer.render("customerListAction");
}

@Remove
public void remove() {
SessionRenderer.removeCurrentSession("customerListAction");
}
}
 


and two xhtml pages:

customerList.xhtml

<f:view xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:s="http://jboss.com/products/seam/taglib"
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>
 


customerDetails.xhtml

<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: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:outputLabel for="txtCustomerStreet">Street</ice:outputLabel>
<ice:outputText id="txtCustomerStreet" value="#{selectedCustomer.street}" />

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

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

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

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

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

</ice:portlet>
</f:view>
 


As you can see the first xhtml (customerList.xhtml) contains only the data table. If a user selects a row the ice:rowSelector calls the select method on the CustomerListAction bean. This method assigns the customer behind the selected row to the selectedCustomer field of the bean. This one is annotated with the Seam @Out annotation and is therefor available for the second xhtml page (customerDetails.xhtml). After the assignment of the customer to the selectedCustomer field the method calls the SessionRenderer.render("customerList") method. This then rerender the pages or better say, populates the data deltas between server and client.

And now the strange thing: If I open the two xhtml sites seperatly in a browser the update works correctly. This means If a user selects a row with a customer in the datatable, the second page updates itself correctly. But if I include those two sites as portlets in the JBoss Portal, the second portal with the customerDetails.xhtml doesn't update the data.

Therefor I assume that this is a bug in the ICEfaces portlet bridge. What do you think? Should I fill in a bug report?

Thanks for your help,

Thierry
jguglielmin

Joined: 20/07/2007 00:00:00
Messages: 181
Offline


Please open the jira, attach the sample application that shows the problem, and assign to me.
thierry.rietsch

Joined: 28/10/2008 00:00:00
Messages: 19
Offline


I've opened the issue but can't assign it (looks like i don't have the right to do that). The issue number is ice-4190.
jguglielmin

Joined: 20/07/2007 00:00:00
Messages: 181
Offline


Thanks.
thierry.rietsch

Joined: 28/10/2008 00:00:00
Messages: 19
Offline


Have you made any progress on this? Thanks for your help!
jguglielmin

Joined: 20/07/2007 00:00:00
Messages: 181
Offline


Yes....It seems that you are trying to use the same session-scoped backing bean for both portlets, but in portlets, a session-scoped backing bean is not the same as in servlets (this is in the docs). Also, you are trying to use jboss-el evaluation of el expression in your row selector component (have to have same signature as for seam-comp-showcase). I will try to attach a working example later today to the jira.
kaizen

Joined: 01/02/2009 00:00:00
Messages: 2
Offline


can i get the completed example source .war that u develop IPC portlet use icefaces n seam..
harsh.jetly

Joined: 06/07/2009 00:00:00
Messages: 8
Offline


hi,
I have the very same issue with ipc in Seam portlet.
Can you give me a working example for this.

Thank you.
 
Forum Index -> JBoss Seam Integration Go to Page: 1, 2 Next 
Go to:   
Powered by JForum 2.1.7ice © JForum Team