Originally published at developer.com
In part two of this series you created a session object to share data between your remote portlets running on the WebLogic Portal (WLP). Objects in the session are great when you will need them for an extended period of time rather than ask the user repeatedly for the same information. As portals (or any web based application) grow in size and complexity, it quickly becomes an effort to maintain performance. One way to improve performance is by keeping the session small, with only the objects that are necessary stored there. Portals that use WSRP can fill the session quickly when objects are placed in session just to share them on a request. Because of this need for speed, let’s take a look at how to orchestrate the way we share our objects using the session just long enough to achieve communication.
The WebLogic Portal includes and Event framework that is ideal for inter-portlet communication (IPC) as it provides APIs to handle such communications in a loosely coupled fashion. For example, let’s say that a user enters a value in portlet A and on submission portlet B needs to get that value for the purpose of a single update. While in the example from part two we used a session object to store the value, this time we will take advantage of the Event framework by firing a custom event in portlet A and the attaching our value to the event:
public
Forward ipcDemoCall1(IpcDemo1FormBean form)
{
Forward forward = null;
PortletBackingContext context =
null;
HttpServletRequest outerRequest =
null;
forward =
new Forward("success");
outerRequest = ScopedServletUtils.getOuterRequest(getRequest());
context =
PortletBackingContext.getPortletBackingContext(outerRequest);
context.fireCustomEvent("loadIpcPortletB",
form);
return forward;
}
Next, we will have portlet B listen for our custom event:
<netuix:handleEvent event=" loadIpcPortletB" eventLabel="handleEvent1"
fromSelfInstanceOnly="false" onlyIfDisplayed="false" sourceDefinitionWildcard="any">
The values above represent the custom event fired from portlet A, an event label that must be unique to avoid headaches. The two “false” values allow us to listen for the event from other portlets no matter where the listening portlet is displayed, and to listen for this event from any portlet.
The above is much easier to configure reliably using the portal IDE (Workshop or Workspace Studio, depending on the WLP version) and the portlet property editor in the Portal perspective, but it would take way too many screen shots to illustrate the full flow and the values above along with the intuitive interface should get you through.
Were we not using WSRP, the payload parameter of fireCustomEvent (getRequest().getParameter(IPC_VALUE));) would be readily available to the listening portlet. However, since the firing portlet (A) does not share the same request object as the listening portlet (B), we need to add a backing file to portlet B.
package
article.examples.portal.util.wsrp.backing;
import
com.bea.netuix.servlets.controls.content.backing.AbstractJspBacking;
import
com.bea.netuix.servlets.controls.portlet.backing.PortletBackingContext;
import
org.apache.beehive.netui.pageflow.scoping.ScopedServletUtils;
import
com.bea.netuix.events.Event;
import
com.bea.netuix.events.CustomEvent;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
javax.servlet.http.HttpSession;
public class
IpcEventHandler extends AbstractJspBacking
{
static final long serialVersionUID=1L;
public static final String IPC_DATA = ".data";
public void handlePayloadEvent( HttpServletRequest request,
HttpServletResponse
response,
Event
event)
{
CustomEvent customEvent =
null;
HttpServletRequest outerRequest = null;
HttpSession outerSession =
null;
Object payLoad =
null;
PortletBackingContext pbc =
null;
String payLoadId = null;
customEvent = (CustomEvent)event;
outerRequest = ScopedServletUtils.getOuterRequest(request);
outerSession = outerRequest.getSession();
pbc =
PortletBackingContext.getPortletBackingContext(request);
if(customEvent.getPayload()!=null)
{
payLoad = customEvent.getPayload();
payLoadId = pbc.getInstanceId()+IPC_DATA;
}
if(payLoad!=null)
{
outerSession.setAttribute(payLoadId,
payLoad);
}
}
}
This works because the event framework has access to request from portlet A even though portlet B does not. To help out the portlet, our backing file takes the event payload and places it in the session. This is done using the portlet id as part of the session key so that this backing file can be reused in any portlet, even by multiple instances of the same portlet.
Admittedly, portlet A could have simply put the value into the session, though doing so would create tighter coupling between the two portlets. Also, portlet A would put the value in the session regardless if there were a portlet that needed it, which would defeat our goal of managing the session. So, the next step is to keep the session to a minimum.
Once portlet B accesses the data from the session, it can store it in its local scope and safely remove it from the session by calling removeAttribute() on the session.
For a small project, having the listener manage the session object directly is probably adequate. In the case of larger projects, where there will be more developers and/or more IPC over WSRP it makes sense to have a more generic approach. Just as our backing file is abstract enough where it can be attached to any portlet listening for any event, we can build a light-weight handler to pull out the session value for the listening portlet and then remove the value from the session. Such a helper class would look like this:
package
article.examples.portal.util.wsrp;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpSession;
import
org.apache.beehive.netui.pageflow.scoping.ScopedServletUtils;
import
com.bea.netuix.servlets.controls.portlet.backing.PortletBackingContext;
public class
IpcDataHandler
{
public static final String IPC_DATA = ".data";
public static Object getIpcData(HttpServletRequest
request)
{
HttpServletRequest outerRequest = null;
HttpSession outerSession =
null;
Object ipcDataObj =
null;
PortletBackingContext pbc =
null;
outerRequest = ScopedServletUtils.getOuterRequest(request);
outerSession = outerRequest.getSession();
pbc =
PortletBackingContext.getPortletBackingContext(request);
ipcDataObj = outerSession.getAttribute(pbc.getInstanceId()+IPC_DATA);
if(ipcDataObj!=null)
{
outerSession.removeAttribute(pbc.getInstanceId()+IPC_DATA);
}
return ipcDataObj;
}
}
We can then use this helper in portlet B as follows:
Forward forward = null;
IpcDemo1FormBean ipcValue = null;
ipcValue = (IpcDemo1FormBean)IpcDataHandler.getIpcData(getRequest());
if(ipcValue!=null)
{
forward
= new Forward("success", ipcValue);
}
else
{
forward
= new Forward("success");
}
return
forward;
Using the above approach, the portlet can continue to work on a request level rather than having to access the session directly.
There are times when a form submission is not the desired UI design, such as tables of data in portlet A where your listening portlet is only interested in one line or a single value. In this case, the Netui tags provide a way to pass these values without a form:
<netui:anchor action="ipcDemoCall2">
<netui:parameter
name="ipcValue" value="Example 1"/>
IPC Link Example 1
</netui:anchor>
The ipcDemoCall2 action in portlet A then puts the value into an event as follows:
import
com.bea.netuix.servlets.controls.portlet.backing.PortletBackingContext;
private static final String IPC_VALUE =
"ipcValue";
@Jpf.Action(forwards = { @Jpf.Forward(name
= "success", path = "index.jsp") })
public Forward ipcDemoCall2()
{
Forward forward = new
Forward("success");
PortletBackingContext context =
null;
HttpServletRequest outerRequest = null;
outerRequest = ScopedServletUtils.getOuterRequest(getRequest());
context =
PortletBackingContext.getPortletBackingContext(outerRequest);
context.fireCustomEvent("loadIpcExample2B",
getRequest().getParameter(IPC_VALUE));
return forward;
}
In this example the value is simply a String rather than an object. Fortunately, we have created our generic helper to not care what kind of object is packed into the payload, so we can continue to pick up the value in the same way we handled it earlier.
Earlier we set up our event listening so that it would not matter if the listening portlet was displayed our not:
<netuix:handleEvent event=" loadIpcPortletB" eventLabel="handleEvent1"
fromSelfInstanceOnly="false" onlyIfDisplayed="false" sourceDefinitionWildcard="any">
The advantage to this is if we want to have the listening portlet on a different page and have the user taken there as part of the interaction. While in a file-based portal we can create this type of interaction by calling the page where the listening portlet resides, in a WSRP interaction we don’t even know where that page is, both because it is administered in a separate portal application and because the instance ID of all WSRP portlets, pages and books are generated at the time they are integrated into the consumer portal. Instead of generating links in code, we add a step to our event handling and load the page where the portlet resides. This is achieved by going the portlet properties as we did before and adding the Activate Page action:

Figure 1: Adding Activate Page to Event Handling
There are many ways to share data between portlets. Many developers have never explored the IPC tools available provided by the WebLogic Portal, either because they haven’t needed to or did not have the time explore the documentation thoroughly enough to discover that there are many robust APIs that facilitate developing a loosely-coupled application. While the advantages to doing so are very clear when demonstrated in the WSRP context, they are of benefit even without WSRP.
There are other approaches to achieving the same results as demonstrated in this series provided in the documentation. The goal here was to share approaches that are not as easily found and provide some real-world context around the value of learning the advance features of WLP. While you will certainly be able to get by with what we have covered, you will be able to make the best choice for your project by reviewing the documentation in addition to these articles.
About the Author
© 2010 Scott Nelson dba FYW Enterprises