18 July, 2007

Inter Portlet Communication in JBoss Portal 2.6

Have you tried to deploy HelloWorldIPC portlet (from Portlet Swap) into JBoss Portal 2.6?
I've tried, but it was unsuccessful.
This portlet works in previous version of JBoss Portal, but doesn't work in 2.6, because some APIs in JBoss Portal was slightly changed.
I've read some developers documentation and found way to resolve this problem, and I created sample of Inter Portlet Communication for JBoss Portal 2.6.
I think, it will be useful for developers. You may see sources below.



Project files

./build.properties
./build.xml
./local.properties
./src
./src/META-INF
./src/META-INF/jboss-service.xml
./src/WEB-INF
./src/WEB-INF/portlet-instances.xml
./src/WEB-INF/portlet.xml
./src/WEB-INF/web.xml
./src/WEB-INF/xlamipc-object.xml
./src/xqx
./src/xqx/web
./src/xqx/web/xlam
./src/xqx/web/xlam/XLamMasterPortlet.java
./src/xqx/web/xlam/XLamSlavePortlet.java


jboss-service.xml

<?xml version="1.0" encoding="UTF-8"?>

<server>
<mbean code="org.jboss.portal.core.event.PortalEventListenerServiceImpl"
name="portal:service=ListenerService,type=ipc_listener" xmbean-dd=""
xmbean-code="org.jboss.portal.jems.as.system.JBossServiceModelMBean">
<xmbean/>
<depends
optional-attribute-name="Registry" proxy-type="attribute">portal:service=ListenerRegistry
</depends>
<attribute name="RegistryId">ipc_listener</attribute>
<attribute name="ListenerClassName">xqx.web.xlam.XLamSlavePortlet$Listener</attribute>
</mbean>
</server>


portlet-instances.xml

<?xml version="1.0" standalone="yes"?>
<deployments>
<deployment>
<instance>
<instance-id>XLamMasterPortletInstance</instance-id>
<portlet-ref>XLamMasterPortlet</portlet-ref>
</instance>
</deployment>
<deployment>
<instance>
<instance-id>XLamSlavePortletInstance</instance-id>
<portlet-ref>XLamSlavePortlet</portlet-ref>
</instance>
</deployment>

</deployments>


portlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
version="1.0">

<portlet>
<portlet-name>XLamMasterPortlet</portlet-name>
<portlet-class>xqx.web.xlam.XLamMasterPortlet</portlet-class>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
<portlet-mode>HELP</portlet-mode>
</supports>
<portlet-info>
<title>XLam Master Portlet</title>
</portlet-info>
</portlet>

<portlet>
<portlet-name>XLamSlavePortlet</portlet-name>
<portlet-class>xqx.web.xlam.XLamSlavePortlet</portlet-class>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
</supports>
<portlet-info>
<title>XLam Slave Portlet</title>
</portlet-info>
</portlet>

</portlet-app>


web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
</web-app>



xlamipc-object.xml

<?xml version="1.0" encoding="UTF-8"?>
<deployments>
<deployment>
<if-exists>overwrite</if-exists>
<parent-ref>default</parent-ref>
<page>
<page-name>XLamIPC</page-name>
<listener>ipc_listener</listener>
<window>
<window-name>XLamMasterPortletWindow</window-name>
<instance-ref>XLamMasterPortletInstance</instance-ref>
<region>left</region>
<height>0</height>
</window>

<window>
<window-name>XLamSlavePortletWindow</window-name>
<instance-ref>XLamSlavePortletInstance</instance-ref>
<region>center</region>
<height>0</height>
</window>
</page>
</deployment>

</deployments>


XLamMasterPortlet.java

package xqx.web.xlam;


