Unique portlet ID

September 10, 2008 · Posted in Portlet · Comment 

Sometimes one need to retreive a unique ID for a particular portlet instance. In my case I needed it to implement configuration storage for each portlet instance independent on the user (see another post for comments on this topic).

The catch is, there is no such thing in the portlet specification. The closest you can find is the getNamespace(). The spec says “to ensure they are unique in the context of the portal page”. However, not neccessarily unique through the whole portal. At least, you don’t know until you have investigated it, for example asking the vendor or reading the code. Let’s say the mthod returns a unique ID. Now, here is the catch; you need that ID in processAction() as well!

In most cases, a portlet goes through render mode (doView)  and then after the user clicks a button, which invokes processAction(). That means, in render() you can grab the ID and for example inject it into the session.

public void render(RenderRequest req, RenderResponse res) throws ... {
    String  ID = res.getNamespace();
    //... do something with ID ...
    req.getPortletSession().setAttribute("portlet.id", ID);
    super.render(req, res);
}

And then pull it out again in processAction()

public void processAction(ActionRequest req, ActionResponse res) throws ... {
    String  ID = req.getPortletSession().getAttribute("portlet.id");
    //. . .
}

So far so good, as they say. Now, consider a lazy user, which stares at the portlet page until the session times out and thenafter clicks that darn button - pow! NullPointerException.

The only solution is to figure out how the portal handles portlet IDs internally. For example, the URL might be annotated with a portlet ID after an action request. For the portal I have been working with (SiteVision) I found out that its ID can be found in the session using the following code snippet.

public String       getID() {
    String  id = (String) getSessAttr("portlet.id");
    if (id == null) {
        String  portletID = "" + getReqAttr("sitevision.portlet");
        id = "svid" + portletID.replace('.', '_');
        setSessAttr("portlet.id", id);
    }
    return id;
}

I have to emphasize this again: this is not portal independet code.

Portlet edit CSS style

September 10, 2008 · Posted in Portlet · Comment 

Working with portlet development can be challenging, because the portal might or might not help you with routine stuff. A portlet goes through several modes. The normal mode is the View mode which shows the content. Another mode is Action, where the portlat receives request parameters and performs some action of it. The mode of interest in this blog entry, is the Edit mode. This mode is used to configure the portlet, or to be more exact, show a configuration form, which then is submitted into the action mode (processAction).

When you want to configure the portlet, the administrator clicks the edit button of the portal to show the edit form of the portlet in question. The result is a popup window with the content. It shows a complete HTML document, where the portlet form is just a subarea.  Now, here is the catch.

  • You want to apply some CSS styles.
  • You do not want to use inline styles, i.e., <tag style=”…”
  • You want to import an external CSS fil, so you can apply a consistent look&feel
  • The style directive must be placed in the head section, not in the body section
  • The HTML emitted by the portlet goes only somewhere into the body area

The solution is to use some a JavaScript snippet to inject the CSS imports into the head DOM. Thankfully, the HTML standard allows script tags to appear in the body. The JS snippet need to be evaluated, after the document has loaded and then modify the DOM. At this time I had just started to investigate jQuery a great JS library. So the snippet below is using the support of jQuery instead of brute-force JavaScript.

Put this snippet at the top of the dispatched JSP from a portlet’s doEdit().

<c:set var="webapp" value="${renderRequest.contextPath}" />
<script type="text/javascript" src="${webapp}/js/jquery-1.2.6.js"></script>
<script>
    $("<style type='text/css'> @import '${webapp}/css/portlet_edit.css'; </style>").appendTo("head");
</script>

As you can see, it relies on the JavaScript files being put into the /js/ directory and the CSS files into the /css/ directory, both at the top of the WAR file content.

Inter portlet communication

September 3, 2008 · Posted in Portlet · Comment 

Writing a portlet is like writing a web application, although the scope is smaller, page rendering limited to a minor area of a web site and you are usually in the dark of the semantics of the portal you will be deploying to. Although not all is lost, there are some fun as well.

I recently completed a portlet project, which involved three different portlets with specific roles. The first assembled search criteria, the second viewed query resuls using a table and the third is intended to view details of one found object. No rocket science here.

The problem pops up when these portlets needs to communicate. Surprisingly, there is currently no standard mechanism for this. The Portlet 1.0 specification  (JSR 168)  from October 2003, leaves some to desire for practical portlet development, enabling various portal server implementors to fill in the blanks or just leave it to the poor developer to find out. This summer (June 2008) version 2.0 of the spec (JSR 286) was finalized and it’s primary feature is portlet events. It remains to see how long it will take before the spec will be implemented on major plattforms.

Back to the problem; at the time I still had to solve it using a less world-wide known portal called SiteVision. It is a CMS with a bare-bone portlet container implementation.

A portlet is either rendering (render) or serving a form request (action) and at most one portlet per request can serve an action. Rendering means a portlet emits HTML - somehow. The idea is that one portlet on a page receives request parameters, processes them and then renders, followed by all other portlets rendering. This works as long as just the first portlet need to perform actions.

The key to the solution is to use the session. A portlet has access to two types of sessions; one private to the portlet instance (and user) called PORTLET_SCOPE and one common to all portlets called APPLICATION_SCOPE. Behind the scene both are part of the HttpSession using various key prefix trixs. For our problem, the app session is clearly the one to use.

The solution is straight forward, put an object in the app session at the sending side and pick it up at the receipment side. If you only have one pair of portlets communicting, choose a common session key name and there you go. On the other hand, if you need to tie two arbitrary portlets together, perhaps via user configuration, you quickly find you need a helper class that takes care of the details. The class PortletMessenger below wraps a session object and provides put() and get() methods.

public class PortletMessenger {
    private PortletSession      session;
    private String              topicName = PortletMessenger.class.getName();

    public PortletMessenger(PortletRequest request) {
        this.session = request.getPortletSession();
    }

    public PortletMessenger withTopic(String name) {
        if (name != null && name.length() > 0) topicName = name;
        return this;
    }

    public PortletMessenger put(String messageName, Object value)  {
        if (!(value instanceof Serializable)) throw new RuntimeException(...);

        this.session.setAttribute(createKey(messageName), value, PortletSession.APPLICATION_SCOPE);
        return this;
    }

    public Object   get(String messageName) {
        String  name  = createKey(messageName);
        Object  value = session.getAttribute(name, PortletSession.APPLICATION_SCOPE);
        session.removeAttribute(name, PortletSession.APPLICATION_SCOPE);
        return value;
    }

    protected String    createKey(String msgName) {
        return topicName + ':' + msgName;
    }
}

You send a portlet message like this

PortletMessenger msgr = new PortletMessenger( actionRequest ).withTopic("myTopic");
msgr.put("myMessageName", myMsg);

And receives the message somewhere else, like this

PortletMessenger msgr = new PortletMessenger( renderRequest ).withTopic("myTopic");
Object msg = msgr.get("myMessageName");

The topic name serves as a namespace - strictly not necessary, but convenient in a large application. The message name is the identifier and must be known on both sides. An alternative implementation might use a (short) queue, instead of the single slot queue I’m using. However, that is only needed if several portlets might send to a single destination. All action and rendering per request, happens on the same thread and as long a message is produced and consumed within the same request, queueing is not needed.

There is one catch to understand and that is the message is sent inside one processAction() at the sending portlet and received within doView() at the receiving portlet.