Portal Federation with WebLogic Portal WRSP Part 1: The Basics

Portal Federation with WebLogic Portal WRSP Part 3: Advanced IPC Techniques

Originally published at developer.com

Managing Session Size

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.  

Abstracting WSRP IPC Session Management

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.

Formless Data Submission Data Sharing

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.

Page Switching with WSRP

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

 

Conclusion

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

Scott Nelson is a Senior Principal Consultant who strives to leverage portal technologies to provide businesses an improved ROI realized from a better user experience and reduced developer maintenance. In other words, he likes to do things better, faster and cheaper.

© 2010 Scott Nelson dba FYW Enterprises