import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.GenericPortlet;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class XLamMasterPortlet extends GenericPortlet
{
protected void doView(RenderRequest renderRequest, RenderResponse renderResponse) throws PortletException, IOException
{
renderResponse.setContentType("text/html");
PrintWriter writer = renderResponse.getWriter();
writer.println("<form action='" + renderResponse.createActionURL() + "' method='post'>");
writer.println("<input name='txt' type='text'/>");
writer.println("<input type='submit' value='Send to Slave' />");
writer.println("</form>");
writer.close();
}

protected void doHelp(RenderRequest renderRequest, RenderResponse renderResponse) throws PortletException, IOException
{
renderResponse.setContentType("text/html");
PrintWriter writer = renderResponse.getWriter();
writer.write("Visit <a href='http://xantorohara.blogspot.com/'>Xantorohara blog</a> for another info.");
writer.close();
}

public void processAction(ActionRequest actionRequest, ActionResponse actionResponse) throws PortletException, IOException
{
//prevent super exception
}
}


XLamSlavePortlet.java

package xqx.web.xlam;

import org.jboss.portal.WindowState;
import org.jboss.portal.api.node.PortalNode;
import org.jboss.portal.api.node.event.PortalNodeEvent;
import org.jboss.portal.api.node.event.PortalNodeEventContext;
import org.jboss.portal.api.node.event.PortalNodeEventListener;
import org.jboss.portal.api.node.event.WindowActionEvent;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.GenericPortlet;
import javax.portlet.PortletException;
import javax.portlet.PortletSecurityException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class XLamSlavePortlet extends GenericPortlet
{
public static class Listener implements PortalNodeEventListener
{
public PortalNodeEvent onEvent(PortalNodeEventContext context, PortalNodeEvent event)
{
PortalNode node = event.getNode();
String nodeName = node.getName();
WindowActionEvent newEvent = null;
if (nodeName.equals("XLamMasterPortletWindow") && event instanceof WindowActionEvent)
{
WindowActionEvent wae = (WindowActionEvent) event;
PortalNode windowB = node.resolve("../XLamSlavePortletWindow");
if (windowB != null)
{
newEvent = new WindowActionEvent(windowB);
newEvent.setMode(wae.getMode());
newEvent.setWindowState(WindowState.MAXIMIZED);
newEvent.setParameters(wae.getParameters());
return newEvent;
}
}
return context.dispatch();
}
}

public void processAction(ActionRequest request, ActionResponse response) throws PortletException, PortletSecurityException, IOException
{
String txt = request.getParameter("txt");
if (txt != null)
{
response.setRenderParameter("txt", txt);
}
}


protected void doView(RenderRequest renderRequest, RenderResponse renderResponse) throws PortletException, PortletSecurityException, IOException
{
renderResponse.setContentType("text/html");
PrintWriter writer = renderResponse.getWriter();
writer.write("Message from Master:");
String txt = renderRequest.getParameter("txt");
writer.println("txt: " + txt);
writer.close();
}
}


build.properties

project.name=XLamIPC


build.xml

<?xml version="1.0" encoding="ISO-8859-1"?>

<project name="xlam" default="war">

<property file="local.properties"/>
<property file="build.properties"/>

<property name="build" value="build"/>
<property name="jarfile" value="${project.name}.jar"/>
<property name="warfile" value="${project.name}.war"/>
<property name="sarfile" value="${project.name}.sar"/>

<path id="classpath">
<fileset dir="${jbossportal.lib}" includes="**/*.jar"/>
</path>

<target name="clean">
<delete dir="${build}"/>
</target>

<target name="jar" depends="clean">
<mkdir dir="${build}/bin"/>
<javac srcdir="src" destdir="${build}/bin" classpathref="classpath" debug="true"/>
<jar basedir="${build}/bin" jarfile="${build}/${jarfile}"/>
</target>

<target name="war" depends="jar">
<copy file="${build}/${jarfile}" todir="${build}/war/WEB-INF/lib"/>
<copy todir="${build}/war/WEB-INF">
<fileset dir="src/WEB-INF"/>
</copy>
<jar basedir="${build}/war" jarfile="${build}/${warfile}"/>
</target>

<target name="sar" depends="war">
<copy file="${build}/${warfile}" todir="${build}/sar"/>
<copy file="${build}/${jarfile}" todir="${build}/sar/lib"/>
<copy todir="${build}/sar/META-INF">
<fileset dir="src/META-INF"/>
</copy>
<jar basedir="${build}/sar" jarfile="${build}/${sarfile}"/>
</target>

<target name="undeploy">
<delete file="${jbossportal.node}/deploy/${sarfile}"/>
</target>

