Author: thomas.heute(a)jboss.com
Date: 2007-05-02 09:07:29 -0400 (Wed, 02 May 2007)
New Revision: 7175
Removed:
docs/trunk/referenceGuide/en/modules/ipc.xml
Modified:
docs/trunk/referenceGuide/en/master.xml
docs/trunk/referenceGuide/en/modules/portalapi.xml
Log:
Merged IPC and PortalAPI
Modified: docs/trunk/referenceGuide/en/master.xml
===================================================================
--- docs/trunk/referenceGuide/en/master.xml 2007-05-02 08:35:47 UTC (rev 7174)
+++ docs/trunk/referenceGuide/en/master.xml 2007-05-02 13:07:29 UTC (rev 7175)
@@ -12,7 +12,6 @@
<!ENTITY tutorials SYSTEM "modules/tutorials.xml">
<!ENTITY xmldescriptors SYSTEM "modules/xmldescriptors.xml">
<!ENTITY urls SYSTEM "modules/urls.xml">
- <!ENTITY ipc SYSTEM "modules/ipc.xml">
<!ENTITY CMS SYSTEM "modules/cmsPortlet.xml">
<!ENTITY navtabs SYSTEM "modules/navtabs.xml">
<!ENTITY themeandlayouts SYSTEM "modules/themeandlayouts.xml">
@@ -69,7 +68,6 @@
<!-- understanding urls --> &urls;
<!-- Content integration --> &contentIntegration;
<!-- Portal API --> &portalapi;
- <!-- IPC --> &ipc;
<!-- clustering configuration --> &clustering;
<!-- WSRP --> &wsrp;
<!-- security administration --> &security;
Deleted: docs/trunk/referenceGuide/en/modules/ipc.xml
===================================================================
--- docs/trunk/referenceGuide/en/modules/ipc.xml 2007-05-02 08:35:47 UTC (rev 7174)
+++ docs/trunk/referenceGuide/en/modules/ipc.xml 2007-05-02 13:07:29 UTC (rev 7175)
@@ -1,234 +0,0 @@
-<chapter id="ipc">
- <chapterinfo>
- <author>
- <firstname>Roy</firstname>
- <surname>Russo</surname>
- <email>roy(a)jboss.org</email>
- </author>
- </chapterinfo>
- <title>InterPortlet Communication (IPC)</title>
- <sect1>
- <title>Introduction</title>
- <para>
- The first version of the Portlet Specification (JSR 168), regretfully, did not
cover interaction between
- portlets on a page. The side-effect of diverting the issue to the subsequent
release of the specification, has
- forced portal vendors to each craft their own proprietary API to achieve
interportlet communication. This
- chapter covers the JBoss Portal Interportlet Communication API, and its ability
to allow a developer to create
- links to other portal pages and affect behaviour in other portlets.
- </para>
- <note>For the remainder of this chapter, the sample available
- <ulink
-
url="http://anonsvn.jboss.org/repos/portletswap/portlets/2_4/bundles...
- here</ulink>
- , will be used to cover the API.
- </note>
- <warning>JBoss Portal IPC enables a one-to-one relationship between portlets!
Do not attempt to affect behaviour
- of more than one portlet per action, as it will not work!</warning>
- </sect1>
- <sect1>
- <title>Configuration</title>
- <sect2>
- <title>Service Descriptor</title>
- <para>
- IPC requires that a listener be available to intercept requests and respond
appropriately. To enable the
- listener, it has to be declared as an mbean in your service descriptor, as in
our example under
-
<emphasis>helloworldipcportlet.sar/META-INF/jboss-service.xml</emphasis>
- :
- <programlisting>
- <![CDATA[
-<?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.common.system.JBossServiceModelMBean">
- <xmbean/>
- <depends
- optional-attribute-name="Registry"
-
proxy-type="attribute">portal:service=ListenerRegistry</depends>
- <attribute name="RegistryId">ipc_listener</attribute>
- <attribute
name="ListenerClassName">org.jboss.portlet.hello.HelloWorldPortletB$Listener
- </attribute>
- </mbean>
-</server>]]>
- </programlisting>
- It is important to note here, that you will most likely not have to change
any of these values, except for
- the
- following:
- <itemizedlist>
- <listitem>
- <emphasis role="bold">name:</emphasis>
- Both the
- <emphasis>mbean type</emphasis>
- and the
- <emphasis>RegistryId</emphasis>
- value must match.
- </listitem>
- <listitem>
- <emphasis
role="bold">ListenerClassName:</emphasis>
- Full path to the listening portet's inner class that acts as the
listener.
- </listitem>
- </itemizedlist>
- </para>
- </sect2>
- <sect2>
- <title>Portal Descriptor</title>
- <para>Enabling IPC, also requires that the listener be declared in the
*-object.xml, so the Portal recognizes
- it.
- The declaration happens at the page level, as in our example:
- <programlisting><![CDATA[<!DOCTYPE deployments PUBLIC
- "-//JBoss Portal//DTD Portal Object 2.6//EN"
- "http://www.jboss.org/portal/dtd/portal-object_2_6.dtd">
-<deployments>
- <deployment>
- <parent-ref>default</parent-ref>
- <if-exists>overwrite</if-exists>
- <page>
- <page-name>IPC</page-name>
- <listener>ipc_listener</listener>
- ...]]>
- </programlisting>
- <note>The
- <emphasis>listener</emphasis>
- value must match the
- <emphasis>name</emphasis>
- values in your service descriptor!
- </note>
- </para>
- </sect2>
- <sect2>
- <title>The Listener</title>
- <para>
- Now that the listener is configured in the service descriptor and the portal
can recognize it, we must
- create the appropriate listener class within our portlet.
- </para>
- <para>In our example, Portlet A will be modifying the behaviour of Portlet
B. So then we will declare the
- listener in Portlet B, the recipient portlet.
- <programlisting><![CDATA[
-public static class Listener implements PortalNodeEventListener
-{
- public PortalNodeEvent onEvent(PortalNodeEventContext context, PortalNodeEvent event)
- {
- PortalNode node = event.getNode();
-
- // Get node name
- String nodeName = node.getName();
-
- // See if we need to create a new event or not
- WindowActionEvent newEvent = null;
- if(nodeName.equals("HelloWorldPortletAWindow") && event
instanceof WindowActionEvent)
- {
- // Find window B
- WindowActionEvent wae = (WindowActionEvent) event;
- PortalNode windowB = node.resolve("../HelloWorldPortletBWindow");
- if(windowB != null)
- {
- // We can redirect and modify the view/mode as well!
- newEvent = new WindowActionEvent(windowB);
- newEvent.setMode(wae.getMode());
- //newEvent.setWindowState(WindowState.MAXIMIZED);
- newEvent.setParameters(wae.getParameters());
- }
- }
-
- //
- if(newEvent != null)
- {
- // If we have a new event redirect to it
- return newEvent;
- }
- else
- {
- // Otherwise bubble up
- return context.dispatch();
- }
- }
-}]]></programlisting>
- </para>
- <para>
- It is important to note here some of the important items in this listener
class.
- Logic used to determine if the requesting node was Portlet A.:
-
<programlisting>nodeName.equals("HelloWorldPortletAWindow")</programlisting>
- </para>
- <para>
- Get the current window object so we can dispatch the event to it:
- <programlisting>PortalNode windowB =
node.resolve("../HelloWorldPortletBWindow");</programlisting>
- </para>
- <para>
- Set the original parameter from Portlet A, so Portlet B can access them in
its processAction():
-
<programlisting>newEvent.setParameters(wae.getParameters());</programlisting>
- </para>
- <para>
- Modify Portlet B windowmode and/or windowstate (ie, Maximize and place in
Edit Mode):
- <programlisting>
-newEvent.setMode(wae.getMode()); // Mode.EDIT;
-newEvent.setWindowState(wae.getWindowState()); //
WindowState.MAXIMIZED</programlisting>
- </para>
- </sect2>
- </sect1>
- <sect1>
- <title>Communicating with another Portlet</title>
- <para>
- Creating a link from Portlet A to Portlet B occurs in the same way you would
normally create a PortletURL:
- <programlisting><![CDATA[
-html.append("<form action=\"" + resp.createActionURL() + "\"
method=\"post\">");
-html.append("<input type=\"text\"
name=\"sometext\"><br/>");
-html.append("<select name=\"color\">");
-html.append("<option>blue</option>");
-html.append("<option>red</option>");
-html.append("<option>black</option>");
-html.append("</select>");
-html.append("<input type=\"submit\"/>");
-html.append("</form>");]]></programlisting>
- As you can see from the code above, we are creating a simple HTML form with an
ActionURL from within Portlet A.
- It will target itself, but be intercepted by the listener, created in Portlet B.
This form passes some text and
- a color value from input fields.
- </para>
- <para>
- Now, in Portlet B, our listener innerclass will trigger the processAction() in
Portlet B, reading in the
- parameters from the Portlet A form:
- <programlisting><![CDATA[
-public void processAction(JBossActionRequest request, JBossActionResponse response)
- throws PortletException, PortletSecurityException, IOException
-{
- String color = request.getParameter("color");
- String text = request.getParameter("sometext");
- if(color != null && text != null)
- {
- response.setRenderParameter("color", color);
- response.setRenderParameter("sometext", text);
- }
-}]]></programlisting>
- Setting the render parameters, it will now pass them on to the Portlet B,
doView();
- </para>
-
- </sect1>
- <sect1>
- <title>Communicating with another Page</title>
- <para>
- As seen in the included NavigationPortlet (tabs found at the top of the default
layout), we are able to create
- links to Portal Pages. Included in the
- <ulink
-
url="http://anonsvn.jboss.org/repos/portletswap/portlets/2_4/bundles...
- download sample</ulink>
- , you can see the basics of creating a link to a Portal Page. I have added
comments in-line to explain the code
- sample below:
- <programlisting>
-<![CDATA[
-// Get the ParentNode. Since we are inside a Window, the Parent is the Page
-PortalNode thisNode = req.getPortalNode().getParent();
-
-// Get the Node in the Portal hierarchy tree known as "../default"
-PortalNode linkToNode = thisNode.resolve("../default");
-
-// Create a RenderURL to the "../default" Page Node
-PortalNodeURL pageURL = resp.createRenderURL(linkToNode);
-
-// Output the Node's name and URL for users
-html.append("Page: " + linkToNode.getName() + " -> ");
-html.append("<a href=\"" + pageURL.toString() + "\">"
+ linkToNode.getName() + "</a>");
- ]]></programlisting>
- </para>
- </sect1>
-</chapter>
Modified: docs/trunk/referenceGuide/en/modules/portalapi.xml
===================================================================
--- docs/trunk/referenceGuide/en/modules/portalapi.xml 2007-05-02 08:35:47 UTC (rev 7174)
+++ docs/trunk/referenceGuide/en/modules/portalapi.xml 2007-05-02 13:07:29 UTC (rev 7175)
@@ -5,6 +5,11 @@
<surname>Viet</surname>
<email>julien(a)jboss.org</email>
</author>
+ <author>
+ <firstname>Thomas</firstname>
+ <surname>Heute</surname>
+ <email>theute(a)jboss.org</email>
+ </author>
</chapterinfo>
<title>Portal API</title>
<sect1>
@@ -324,15 +329,281 @@
</sect2>
<sect2>
<title>Portal session events</title>
- <para>The life cycle of the session of the portal associated with the user
can also raise events.</para>
+ <para>The life cycle of the session of the portal associated with the user
can also raise events. This kind of
+ event is not bound to a portal node since it is triggered whenever a portal
session is created or destroyed</para>
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center"
fileref="images/portalapi/PortalSessionEvent.png" format="png"/>
+ </imageobject>
+ <caption>
+ <para>The PortalSessionEvent class</para>
+ </caption>
+ </mediaobject>
+ <para>There are two different types of events:
+ <itemizedlist>
+
<listitem>org.jboss.portal.api.session.event.PortalSessionEvent.SESSION_CREATED,
fired when a new portal session is created</listitem>
+
<listitem>org.jboss.portal.api.session.event.PortalSessionEvent.SESSION_DESTROYED,
fired when a new portal session is destroyed</listitem>
+ </itemizedlist>
+ </para>
</sect2>
<sect2>
<title>Portal user events</title>
- <para>The life cycle of the user can also raise events such as its
authentication.</para>
+ <para>The life cycle of the portal user can also raise events such as its
authentication. A subclass of the wider scope UserEvent class is
+ provided and triggers events whenever a user signs in or out. The UserEvent
object gives access to the user name of the logged-in user through
+ the method <emphasis>String getId()</emphasis>.</para>
+ <mediaobject>
+ <imageobject>
+ <imagedata align="center"
fileref="images/portalapi/user.event.png" format="png"/>
+ </imageobject>
+ <caption>
+ <para>The UserEvent class and UserAuthenticationEvent
sub-classes</para>
+ </caption>
+ </mediaobject>
+ <para>The UserAuthenticationEvent triggers two events that can be
catched:
+ <itemizedlist>
+
<listitem>org.jboss.portal.api.session.event.UserAuthenticationEvent.SIGN_IN, fired
when a portal user signs in</listitem>
+
<listitem>org.jboss.portal.api.session.event.UserAuthenticationEvent.SIGN_OUT, fired
when a portal user signs out</listitem>
+ </itemizedlist>
+ </para>
+ <para>Based on the UserEvent class other custom user related events could
be added like one that would trigger when a new user is
+ being registered</para>
</sect2>
</sect1>
<sect1>
<title>Examples</title>
- <para>todo</para>
+ <para>The events mechanism is quite powerful, in this section of the chapter
we will see few simple examples to explain how
+ it works.</para>
+ <sect2>
+ <title>UserAuthenticationEvent example</title>
+ <para>In this example, we will create a simple counter of the number of
logged-in registered users. In ordder to do that we just need to keep track
+ of Sign-in and Sign-out events.</para>
+ <para>First, let's write our listener. It just a class that will
implement <emphasis>org.jboss.portal.api.event.PortalEventListener</emphasis>
and
+ its unique method <emphasis>void onEvent(PortalEventContext eventContext,
PortalEvent event)</emphasis>. Here is such an example:
+ <programlisting><![CDATA[
+package org.jboss.portal.core.portlet.test.event;
+
+import[...]
+
+public class UserCounterListener implements PortalEventListener
+{
+
+ /** Thread-safe long */
+ private final SynchronizedLong counter = new SynchronizedLong(0);
+
+ /** Thread-safe long */
+ private final SynchronizedLong counterEver = new SynchronizedLong(0);
+
+ public void onEvent(PortalEventContext eventContext, PortalEvent event)
+ {
+ if (event instanceof UserAuthenticationEvent)
+ {
+ UserAuthenticationEvent userEvent = (UserAuthenticationEvent)event;
+ if (userEvent.getType() == UserAuthenticationEvent.SIGN_IN)
+ {
+ counter.increment();
+ counterEver.increment();
+ }
+ else if (userEvent.getType() == UserAuthenticationEvent.SIGN_OUT)
+ {
+ counter.decrement();
+ }
+ System.out.println("Counter : " + counter.get());
+ System.out.println("Counter ever: " + counterEver.get());
+ }
+ }
+}
+ ]]></programlisting>
+ On this method we simply filter down to UserAuthenticationEvent then depending
on the type of authentication event we update the
+ counters. <emphasis>counter</emphasis> keeps track of the registered
and logged-in users, while counterEver only counts the number of
+ times people logged-in the portal.</para>
+ <para>Now that the Java class has been written we need to register it so
that it can be actionned when the events are triggered. To do
+ so we need to register it as an mbean. It can be done by editing the sar
descriptor file:
+ <emphasis>YourService.sar/META-INF/jboss-service.xml</emphasis> so
that it looks like the following:
+ <programlisting><![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<server>
+ <mbean
+ code="org.jboss.portal.core.event.PortalEventListenerServiceImpl"
+ name="portal:service=ListenerService,type=counter_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">counter_listener</attribute>
+ <attribute name="ListenerClassName">
+ org.jboss.portal.core.portlet.test.event.UserCounterListener
+ </attribute>
+ </mbean>
+</server>
+ ]]></programlisting>
+ This snippet can be kept as it is, providing you change the values:
+ <itemizedlist>
+ <listitem>
+ <emphasis role="bold">name:</emphasis> Must
follow the pattern: portal:service=ListenerService,type={{UNIQUENAME}}
+ </listitem>
+ <listitem>
+ <emphasis role="bold">RegistryId:</emphasis> Must
match the type (here: counter_listener)
+ </listitem>
+ <listitem>
+ <emphasis
role="bold">ListenerClassName:</emphasis> Full path to the listener
+ (here: org.jboss.portal.core.portlet.test.event.UserCounterListener).
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>That's it we now have a user counter that will display it states
each time a user logs-in our logs-out.</para>
+ </sect2>
+ <sect2>
+ <title>Achieving Inter Portlet Communication with the events
mechanism</title>
+ <para>The first version of the Portlet Specification (JSR 168),
regretfully, did not cover interaction between
+ portlets. The side-effect of diverting the issue to the subsequent release of
the specification, has
+ forced portal vendors to each craft their own proprietary API to achieve
interportlet communication. Here we will
+ see how we can use the event mechanism to pass parameters from one portlet to
the other.</para>
+ <para>The overall scenario will be that Portlet B will need to be updated
based on some parameter set on Portlet A.
+ To achieve that we will use a portal node event.</para>
+ <para>Portlet A is a simple Generic portlet that has a form that sends a
color name:
+ <programlisting><![CDATA[
+public class PortletA extends GenericPortlet
+{
+ protected void doView(RenderRequest request, RenderResponse response)
+ throws PortletException, PortletSecurityException, IOException
+ {
+ response.setContentType("text/html");
+ PrintWriter writer = response.getWriter();
+ writer.println("<form action=\"" + response.createActionURL() +
"\" method=\"post\">");
+ writer.println("<select name=\"color\">");
+ writer.println("<option>blue</option>");
+ writer.println("<option>red</option>");
+ writer.println("<option>black</option>");
+ writer.println("</select>");
+ writer.println("<input type=\"submit\"/>");
+ writer.println("</form>");
+ writer.close();
+ }
+}
+ ]]></programlisting>
+ </para>
+ <para>The other portlet (Portlet B) that will receive parameters from
Portlet A is also a simple Generic portlet:
+ <programlisting><![CDATA[
+public class PortletB extends GenericPortlet
+{
+
+ public void processAction(ActionRequest request, ActionResponse response)
+ throws PortletException, PortletSecurityException, IOException
+ {
+ String color = request.getParameter("color");
+ if (color != null)
+ {
+ response.setRenderParameter("color", color);
+ }
+ }
+
+ protected void doView(RenderRequest request, RenderResponse response)
+ throws PortletException, PortletSecurityException, IOException
+ {
+ String color = request.getParameter("color");
+ response.setContentType("text/html");
+ PrintWriter writer = response.getWriter();
+ writer.println("<div" +
+ (color == null ? "" : " style=\"color:" + color +
";\"") +
+ ">some text in color</div>");
+ writer.close();
+ }
+
+ // Inner listener explained after
+}
+ ]]></programlisting>
+ </para>
+ <para>With those two portlets in hands, we just want to pass parameters
from Portlet A to Portlet B (the color in
+ as a request parameter in our case). In order to achieve this goal, we will
write an inner Listener in Portlet B
+ that will be triggered on any WindowActionEvent of Portlet A. This listener will
create a new WindowActionEvent
+ on the window of Portlet B.
+ <programlisting><![CDATA[
+public static class Listener implements PortalNodeEventListener
+{
+ public PortalNodeEvent onEvent(PortalNodeEventContext context, PortalNodeEvent event)
+ {
+ PortalNode node = event.getNode();
+ // Get node name
+ String nodeName = node.getName();
+ // See if we need to create a new event or not
+ WindowActionEvent newEvent = null;
+ if (nodeName.equals("PortletAWindow") && event instanceof
WindowActionEvent)
+ {
+ // Find window B
+ WindowActionEvent wae = (WindowActionEvent)event;
+ PortalNode windowB = node.resolve("../PortletBWindow");
+ if (windowB != null)
+ {
+ // We can redirect
+ newEvent = new WindowActionEvent(windowB);
+ newEvent.setParameters(wae.getParameters());
+ // Redirect to the new event
+ return newEvent;
+ }
+ }
+ // Otherwise bubble up
+ return context.dispatch();
+ }
+}
+ ]]></programlisting>
+ </para>
+ <para>
+ It is important to note here some of the important items in this listener
class.
+ Logic used to determine if the requesting node was Portlet A.:
+
<programlisting>nodeName.equals("PortletAWindow")</programlisting>
+ </para>
+ <para>
+ Get the current window object so we can dispatch the event to it:
+ <programlisting>PortalNode windowB =
node.resolve("../PortletBWindow");</programlisting>
+ </para>
+ <para>
+ Set the original parameter from Portlet A, so Portlet B can access them in
its processAction():
+
<programlisting>newEvent.setParameters(wae.getParameters());</programlisting>
+ </para>
+ <!--
+ <para>
+ Modify Portlet B windowmode and/or windowstate (ie, Maximize and place in
Edit Mode):
+ <programlisting>
+newEvent.setMode(wae.getMode()); // Mode.EDIT;
+newEvent.setWindowState(wae.getWindowState()); //
WindowState.MAXIMIZED</programlisting>
+ </para>
+ -->
+ <note>The portlet 2.0 specification (JSR 286) will cover Inter Portlet
Communication so that portlets using it
+ can work with different portal vendors.</note>
+ </sect2>
+ <sect2>
+ <title>Link to other pages</title>
+ <para>Linking to some other pages or portals is also out of the scope of
the portlet
+ specification. As seen previously JBoss Portal offers an API in order to create
links
+ to other portal nodes. The JBoss request gives access to the current window node
from
+ which we can navigate from.</para>
+ <programlisting>
+<![CDATA[
+// Get the ParentNode. Since we are inside a Window, the Parent is the Page
+PortalNode thisNode = req.getPortalNode().getParent();
+
+// Get the Node in the Portal hierarchy tree known as "../default"
+PortalNode linkToNode = thisNode.resolve("../default");
+
+// Create a RenderURL to the "../default" Page Node
+PortalNodeURL pageURL = resp.createRenderURL(linkToNode);
+
+// Output the Node's name and URL for users
+html.append("Page: " + linkToNode.getName() + " -> ");
+html.append("<a href=\"" + pageURL.toString() + "\">"
+ linkToNode.getName() + "</a>");
+ ]]></programlisting>
+ <para>From this, it is easy to create a menu or sitemap, the
<emphasis>List getChildren()</emphasis>
+ method will return all the child nodes on which the user has the view right
access.</para>
+ </sect2>
+ <note>
+ <title>Samples</title>
+ <para>Those examples are available in the core-samples package in the
sources of JBoss Portal.
+ There are more examples of events usage in the samples delivered with JBoss
Portal. One of them
+ shows the usage of a portal node event to only have one window in normal mode at
a time in a region.
+ Anytime another window is being put in normal mode, all the other windows of the
same regions
+ are automatically minimized.</para>
+ </note>
</sect1>
</chapter>