One of the commonest queries from new portlet developers is how to create a link in one portlet which can trigger a response in a different portlet (typically an Index portlet which triggers the display of an item in a Display portlet). The problem stems from the way the portal has to keep portlets from interfering with each other: clicking a link in one portlet results in a request which is processed by only that portlet, so all other portlets are completely unaware of the interaction, and cannot see any parameters that might have been passed. Thus, for this scenario, the first portlet needs a way to explicitly send a message to the second, informing it of what action to perform or information to render. This functionality is commonly referred to as inter-portlet communication or IPC.
However, the method of inter-portlet communication is not defined in the current portlet specification, JSR168, although it will be in the next version. Almost every portal has its own custom implementation, with different messaging behaviours and APIs. Non portal-specific (i.e. JSR168-compliant and portable) solutions are possible, but require the portlet developer to implement their own IPC system.
A further common request is for clicking on a link in one portlet to result in navigation to a different portal page or portlet. This feature is sometimes included under the topic of IPC as it is often an associated necessity (for example, if the Display portlet is on a different page to the Index portlet, it is convenient for a selection on the Index portlet to additionally navigate to the Display page). In this thesis, we do not include navigation between portal pages as a critical component of IPC; however, we do discuss how limited page navigation could be supported (Section#).
IPC is not appropriate for all situations: sometimes it may be better to develop one portlet which can perform multiple tasks in different modes, rather than a collection of portlets that communicate among themselves. In particular, if the messages to be sent between portlets are large or frequent, and the portlets are tightly coupled and must always be used together in a particular arrangement on the page, this may indicate that the portlets would be more easily merged into one large portlet. However, if the portlets are related but only loosely coupled - each being responsible for well-defined and largely independent tasks - it may be more appropriate to treat them as components, linked using IPC.
In this chapter we will discuss some of the portal-specific IPC solutions available, the possible approaches for IPC implementations within JSR168, and finally our development of a JSR168-compliant IPC library.
Portal-specific IPC Implementations
Portals which implement their own custom inter-portlet communication mechanisms provide a communications API which allows the portlet developer to concentrate simply on sending the messages, without needing to know about the back-end implementation.
Usually, the process of linking portlets together with messaging must be performed by a portal developer or admin, using portal-specific configuration tools or APIs. This is acceptable for static site layouts controlled by the portal admin, but does not easily allow changes later. Thus, the most advanced implementations of IPC permit code-less configuration, allowing the end user of the portal to set up communication between portlets using web-based control panels, at runtime.
As discussed in Chapter#Instances, there is some variation in the treatment of portlet instances, and this affects the way IPC is configured in different portals. Most portals treat each portlet window as an independent source and sink of messages, and this is reflected in their IPC configuration tools, where IPC configuration is done in parallel with creating pages and placing portlet windows. However, some portals are more restrictive and consider the portlet entries in the portlet.xml registry as the true portlet instances, so the IPC configuration is tied directly to these and does not need to be associated with the page layout or portlet window IDs.
Some portals have extended their implementation of JSR168 to support their own IPC system; many simply continue to support their own non-JSR168 portlets, which often include IPC support preceding JSR168 by several years. In either case, using the portal-specific IPC solutions, even those that extend JSR168, will result in portlets which can only be deployed on that portal.
BEA WebLogic
BEA WebLogic manages portlet communication using a system similar to Java Listeners. Portlets can be set to listen to another portlet, identified using the source portlet window's unique ID, which is generated by the Portal. Portlet state is managed with explicit "page flows", which are defined using an editor program. A message is triggered by a user clicking on a link which corresponds to a named action in the page flow. When such a link in a source portlet is clicked, the corresponding function is also called in all listening portlets.
This approach requires the exact communication links between portlet windows to be specified during portlet development.
IBM WebSphere
IBM WebSphere's system for portlet communication is called "message events". Portlets which are in the same portlet application can send and receive messages (which may consist of any Java object), addressed using portlet window IDs. Portlets may implement a MessageListener interface, which includes a function that will be called when a message is received.
To process messages, the Portal manages the execution of the following, each time a page loads:
all action events (these may send message events)
all message events, executing Listener functions on the receiving portlets (these may send more message events, which will be processed until no more are left)
all window events (requests to change window state)
all renders (any messages sent during this phase will be ignored)
This procedure allows a message to trigger other messages, in a branching message chain which is fully processed before the page renders. Because messages may only be sent in the Action phase, and all message events are dealt with before the render phase begins, the message state is consistent and safe from any further changes when the portlets finally render.
WebSphere's advanced IPC system allows portlets to be developed without specific reference to particular portlet IDs or even agreed message names; the portlets are thus reusable components independent of any particular portal layout. Such cooperative ("Click-to-action") portlets register with a Property Broker, and a "Portlet Wiring Tool" portlet allows the Portal user to map connections between published properties and consumed properties at runtime.
Sybase Enterprise Portal 6.0's IPC implementation uses the Event-Listener model and is configured at page design-time using custom programs. Published message events are given global names, and are accessible across the whole portal. Limited types of data can be included in messages; the messages are received by portlets as CGI form parameters.
Oracle Portal (in Oracle Application Server 10g) has an advanced IPC system which is configurable at runtime by any page designer. This is a custom implementation which only works with Oracle's own kind of portlets.
Oracle defines three different kinds of parameters available to its portlets:
Private: Private parameters correspond to JSR168 portlet parameters, these are only visible to one portlet window.
Public: Public parameters are defined by the portlet programmer, and make up the portlet's published interface: the inputs and outputs of the portlet. At runtime, the page designer can assign values to these parameters (using a constant, a variable, or a page parameter).
Page/Page Group: Page (Group) parameters are defined and set at runtime by the page designer, and associated with a particular page or page group. The page designer can then map them to public parameters of portlets. In this way, multiple associated portlets on a page - e.g. each showing different information on a selected item - can be configured by a single change to a page parameter.
Each messaging event, with its associated public parameters, is explicitly defined by the portlet programmer as part of the portlet's published interface. At runtime, the page designer can configure the effect of the event produced by a portlet window: it can set page parameters from event parameters, and/or cause a redirect to a different page.
Like WebSphere's IPC implementation, this allows portlets to be developed and used as components which are independent of any particular portal layout, and configured through a web interface on the portal.
eXo Portal's IPC implementation uses an extended version of the JSR168 PortletContext to send messages in the Action phase, either directly to a named portlet or broadcast to all portlets in the same portlet application. MessageListener classes are registered in the portlet.xml, using eXo-specific extensions. The portlet entities referenced by name correspond directly to portlet instances in the portlet.xml, not individual portlet windows on pages.
Plumtree is unusual in using AJAX to render and update the display of portlet windows on a page, so that it is not necessary to reload the entire page when a portlet renders. Implicitly this method relies on the portal providing a way to remotely update and retrieve a single portlet window's fragmentary content, outside the context of the aggregated page; this is not a usual feature in portals. This is however a rendering approach which is becoming more seriously considered, as it has advantages in efficiency and speed. It does however introduce potential problems with usability and stability, due to the differences in page behaviour (e.g. bookmarks, back button may not behave as expected), and varying support for JavaScript in different browsers.
The dependence on JavaScript for page rendering allows the messaging logic layer to be moved from the server to the JavaScript on the client. Thus, a user clicking a link in a portlet will trigger a local JavaScript function call instead of a direct page submission to the server. This will in turn trigger JavaScript listeners belonging to other portlets, which can retrieve updated portlet window renders to display to the client, or redirect the client to a different page.
Thus, the standard JSR168 portlet request handling is largely bypassed for messaging, as all message events are triggered and processed on the client. Messages are not sent within either the action or the render phase, but in JavaScript on the client, and messages can be chained as many times as needed. JavaScript message listeners may invisibly initiate any number of new portlet requests behind the scenes, to update portlet state and retrieve new window renders.
The IPC configuration (e.g. message names, implementation and registration of JavaScript listeners) is hardcoded by the portlet programmer, and is not modifiable by portal users at runtime or during page construction.
Like eXo, Liferay adds its IPC support by extending its JSR168 implementation. It does this by introducing new versions of the JSP tags for generating links in a portlet.
The JSR168 actionURL and renderURL tags generate links which lead to a new Action or Render request targeted to the current portlet, with associated parameters and any other attributes such as changes of window state or portlet mode.
Liferay extends these tags with a new attribute, allowing the portlet developer to specify a portlet name to which the new request may be targeted. This approach allows a portlet send information to another portlet very easily. However, there are some limitations: messages cannot be broadcast to multiple portlets, and as the originating portlet is no longer targeted, it will have no way of knowing what link has been followed, or even that it has been clicked.
JBoss Portal 2.2 provides its own IPC implementation as an extension to JSR168. Its approach is to allow listeners to intercept events on the server and modify or redirect them.
Using JBoss's IPC, the portlet sending a message does not need to write any messaging-specific code; instead it simply posts the information to itself as a normal Action request. The receiving portlet will have registered a Listener class at deployment time (this is configured as an MBean in a deployment descriptor file). The Listener can inspect all events, and when it finds an Action event from the named source portlet window, it can intercept and replace it with a similar Action event targeting the listening (named) portlet window.
Thus in behaviour this would act similarly to Liferay's implementation (although more flexible): an Action URL in one portlet can result in that Action being executed on another portlet window.
Implementation approaches for JSR168-compliant IPC
In JSR168-compliant implementations of IPC, the portlet developer must completely define and implement the details of the communication system. As the system must work on any JSR168-supporting portal, the developer is restricted to using only the portlet features and services defined by JSR168.
Most of the custom approaches to implementing IPC taken by portals are not suitable for use in a pure JSR168 portlet, as they require portal-level modifications (usually to the portlet request processing procedure) that are beyond the reach of portlet code.
The Event/Listener model is commonly used in J2EE applications, and is the most popular choice among proprietary IPC implementations. It is well-defined and reliable, allowing programmers to implement and register Listeners to link portlets with message events - some portals only permit 1:1 messaging, others allow 1:many. The portal then gains the option to improve efficiency by re-rendering only those portlets which have received messages, and can also support message chaining. Unfortunately, it requires portal-level support to be properly implemented. In particular, we believe this model is unsuitable for a JSR168 solution because:
a listener registry and event system must be in place in the portal to call listeners when a messaging event takes place. This registry must well integrated into the portal, so that any portlet window can receive and act upon messages, even if the user has not yet visited and instantiated it in the current session. (In the portals examined this has been implemented in a variety of ways, including various modifications to the request processing pipeline and a mostly client-side JavaScript/AJAX implementation.) The portal must also provide listener configuration tools, again reliant on portal-support to enable configuration of not-yet-visited portlet windows at runtime.
configuration of listeners must have been completed before the user starts triggering any message events. Once an event has occurred, it is too late to configure a new portlet to listen to it. This is a design - not implementation - restriction of the model.
Thus, the main problems with the Event/Listener model are due to the way the messaging system must 'push' messages to the receivers. In the context of a JSR168 portlet, which has limited or no information about other portlets in its environment, this cannot be done reliably, and there is also no way of triggering the receiving portlets to act upon the message within the current portlet lifecycle.
We found a basic 'message-board' model more appropriate to the environment of a JSR168 portlet. In this model, messages may be published to a public space, and receiving portlets may explicitly read ('pull') any messages they are interested in, in their own time. This is a very loosely-coupled, asynchronous model, that does not need listening portlets to be registered before a message is sent; conversely, a new portlet window can easily be added to a page and configured to read a message that was sent previously in the session.
Within JSR168, we are restricted to sending and receiving messages within the standard portlet request handling procedure. Thus, messages may only be sent or received in the Action phase (while a request to the portlet is being processed, e.g. from a form submission) or in the Render phase (while the portlet display is being generated).
Those portals whose portlet interfaces are close to JSR168 typically require that messages are sent in the equivalent of the Action phase. This is because the Action phase is guaranteed to complete before the page starts rendering, so this policy should ensure that all portlets on the page see the same messages while they render. If the portlets were to send messages in the View phase, portlets rendering later on the page may show views inconsistent with other portlets, particularly if the portal uses threading to render portlets in parallel. This approach fortunately also corresponds well with the usual client behaviour that should trigger a message: for example, selecting an item in an Index portlet to trigger a message from that portlet containing the item's ID.
However, sometimes a message may be triggered by a non-client event: namely, in message chaining, where as a result of receiving a message, a portlet may need to send another message. In this case, the portlet will not have the opportunity to go into the Action phase to send the message, and if it is to send at all, must do so in the same Render phase. As this may result in the confusion and inconsistency described previously, this is not recommended - nor will it support multiple stages of message chaining within a single page render. This is one of the main disadvantages of using the Message Board model as opposed to Event/Listener.
Portlet windows may retrieve messages at any time when they are active - that is, during the Action or Render phases.
Portlets can therefore only retrieve and react to messages when a client views the portal page containing them, and - unless it is acceptable to put 'Update!' Action buttons in every portlet - this must be done in the Render phase. This goes against the recommended practice of making the Render code as lightweight as possible. An alternative would be to detect the presence of the new message and simply present a notification to the user that the portlet needs to be manually refreshed.
Thus, the messaging is asynchronous and also unreliable - a portlet window which is never viewed will never read and react to a message sent to it. This is efficient and as expected if we consider portlets as simple web pages and tools (interface components) that are only of importance when the user wants to view them. However it does emphasise that portlets should never be treated as functional components of an independent, back-end engine.
Another result of this behaviour is that for messages to be received, the Render phase must actually take place, which is usually triggered when a portlet window is shown on a page. However, to improve performance, some portals cache portlet render fragments until an explicit action is taken in a portlet, so preventing the view-phase reaction code from triggering. There is currently no way of informing a portlet window that its content needs to be refreshed as a consequence of a message sent from a different portlet. This is another disadvantage resulting from the lack of portal-level support for IPC. The only workaround - other than the previously mentioned 'Update!' buttons in every portlet - is to disable caching for the receiving portlets by setting their 'expiration-cache' to zero in the portlet deployment descriptor: this may in turn result in decreased performance. Thus, with caching turned off, it is even more important to make Render code lightweight, and if this is not possible the portlet developer may need to implement their own caching mechanism (e.g. storing re-used data in the session).
A messaging system must provide a centralised point of access for messages, visible to all portlets. For this, we must make use of shared message spaces which are provided by or compatible with JSR168.
The best and easiest approach is to store messages in the session (APPLICATION_SCOPE) {Fig. #}, which is accessible by all portlets in that application. This is the only easily-accessible shared storage place provided by JSR168, so it is usually recommended that portlets which need to communicate are packaged in the same portlet application.
Fig. # Simple interportlet communication using a shared session attribute. The Deployed Service Index portlet provides a list of services. Selecting a service from this list makes the Service portlet show its interface. This is implemented by storing the service path in a session variable, in the 'Application' scope which is visible to both portlets.
However, the issue mentioned in Section# concerning the sharing of sessions for portlets and servlets may cause problems if servlets are expected to take part in portlet messaging interactions. If the portlets and servlets in the same application do not see the same session, as is the case with certain portal setups, it will be necessary to treat the communication as cross-context.
Sometimes the PortletContext is mentioned as a possible storage place for shared data. There is one PortletContext per portlet application, on which attributes can be set, but - like ServletContext attributes - these are globally visible to all concurrent user sessions and are therefore not appropriate for our intended IPC use cases.
Web (and thus portlet) applications are kept strictly separate by the Servlet specification, and do not share sessions. Without any JSR168-provided shared space, it is therefore necessary to use a common external message store that is visible to all portlets, for example an EJB or database. This approach is more complex as it requires additional setup and maintenance of the external message store, so if at all possible it is best avoided, by packaging communicating portlets within the same application.
Fig# Cross-context communication relies on an external message store, and a known portal user session id.
If communication between portlet applications is required, each portlet must be able to access an identifier representing the user's whole portal session, not just the session ID for that portlet's application (which may differ across applications). A suitable identifier for the portal session may be retrieved through PortletRequest.getRequestedSessionId(), but this will only be available once the client browser has agreed to take part in the session, and will therefore not be available on the first portal page a client visits. Section# mentions some other approaches, but none are completely satisfactory.
When developing a portlet which sends a message, someone must do some configuration so that the message can be addressed to its receiving portlet(s). In many of the portal-specific solutions, the ID of the target portlet window is the configuration parameter required, and custom tools are often provided to ease the configuration process. In our "Message Board" model, the public message name is the parameter to be configured, and must match in both sending and receiving portlets.
The simplest level of configuration is to hard-code the message names (or target portlet window ID) in the portlets' code. For message names, this may result in naming clashes, and somewhat restrict the arrangement of portlets in portal pages. For target portlet windows, this will tightly-couple the portlet implementation to the particular portal page layout being used.
A slightly more flexible approach would be to define the message names/portlet windows used in a configuration file (e.g. as initial parameters for the portlets in the portlet deployment descriptor portlet.xml), which would allow the deployer of the portlet application (the portal administrator) to modify the message names/portlet windows used before the portal is started.
The greatest flexibility is provided by the ability to change the message names or target portlet windows while the portal server is running, typically through a web interface on the Portal itself. Both IBM WebSphere and Oracle Portal allow such configuration as part of the page layout editing interface (Figs #). This allows new portlets to be added and communication channels to be dynamically configured at any time during normal browsing.
Fig # IBM WebSphere's portlet "wiring" tool, a custom portlet that allows the user to configure the "wires" between portlets on a page at runtime.
Fig # Oracle Portal's page editing mode, allowing message parameter mappings to be configured.
There are several other notable features displayed by the portal-specific IPC implementations examined:
Oracle Portal includes an intermediate area for messages: page or page-group parameters, which can be used as variables to set input messages on many portlets at once. An alternative implementation with the same effect is to permit a single portlet to broadcast a message to many others, and the equivalent in our "Message Board" model would be to have many portlets reading from a single named message, which would correspond closely to the page parameter.
Some portals include redirection to a different page as part of the reaction to a portlet event. Typically this redirect is to the page on which the receiving portlet lies. We chose not include redirection as a feature in our IPC library implementation, although portlets can still redirect to a different page in their Action phase. This is discussed further in Section#.
The type of data permitted in portlet messages varies from simple Strings to any Java Object.
Our main interest is communication within the same portlet application, as all Discovery Net portlets are packaged together, and thus we will assume in the following discussion that messages are stored in the APPLICATION_SCOPE portlet session. However, in our actual portlet messaging implementation, access to the message store is abstracted out and the implementation can be replaced if cross-context messaging is required.
Hard-coding a pair of communicating portlets to check a known session attribute for a message is the easiest implementation approach (Fig. #), and appropriate when the portlets are being developed for a site whose design is static (although maintenance may become unwieldy if many communicating portlets are required, as the message names must be kept consistent).
However in our portal scenario, we need to develop portlets as reusable components that can be added in any quantity to any page, allowing communication channels between portlet windows to be configured at runtime by the user. For example one page may have a Service Index portlet window whose selections are displayed in a Service portlet window on the same page, and a second page may have two more Service portlet windows which the user has already configured to show two favourite services. Selections on the Service Index should only affect its corresponding Service portlet window, not the two on the other page. In addition, the user may be able to construct their own new pages, and add further portlet windows, which again should not necessarily interfere with existing communications.
Thus, in a changeable environment where many different types of portlets are sending out many different messages, it should be up to the user - not the portlet programmer - which messages the portlet window actually listens to or sends at runtime. Also, ideally, the internal message identifiers used in each portlet's code should not have to match those used in other portlets, nor should the portlet programmer have to worry about naming conflicts with other portlets.
As an even more advanced scenario, it is possible that a portlet may need to dynamically add or remove message inputs/outputs at runtime, for example a Service portlet which may switch between different services with different numbers of inputs and outputs.
We also need to support the situation where a user adds a new portlet window to a page that uses as input a message which has already been sent (Fig#). As we have discussed, this is not possible with the Event/Listener model, but is supported with the Message Board model.
Fig# Scenario where it is useful for a newly-added portlet to be able to read an existing message. The message in question is the result of a long-running service.
In summary, our requirements for an IPC library are a combination of the best portal-specific IPC features, and further features to support our flexible, dynamic portal scenarios:
Easy to use and integrate into existing portlet code: provide an IPC API that is as convenient to use as portal-specific alternatives.
Communication between portlets in the same webapp, but extendable to support cross-context communication
Communication between portlet windows on the same or different portal pages
Different mappings allowed for different portlet windows of the same portlet instance
Ability for messages to be sent to multiple receivers: eg A->B + A->C, even A->A
Support for hardcoding mappings by the portal admin, for when portal page layouts are fixed
Support for modifying mappings by a portal user at runtime
Ability to configure a portlet to receive as input a message that has already been sent
Support for addition or removal of mappings at runtime
To achieve these requirements we have developed a generic JSR168-compliant portlet messaging library which provides the necessary features and presents a simple messaging API for portlet developers to use. To remain JSR168-compliant, no portal-specific code could be used, and some limitations were necessary. Nevertheless this library meets our needs well, allowing our components to be written with clean code and to communicate flexibly. It is provided as a standalone library and is freely available from http://www.doc.ic.ac.uk/~mo197/portlets.
Throughout this discussion, it should be noted that the overriding requirement of this design is JSR168-compliance, and as a result it is not as efficient or robust as it might be otherwise. The eventual portlet IPC system defined by the next portlet specification will not have to work within these constraints, and will probably take an entirely different form as a result, perhaps more similar to existing portal-specific implementations.
In our chosen "Message Board" model, portlets may publish named messages which are then available to read at that message box name. Receiving portlets do not by default consume messages but only read them, so that other portlets may also read the same message. The messages persist until they are explicitly overwritten, so that any newly added or loaded portlets can read previously published messages. Thus these messages act as shared state indicators, rather than discrete events. A disadvantage of this approach is that the receiving portlets must themselves maintain a history of messages so that they can detect when a message has changed.
To avoid the problems of hard-coding message names, and to permit users to configure messaging channels between portlet windows at runtime, we have added a translation layer between the internal message names used in portlet code and the public names of message boxes visible at runtime to all portlet windows. Thus, internally a portlet may refer to a particular output message as "path", but in the portal, the message box to which the message is sent may be configured by the user, e.g. to "Service path for page 1". Similarly, the user can configure the names of message boxes from which the portlet reads each of its input messages. This process of message mapping allows all of 1:1, and 1:N messaging (Fig #), as every message channel includes an intermediate message box. It does not however support N:1 mappings, e.g. combining 2 boxes into 1 input, or 2 outputs into 1 box. In practice, this approach to abstraction is similar to Oracle Portal's use of 'page parameters' (Section#).
Fig# Abstraction of message names. Messaging library mediates access to shared messages, allowing mapping of local names (hard-coded in portlets) to global names (user-configurable at runtime).
As previously discussed, configuration of IPC may be performed, with increasing levels of flexibility, at:
programming time (in code or configuration files)
deployment time (in portlet parameters)
page development time (with custom tools or through a web interface on the Portal)
runtime (through a web interface on the Portal).
The latter, most flexible, option is what we require.
Approach
Advantages
Disadvantages
1. In each portlet
Mappings are kept together with their portlet - intuitive. Efficient, as mappings are only loaded when a portlet window is first viewed.
Need to edit and save every portlet involved in the communication - potentially cumbersome
2. In a single "wiring tool" portlet
All mappings can be edited and seen at once - fast.
Potentially more complicated for user, if there are many mappings visible. All mappings are stored in a single portlet, which would need a way of accessing information about all the portlet windows in the portal - even before their pages have been viewed (requires portal-level support).
Table# Approaches to storing IPC configuration: GUI presentation.
Approach
Advantages
Disadvantages
1. Store in portlet preferences
Easy to implement, JSR168 mechanism. Can be set as default values upon deployment, or by user at runtime.
The portlet window must be instantiated/viewed to be able to load preferences.
2. External to portal
Can use any interface (per portlet or centralised), and no loading/timing problems - they can all access the store. Supports cross-context communication.
Extra work and dependencies in setting up and managing an external store.
Table# Approaches to storing IPC configuration: storage location.
The possible approaches to storage and configuration of the message mappings are summarized in Tables #.
While a single "wiring tool" portlet would be the most elegant approach for configuring message mappings - and is the usual approach taken by custom IPC implementations - it is not possible to implement effectively without portal-level support for retrieving a listing of all portlet windows on the site. Therefore we must spread out the mapping configuration among the portlets to which the mappings belong: allowing configuration of each portlet's input and output mappings in its own Edit mode. For storage of mappings, we decided to to use the portlet preferences, as a simple and flexible mechanism which allows values to be set both upon deployment and at runtime by the user. However we additionally propagate the mappings to a centralised MessageStore when the portlet first loads, and in this way can optionally support cross-context communication by providing an externally-persisted MessageStore implementation.
To achieve this, the portlets delegate to a shared Message Helper in the application session to publish and read all messages (the Message Helper in turn delegates to a pluggable Message Store). When a portlet first loads, it registers its inputs and outputs through the Message Helper, and from then on the Message Helper refers to and modifies these local-to-global message name mappings as required (Fig. #). The mappings are defined and saved in each portlet's parameters, using the standard parameter persistence mechanism, and may be modified in each portlet's Edit mode. A simple but generic implementation of this edit mode is shown in Fig. #: the interface is dynamically generated by inspection of the messages in the Message Store and the current portlet's messaging configuration.
Fig. # Dynamically-generated mapping configuration forms, accessible in the portlet's Edit mode at runtime. Two portlets are shown, the first configured to publish a message, the second to read it.
The main disadvantages of this approach are:
Both ends of a communication channel must be separately configured: both the sending portlet's output mapping and the receiving portlet's input mapping (Fig #). The user interface for IPC configuration could potentially be improved greatly using AJAX, if the portlet/servlet session problems were not a concern.
Existing mappings (e.g. available output messages) will only be included in the configuration dialog after their parent portlet window has been rendered (and thus loaded) in the user's current session at least once.
In implementation, the portlet developer does not need to make their portlets extend from any special portlet class: rather they can use the messaging library as a separate service to be called when needed, simply including the messaging library JAR in their portlet application. Of course, as it is not a standard, only portlets which have been designed to use this messaging library will be able to communicate with each other.
The portlet developer must provide a portlet ID to uniquely identify the portlet window to the Message Helper. This is not directly accessible through JSR168, but workarounds are available as discussed in Section#.
public void doView(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
PortletSession portletSession = request.getPortletSession(true);
String id = getInstanceID(request);
String msg_session_id = MessageHelper.getSessionID(request);
// load this portlet's inputs and outputs from preferences
MessageHelper.loadPrefs(request, id, msg_session_id);
MessageHelper helper = new MessageHelper(portletSession, id, msg_session_id);
String broadcastAuthor = helper.getAsString("author");
...
writer.write("Selected author: "+broadcastAuthor);
Code fragment showing the use of the IPC library to a) send a message in one portlet b) receive a message in another portlet.
The exact implementation of Message Store used is easily configured through a properties file. Hence for example support for cross-context communication can be switched on or off without recompiling the portlet code.
In addition, for cross-context communication, the implementation of the SessionIDRetriever is also configurable, due to the issues mentioned in Section#.
As previously mentioned, navigation between pages is often a desired side-effect of sending messages, usually to visit the page which contains the portlet receiving the message. There are a few problems that make the implementation of this feature non-trivial.
One technical restriction is that a portlet can only change the page (by sending a 'redirect' instruction to the client browser) in the Action phase, as this is the only time in its lifecycle that it has access to page headers. Thus, messages sent from a Render phase (as might be done in response to receiving a message) will not be able to trigger page changes. This means that IPC-triggered page changes can only happen with primary messages, sent directly as a result of a user's click - which will probably usually be the case anyway.
Secondly, there is the problem of configuring the address of the page to redirect to. This address is entirely situation-dependent, and will be different for each portal implementation, and each website layout. Currently, the user must always look up this address and configure it manually in every instance of the portlet. Even in the case where we know Portlet A always sends the message to Portlet B, and wishes to automatically navigate to the page containing Portlet B, there is no way for the portlet code to find out the target page address using the Portlet API. In addition, we would want to be able to present (at runtime) a user-friendly configuration interface in the portlet itself, allowing users (or just page designers) to select the target page from a list of all available portal pages. But again, due to the lack of a portal-context-inspection API (as discussed in Section#), this is not possible without using portal-specific code, and instead we are forced to require the users to find out and type in the full target page URL themselves.
The page-navigation feature is not currently included in our Portlet Messaging Library, due to these technical and design issues. However, they are not critical and may be acceptable if the need is great enough and the limitations are made clear, so this feature will probably be introduced in the future.
In this chapter we have introduced the topic of inter-portlet communication and discussed its implementation in different portals, and we have then described the design and implementation of a JSR168-compliant IPC library.
The restrictions of the IPC library are mainly due to the limitations of working within JSR168, and so cannot be practically resolved at this time. These include:
Send messages in Action phase (not mandated, but highly recommended)
Receive messages in Render phase (thus view caching must be disabled for receiving portlets, whose view process might not be lightweight)
No explicit support for message chaining
Need to obtain an ID for each portlet window
In addition, the current interface for modifying message mappings in the IPC library could be made much simpler to use and understand. A more intuitive presentation would be to allow the user to click & drag to connect outputs to inputs, using JavaScript. Implementing such an interface would have to overcome a number of concerns:
treatment of multiple pages: how could a user connect together portlet windows on different pages?
portlet preferences on more than one portlet window would need to be saved to set up a single connection, which would require multiple 'update/save' requests to the portal.
Such a messaging configuration interface would be possible using AJAX, but would first require some additional portal features:
centralised support and management of message mappings
access methods to retrieve information about what other portlet windows are present in the site, including those which have not yet been visited by the user.
servlet endpoints permitting independent access to portlet windows (e.g. for background-saving of portlet window preferences using AJAX)
reliable consolidation of servlet and portlet sessions
However, our library still provides a portable, flexible and easy-to-use implementation of IPC for JSR168 portlets, as a viable alternative to portal-specific solutions. In summary, the IPC Library's features are:
Simple API
Messages are public and have a two-part identifier: namespace + name.
Message contents may be any Java object
Flexible, loosely-coupled communication between portlet windows
Configuration in portlet.xml default preferences, or through editing portlet preferences at runtime
Messaging within or across portlet applications
Pluggable Message Store for different concrete implementations
Future developments of the IPC library will probably include support for page navigation alongside sending messages. While this is not a concept that is strictly tied to messaging, it is a commonly-associated and often-requested parallel feature.