The Java Portlet Specification (originally created through JSR-168) provides a standard for developing portal components with the Java programming language. Although the specification was originally created with the intent of standardizing the API and execution environment of portals and portlets, developers are also leveraging the specification as a standard for developing Web application plugins. By implementing or embedding a portlet container within a Web application, developers allow their Web applications to be extended by third parties through the deployment of compliant portlets.
Apache Pluto, the reference implementation of the Java Portlet Specification, implements a portlet container that can be embedded easily within a portal or Web application. This article provides a comprehensive tutorial that explains how to embed the Pluto Portlet Container (version 1.1) into a Web application. It investigates the basic architecture of Portal Systems, provides an overview of Pluto's public API, and discusses two different integration techniques.
Portal System Components
The Java Portlet Specification defines three major components of a portal system. The Portal itself provides personalization, single sign on, content aggregation, and other enterprise services. The specification does not specify which services must be implemented by the portal. This decision is left up to the discretion of the portal vendor.
Java Portlets provide content from disparate sources. This content is aggregated into a single presentation by the portal. Portlet developers wanting to create portlets, which are deployable within a compliant portal, implement interfaces defined by the Portlet API and adhere to the lifecycle restrictions defined by the Portlet Specification.
A Portlet Container manages the lifecycle and execution environment of Java Portlets. Portlet containers instantiate, initialize, and invoke portlets in a manner defined by the specification. By embedding a compliant portlet container within a portal or Web application, portlets can be used as an extension point of any Web applications.
The Pluto Portlet Container
The Apache Pluto Project implements an embeddable portlet container and other modules which are used to implement, test, and run it. The container has been implemented to provide a simple, lightweight implementation of the Java Portlet Specification.
The Pluto portlet container is implemented as a lightweight container. The container encapsulates various services used in the processing of requests, and leverages a domain model that represents portlet configuration information. In addition, the container is responsible for providing the execution environment specified by the portlet specification. This environment is provided primarily through the implementation of Portlet API interfaces.
Portlet Container Responsibilities
The container implementation within the Pluto Container fulfills requests through delegation a series of encapsulated components. The container is responsible for the lifecycle of these services, including their initialization, invocation, and destruction.
Each request received by the container includes a small amount of information concerning which portlet should be serviced in its current state. This information, encapsulated within the PortletWindow interface, is provided to the container along with the originating servlet request and response. It is the responsibility of the container to interpret this configuration information into an invocation plan and an environment in which it can be fulfilled.
Internal Container Components
To provide a clear separation of concerns, each of the functions required of the portlet container is serviced by an individual component. These components, integrated either directly or indirectly by the container, fulfill the requests requested of the portlet container.
- Portlet Invoker
The portlet invoker is responsible for dispatching portlet requests to the managed portlet instances. The portlet invoker utilizes the configuration information interpreted and provided by the container to determine which portlet is to be invoked. The invoker is responsible for invoking the proper service method of the portlet.
The portlet context manager is responsibile for ensuring that only one instance of the PortletContext interface exists for each PortletApplication serviced by the container. Internal container services needing to retrieve a Portlet Context request it from the manager. The manager determines whether or not an existing context can be utilized and creates it if necessary.
- PorltetDescriptorRegistry and Descriptor Services
The descriptor service is used to read Web application and portlet application deployment descriptors. The service reads descriptors from their appropriate locations and converts them into a simple domain model that provides configuration information to the container.
The Portlet Container encapsulates the descriptor service within a registry to ensure that the reading of the descriptors is optimized and only performed when necessary. The descriptor registry is responsible for caching the descriptor information.
Note: Because the reading and writing of deployment descriptors is a common requirement of portal systems, containers, and utilities, the descriptor service and implementation utilized by Apache Pluto is implemented as a separate module that is a dependency of the container and can be leveraged outside of the container.
Pluto's Implementaion Descisions
A few key implementation decisions enable Apache Pluto to be easily embedded and deployed within any compliant servlet container. These decisions are critical to understanding the container, and may effect design decisions of the embedding Web application (or portal).
- Service Interfaces
All critical services within the Portlet Container are defined as interfaces. This allows embedding applications to provide their own implementations of the services, while also allowing Pluto to provide default implementations for many of the services.
An implementation of the org.apache.pluto.PortletContainerServices interface must be provided during the creation of a container instance. This interface defines the services that must be implemented by the embedding container. Additionally, the org.apache.pluto.OptionalPortletContainerServices interface defines services that may be provided by the embedding application. Each individual services is detailed below.
- Instance Container
The mechanism for interacting with a portlet container is the org.apache.pluto.PortletContainer interface. This interface defines methods for managing the container's lifecycle and for invoking portlets.
Instances of the PortletContainer interface are created through the org.apache.pluto.PortletContainerFactory. The factory is used to create instances so that application integrators are shielded from implementation decisions and changes to Pluto's implementation.
The decision to utilize an instance container versus a static invocation façade allows Pluto to support the creation of multiple containers within a single JVM while maintaining simplicity. The alternate approach (implemented in previous versions of Pluto) proved to add significant complextity to Pluto's API by requiring tracking of services and configuration information through ThreadLocal variables and multiple lookup mechanisms.
- Cross Context Dispatching
Pluto utilizes cross-context dispatching, as defined by the servlet specification as the mechanism for invoking portlets. Pluto dispatches portlet requests through an intermediate servlet that configures portlets and invokes them as necessary.
By leveraging this mechanism, Pluto is able to leverage the servlet container's implementation to manage the execution environment required by the servlet specification—a level of compatibility that is required by the portlet specification.
As a result of this decision, portlet applications are deployed as traditional Web applications through the servlet containers deployment mechanism—and in a seperate Web application context. The portlet container then is configured to provide dispatch requests to the appropriate context as required. Although this result may be confusing to one unfamiliar with the inner workings of the container, it is easily understood once one understands the implementation decision and thinks of a portlet as a view into an application.
One downside of this configuration is the requirement that portlet container libraries that are utilized within both the embedding application and portlet applications must be loaded within a common classpath which is shared by both Web applications.