<target name="deploy" depends="undeploy, sar">
<copy file="${build}/${sarfile}" todir="${jbossportal.node}/deploy"/>
</target>
</project>


local.properties (* You should replace paths with your real data)

jdk.home=E:/devenv/tools/jdk-1.5.0_04

jbossportal.home=E:/devenv/tools/jboss-portal-2.6
jbossportal.node=${jbossportal.home}/server/default
jbossportal.lib=${jbossportal.node}/deploy/jboss-portal.sar/lib



You may download these sources from Xantorohara.blogspot.com samples

15 comments:

prasadgc said...

Hi Xantorohara,

I'm glad to find that there's someone like you addressing these very important areas in portal application development (GWT, IPC, etc). This is great work.

I tried getting the IPC application to work. However, the PortalEventListenerServiceImpl class did not load because no classloaders were found.

The abridged error stack is as follows:

20:25:00,201 ERROR [MainDeployer] Could not create deployment: file:/usr/local/jboss-portal-2.6/server/default/deploy/XLamIPC.sar
org.jboss.deployment.DeploymentException: No ClassLoaders found for: org.jboss.portal.core.event.PortalEventListenerServiceImpl; - nested throwable: (java.lang.ClassNotFoundException: No ClassLoaders found for: org.jboss.portal.core.event.PortalEventListenerServiceImpl)
at org.jboss.system.ServiceConfigurator.install(ServiceConfigurator.java:196)
...
at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.ClassNotFoundException: No ClassLoaders found for: org.jboss.portal.core.event.PortalEventListenerServiceImpl
at org.jboss.mx.loading.LoadMgr3.beginLoadTask(LoadMgr3.java:212)
...

Any idea what the problem could be?

Thanks in advance.

Ganesh

Xantorohara said...

Try to do this:
ant undeploy
ant deploy
(without JBoss Portal reloading).

Xantorohara said...

This exception throws only at JBoss Portal start. I think, it is because JBoss deploys XLamIPC before Portal service.

But hot deployment works correctly.

It is necessary to set dependencies between services. Do you know how do it?

prasadgc said...

Thanks, the undeploy-redeploy worked.

Ganesh

Anonymous said...

Can you zip up your project and put it online. Thanks

Unknown said...

Has anyone tried this on 2.6.2. I did and am unable to get it to work. The listener appears to be properly registered according to the log. Yet, it does not get activated on a message.

Martijn Hinten said...

This is good stuff! I got it working on 2.6.3. Even amended is some to play with the window maximizing.

Kudos to Xantorohara.

Anonymous said...

slave portlet is already taking the null value.it doesn't get effected either i press submit in master portlet or not.it reamins same as NULL in the slave portlet..
can u plz help me out..
thanks & regards
Manav Sachdeva

Anonymous said...

i too am unable to get this working. slave portlet displays just null even after hitting the submit button. please help.

Thanks in advance,
sk

Anonymous said...

Finally got it working!! But the very first time it gives error, How do we set the dependency between IPC and portal service??

Anonymous said...

slave portlet is already taking the null value.it doesn't get effected either i press submit in master portlet or not.it reamins same as NULL in the slave portlet..
can u plz help me out..

Anonymous said...

Is it mandatory to deploy project in .sar format. i deployed in .war format and i am able to see two widgets in IPC page but there is no communication between them and there is no error also.
and also i want to know where implemented listener class will be registered.
can some one help me in this regard

Anonymous said...

Example is working for me.
Even i faced the same problem like Client taking null value.
to avoid that i made folder structure in following way.

every thing is under ipc.sar in that i have ipc.war,lib folder(contains .jar file for master,slave & listener)
and META-INF(Jboss-service.xml)
Deploy the ipc.sar file finally.

Anonymous said...

i just want to know how is this onEvent() function in listenerclass is called or how d complete class itself is called..
if any1 trying to run dis has achievd doing it...plz tell
mine is showing null values only.

Unknown said...

Hi,

Its amazing post, very informative for us. Jboss Portal Development provides an open source platform for hosting and serving a portal's Web interface, publishing and managing its content, and customizing its experience.