Level: Intermediate J. Jeffrey Hanson (jeff@jeffhanson.com), CTO, Max Software, Inc.
17 Jul 2007 Portal and portlet technology development is a hot skill to have,
especially when developing Web 2.0-enabled applications. The Apache Pluto project is
the reference implementation of the Java™ Portlet Specification, which was
originally created through the Java Community Process and Java Specification
Request (JSR) 168. The specification defines guidelines for portals and portlet
components developed with the Java programming language. This specification is being
recognized as the universal standard for traditional portals and as a framework for
building pluggable Web applications. Find out how combining the Pluto project with
Apache Geronimo's Java Platform, Enterprise Edition (Java EE) platform creates a highly flexible and powerful environment for
building customizable and manageable systems using portals and portlets.
Introduction to Apache Pluto
Apache Pluto, a subproject of the Apache Portals project, is an open source
implementation of the Java Portlet Specification. The Pluto project provides a
portlet container runtime environment, as mandated by the specification, in which
portlets can be instantiated and managed. In this article, I discuss the
high-level features of Pluto and how Pluto can be integrated with Apache Geronimo.
There's also a sample application (see the Downloads section) containing Geronimo GBeans, which abstract the public interfaces of the primary components of the Pluto framework. These GBeans can then be deployed to a running Geronimo instance, where they can be used to monitor and manage Pluto's portal features.
The Pluto project provides a portlet container for managing portlets and a
special-purpose portal application known as the Portal Driver, which provides
configuration services, a template framework, and a framework for invoking
individual portlets embedded within the container. The Pluto portlet container
manages portlet invocations, portlet context handling, portlet deployment
descriptor registry functionality, and portlet deployment descriptor services. The
container also provides a plug-in framework for extending itself with additional
functionality.
The Pluto portlet container exposes a set of mandatory and optional services for
facilitating, among other things, communication between portlets and calling
parties. These services are described later in this article.
The diagram in Figure 1 illustrates the primary components of Apache Pluto.
Figure 1. Architectural components
of Apache Pluto
Introduction to Apache Geronimo
Apache Geronimo is a fully compliant Java EE platform that
you can use to build enterprise-grade applications and services. Geronimo
is based on an architecture that uses Inversion of Control (IoC) techniques to
decouple components and services. This decoupling makes an extremely configurable
and modular runtime environment. Geronimo also takes advantage of Java
Management Extensions (JMX) and a similar proprietary managed-bean framework that
makes Geronimo an easy platform to monitor, configure, and manage.
Geronimo is bootstrapped using a given aggregation of assembled modules that are
connected and managed internally by a lightweight kernel component. A Geronimo
module is an arbitrary component made up of a set of classes: dependencies, other
modules, and a serialized configured state. The Geronimo kernel loads and
assembles modules when a Geronimo instance is started. Modules determine
functionality for a runtime Geronimo subsystem and the dependencies that
are required for each Geronimo subsystem. All core services in a Geronimo run time
are deployed as modules.
Modules are described using an XML document that's
referred to as a deployment plan or plan. A final deployment plan in
Geronimo is made up of a combination of an initial deployment plan, a Maven
Project Object Model (POM) file, and a Maven project.properties file. Figure 2
shows how these files are processed to create a final deployment plan.
Figure 2. Geronimo deployment
plans
The contents of a plan are constrained by an XML Schema Document (XSD). Among
other things, a plan defines a module ID, a module's dependencies, environment
properties for a module, services provided by the module, and GBeans for the
module.
The example in Listing 1 illustrates a simple Geronimo deployment plan.
Listing 1. A simple Geronimo deployment plan
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="http://geronimo.apache.org/xml/ns/deployment-1.1">
<environment>
<moduleId>
<groupId>geronimo</groupId>
<artifactId>simple</artifactId>
<version>1.0.0</version>
<type>car</type>
</moduleId>
<dependencies>
<dependency>
<groupId>geronimo</groupId>
<artifactId>j2ee-server</artifactId>
<type>car</type>
</dependency>
</dependencies>
<hidden-classes/>
<non-overridable-classes/>
</environment>
<gbean name="SimpleService" class="com.example.myservices.MyServiceGBean">
<attribute name="prop1">12345</attribute>
<attribute name="prop2">This is the value for property 2</attribute>
</gbean>
</module>
|
When a deployment plan similar to the plan in Listing 1 is transformed by the
build process, a Configuration Archive (CAR) file is created with a unique name.
The unique name generated for the configuration in Listing 1 is
geronimo/simple-1.0.0/car.
Geronimo CAR files
A CAR file is an automatically generated Java Archive (JAR) file containing the
serialized state of a deployment plan and any other ancillary resources. A
serialized deployment plan is embodied in a file called config.ser in the META-INF
directory of the CAR. CAR files are created by the build process via the Geronimo
packaging plug-in for Maven.
Geronimo repositories
A Geronimo repository is a data store and registry of artifacts, typically
structured as a directory hierarchy on the file system. The binary distribution of
Geronimo provides a directory named repository that contains all dependencies for
the modules that make up the core Geronimo platform.
A Geronimo artifact is an arbitrary entity, such as a JAR file, Web
Archive (WAR) file, CAR file, and so on, that's added to a Geronimo repository
using either the Geronimo Web console or the command-line deployment and build
utilities provided with the Geronimo distribution.
Download and install Apache Geronimo
Download the Geronimo platform from the site listed in the
Resources section, and extract the files to a directory
to be referred to as {GERONIMO_HOME}. After you've downloaded and extracted the
Geronimo distribution, execute the startup script found in the
{GERONIMO_HOME}\bin\ directory of your Geronimo installation. You should see a
console window similar to Figure 3.
Figure 3. Geronimo startup
The startup console shows a number of modules, connectors, and applications that
are loaded and started and from which the Geronimo runtime environment is
created. You can stop the Geronimo run time using the shutdown script, also found
in the {GERONIMO_HOME}\bin\ directory of your Geronimo installation.
Pluto services used by Geronimo
Geronimo 1.1.1 uses Pluto 1.0.1 as the portal environment for its management
console. In this portal environment, services required by the portal container and
services used by the portal driver are defined and loaded when the Web console
initializes.
The following is a list of the standard services defined for Geronimo's
Pluto-enabled Web console:
-
Config service —
The
ConfigService interface
represents information about Geronimo's Pluto portal configuration.
-
Factory manager service —
The
FactoryManagerService interface represents
functionality for managing the lifetime of factories registered during the Pluto
container startup.
-
Log service —
The
LogManagerService interface
represents functionality defining the Pluto portal driver's logging
implementation.
-
Portlet definition registry service —
The
PortletDefinitionRegistryService interface represents
all portlets and portlet applications available in the Web console portal. This
service presents and manages information about the Web console portlets and
portlet applications.
-
Portlet entity registry service —
The
PortletEntityRegistryService interface represents a
registry of all portlet and portlet application instances available in the Web
console portal.
-
Page registry service —
The
PageRegistryService
interface represents a registry of pages, windows, and portlet entries that make
up the Geronimo Web console.
In this article, you create GBeans and utilities that expose these Pluto
services to an administration framework operating in the Geronimo runtime
environment.
Managing the Pluto portal environment
Before you begin work to manage the Pluto environment, you need to download the
source for the Pluto framework (see the Resources section
for a link). Download and
extract the files to a directory to be referred to as {PLUTO_HOME}.
Object instances representing the Pluto services mentioned previously can be
retrieved by a component running within the same servlet context as the Web
console Web application. This allows access to configuration information that can
be wrapped by Geronimo GBeans.
Configuration information for the Pluto portal environment is referenced by the
object stored in the
org.apache.pluto.portalImpl.services.ServiceManager
class and retrieved using the getService method of the
ServiceManager class. A reference to the
org.apache.pluto.portalImpl.services.config.ConfigService
class must be passed as a parameter to the getService
method of the ServiceManager class to retrieve an
instance of the ConfigService component.
With an instance of the ConfigService component
available, you can wrap this component as a standard Geronimo GBean and make it
available to the Pluto admin environment. Listing 2 illustrates how the
ConfigService information is presented by a Geronimo
GBean.
Listing 2. ConfigService as a Geronimo GBean
public class ConfigServiceGBean
implements GBeanLifecycle
{
public static final GBeanInfo GBEAN_INFO;
static
{
GBeanInfoBuilder infoBuilder =
new GBeanInfoBuilder("ConfigServiceGBean", ConfigServiceGBean.class);
infoBuilder.addAttribute("parameters",
org.apache.pluto.portalImpl.util.Parameters.class,
true);
infoBuilder.addOperation("getParameters");
infoBuilder.addOperation("setString", new Class[] { String.class,
String.class });
infoBuilder.addOperation("getString", new Class[] { String.class });
infoBuilder.addOperation("getInteger", new Class[] { String.class });
infoBuilder.addOperation("getBoolean", new Class[] { String.class });
infoBuilder.addOperation("paramKeys");
GBEAN_INFO = infoBuilder.getBeanInfo();
}
public static GBeanInfo getGBeanInfo()
{
return GBEAN_INFO;
}
private org.apache.pluto.portalImpl.services.config.ConfigServiceImpl
configServiceImpl = null;
public ConfigServiceGBean()
{
try
{
Class configServiceCls =
Class.forName("org.apache.pluto.portalImpl.services.config.ConfigService");
org.apache.pluto.portalImpl.services.Service configService =
org.apache.pluto.portalImpl.services.ServiceManager.getService(configServiceCls);
if (configService != null)
{
configServiceImpl =
(org.apache.pluto.portalImpl.services.config.ConfigServiceImpl)
configService;
}
}
catch(Exception e)
{
System.err.println("Exception in ConfigServiceGBean: " + e);
}
}
public org.apache.pluto.portalImpl.util.Parameters getParameters()
{
return configServiceImpl.getParameters();
}
public java.util.Iterator paramKeys()
{
return configServiceImpl.getParameters().keys();
}
public String getString(String name)
{
return configServiceImpl.getString(name);
}
public void setString(String name, String value)
{
configServiceImpl.getParameters().setString(name, value);
}
public Integer getInteger(String name)
{
return configServiceImpl.getInteger(name);
}
public Boolean getBoolean(String name)
{
return configServiceImpl.getBoolean(name);
}
public void doFail()
{
System.err.println(getClass().getName() + " failed");
}
public void doStart()
throws Exception
{
System.out.println("Starting " + getClass().getName());
}
public void doStop()
throws Exception
{
System.out.println("Stopping " + getClass().getName());
}
}
|
After you've created a standard Geronimo GBean for the
ConfigService component, it must be loaded and started
by the Geronimo kernel. You retrieve the Geronimo kernel using the
getSingleKernel method of the
org.apache.geronimo.kernel.KernelRegistry class.
With a reference to the kernel, you can describe a GBean using a
GBeanData instance. The GBean is then loaded and
started by the kernel, as shown in Listing 3.
Listing 3. Loading and starting a GBean using the GBeanManager
public class GBeanManager
{
public static void loadAndStartGBean(Class gBeanCls,
GBeanInfo gBeanInfo,
String serviceType)
{
java.net.URI gBeanURI =
java.net.URI.create("devworks/" + gBeanCls.getName() + "/1.0.0/?service="
+ serviceType);
org.apache.geronimo.gbean.AbstractName abstractName =
new org.apache.geronimo.gbean.AbstractName(gBeanURI);
org.apache.geronimo.gbean.GBeanData gBeanData =
new org.apache.geronimo.gbean.GBeanData(abstractName, gBeanInfo);
System.out.println("Loaded gBeanData for class: " + gBeanCls.getName());
org.apache.geronimo.kernel.Kernel geronimoKernel =
org.apache.geronimo.kernel.KernelRegistry.getSingleKernel();
System.out.println("Found kernel: " + geronimoKernel.getKernelName());
ClassLoader clsLoader = Thread.currentThread().getContextClassLoader();
try
{
geronimoKernel.loadGBean(gBeanData, clsLoader);
System.out.println("Loaded gBean: " + gBeanCls.getName());
}
catch (GBeanAlreadyExistsException e)
{
System.out.println("GBean [" + gBeanCls.getName() + "] already loaded");
}
try
{
geronimoKernel.startGBean(gBeanCls);
System.out.println("Started gBean: " + gBeanCls.getName());
}
catch (GBeanNotFoundException e)
{
System.err.println("GBean [" + gBeanCls.getName() + "] not found");
}
}
public static void stopAndUnloadGBean(Class gBeanCls)
{
org.apache.geronimo.kernel.Kernel geronimoKernel =
org.apache.geronimo.kernel.KernelRegistry.getSingleKernel();
System.out.println("Found kernel: " + geronimoKernel.getKernelName());
try
{
geronimoKernel.stopGBean(gBeanCls);
System.out.println("Stopped gBean: " + gBeanCls.getName());
}
catch (GBeanNotFoundException e)
{
System.err.println("GBean [" + gBeanCls.getName() + "] not found");
return;
}
try
{
geronimoKernel.unloadGBean(gBeanCls);
System.out.println("Unloaded gBean: " + gBeanCls.getName());
}
catch (GBeanNotFoundException e)
{
System.err.println("GBean [" + gBeanCls.getName() + "] not found");
return;
}
}
public static Object getGBean(Class gBeanCls)
throws GBeanNotFoundException
{
org.apache.geronimo.kernel.Kernel geronimoKernel =
org.apache.geronimo.kernel.KernelRegistry.getSingleKernel();
System.out.println("Found kernel: " + geronimoKernel.getKernelName());
return geronimoKernel.getGBean(gBeanCls);
}
}
|
After the ConfigService component has been wrapped in
a Geronimo GBean and loaded and started by the kernel, a JavaServer Pages (JSP)
component or
servlet can use the GBean to access information managed by the
ConfigService component.
The JSP example in Listing 4 illustrates retrieving the
ConfigService GBean and using it to get and set
information managed by the ConfigService component.
Listing 4. Management page for the ConfigService GBean
<h3>Pluto Admin on Geronimo: Config Service</h3>
<%
try
{
com.devworks.pluto.gbeans.GBeanManager.loadAndStartGBean(
com.devworks.pluto.gbeans.ConfigServiceGBean.class,
com.devworks.pluto.gbeans.ConfigServiceGBean.GBEAN_INFO,
"config");
Object gbeanObj =
com.devworks.pluto.gbeans.GBeanManager.getGBean(
com.devworks.pluto.gbeans.ConfigServiceGBean.class);
if (gbeanObj != null)
{
com.devworks.pluto.gbeans.ConfigServiceGBean configServiceGBean =
(com.devworks.pluto.gbeans.ConfigServiceGBean)gbeanObj;
java.util.Enumeration reqParams = request.getParameterNames();
while (reqParams.hasMoreElements())
{
String paramName = (String)reqParams.nextElement();
String newParamValue = request.getParameter(paramName);
String oldParamValue = configServiceGBean.getString(paramName);
if (newParamValue.equalsIgnoreCase(oldParamValue) == false)
{
System.out.println("Setting param: " + paramName + " to value: "
+ newParamValue);
configServiceGBean.setString(paramName, newParamValue);
}
}
out.println("<form name='configForm' method='post' "
+ "action='ConfigServiceAdmin.jsp'><table>");
java.util.Iterator keys = configServiceGBean.paramKeys();
while (keys.hasNext())
{
String paramKey = keys.next().toString();
String paramValue = configServiceGBean.getString(paramKey);
out.println("<tr><td>Param " + paramKey + "</td>"
+ "<td><input type='text' name='" + paramKey
+ "' value='" + paramValue + "'/></td>"
+ "<td><input type='submit' value='submit'/></td></tr>");
}
out.println("</table>");
com.devworks.pluto.gbeans.GBeanManager.stopAndUnloadGBean(
com.devworks.pluto.gbeans.ConfigServiceGBean.class);
}
else
{
out.println("Unable to find ConfigServiceGBean<br/>");
}
}
catch(Exception e)
{
e.printStackTrace(System.out);
out.println("<br/>Exception: " + e);
}
%>
|
You can access information managed by other services, such as the portlet
definition registry service or portlet entity registry service, using the same
techniques to wrap each component as a GBean. These GBeans can then be loaded and
started by the kernel and referenced by administration components, such as JSPs or
servlets. (See the Resources section for the source code
demonstrating these concepts.)
Configure users and roles
Security role references (represented by
org.apache.pluto.om.common.SecurityRoleRef instances)
determine whether a user is mapped to a specified role for each portlet request.
Standard Java 2 Platform, Enterprise Edition (J2EE) and Java EE security measures
are taken to determine the rights given to an authenticated user in the context of a
particular portlet by applying the security information configured within the set
of security role references stored within each portlet definition.
The portlet entity registry service GBean is used to retrieve and modify
security role references for a given portlet definition. As with the
ConfigService GBean, a static
GBeanInfo object is created and made available in a
static getGBeanInfo method, as shown in Listing 5.
Listing 5. GBeanInfo for the portlet entity registry service GBean
public class PortletEntityRegistryServiceGBean
implements GBeanLifecycle
{
public static final GBeanInfo GBEAN_INFO;
static
{
GBeanInfoBuilder infoBuilder =
new GBeanInfoBuilder("PortletEntityRegistryServiceGBean",
PortletEntityRegistryServiceGBean.class);
infoBuilder.addOperation("getPortletEntityKeys");
infoBuilder.addOperation("getPortletEntityID",
new Class[] { String.class });
infoBuilder.addOperation("getPortletEntityWindowList",
new Class[] { String.class });
infoBuilder.addOperation("getPortletEntityDefName",
new Class[] { String.class });
infoBuilder.addOperation("getPortletEntityDefAppID",
new Class[] { String.class });
infoBuilder.addOperation("getPortletEntityDefAppContext",
new Class[] { String.class });
infoBuilder.addOperation("getSecurityRoleRefs",
new Class[] { String.class });
infoBuilder.addOperation("setSecurityRoleRefs",
new Class[] { String.class,
org.apache.pluto.om.common.SecurityRoleRefSet.class });
GBEAN_INFO = infoBuilder.getBeanInfo();
}
public static GBeanInfo getGBeanInfo()
{
return GBEAN_INFO;
}
|
Each operation defined by the GBeanInfo object is
implemented using an instance of the object stored in the
org.apache.pluto.portalImpl.services.ServiceManager
class and retrieved using the getService method of the
ServiceManager class. In a manner similar to the
ConfigService GBean, a reference to the
org.apache.pluto.portalImpl.services.portletentityregistry.PortletEntityRegistryService class
must be passed as a parameter to the getService method
of the ServiceManager class to retrieve an instance of
the PortletEntityRegistryService component.
With an instance of the
PortletEntityRegistryService component available and
exposed as a standard Geronimo GBean, security role information for a portlet can be made available to the Pluto admin environment, as illustrated by
the GBean methods in Listing 6.
Listing 6. Security role information presented by the portlet entity registry service GBean
public org.apache.pluto.om.common.SecurityRoleRefSet
getSecurityRoleRefs(String entityKey)
{
org.apache.pluto.portalImpl.om.portlet.impl.PortletDefinitionImpl
portletDefinitionImpl = getPortletDefImpl(entityKey);
if (portletDefinitionImpl == null)
{
return null;
}
return portletDefinitionImpl.getCastorInitSecurityRoleRefs();
}
public void setSecurityRoleRefs(String entityKey,
org.apache.pluto.om.common.SecurityRoleRefSet securityRoleRefSet)
{
org.apache.pluto.portalImpl.om.portlet.impl.PortletDefinitionImpl
portletDefinitionImpl = getPortletDefImpl(entityKey);
if (portletDefinitionImpl == null)
{
return;
}
portletDefinitionImpl.setCastorInitSecurityRoleRefs(securityRoleRefSet);
}
|
When you wrap the desired services as GBeans and make them available to the
kernel, you can use them to monitor and manage portal applications, as covered in
the next section.
Monitor and manage portal applications
To use the GBeans described previously, you must use them in the same context as
the Web console application. You do so by adding JSPs, servlets, and/or Java
classes to the Web console CAR file. For the Jetty Web console, you can find the
CAR file in
the Geronimo repository at Geronimo/webconsole-jetty/1.1.1/car directory. The Web
application for the Web console is in a .war file named framework.war, which is a
child of the CAR directory.
To add Pluto administration functionality to Geronimo using the GBeans defined earlier, create a new subdirectory of framework.war, called plutoadmin. In the plutoadmin
directory, place the JSPs found in the sample code (see the
Downloads section). These JSPs provide the
GBeanManager class to access the GBeans.
After you've populated the plutoadmin directory with the desired JSPs and other
Web resources (and each time a modification is made to the plutoadmin resources),
you must restart the Web console CAR file using the Geronimo deployer utility, as shown
in Listing 7.
Listing 7. Command line for restarting the
Web console CAR file
C:\<GERONIMO_HOME>\bin>deploy --user system --password manager restart \
geronimo/webconsole-jetty/1.1.1/car
|
The result of this command line is shown in Listing 8.
Listing 8. Results of restarting the Web
console CAR file
Restarted geronimo/webconsole-jetty/1.1.1/car
`-> standard.war
`-> framework.war
|
Now point a Web browser to http://localhost:8080/console/plutoadmin/ to access
the Pluto management pages. Links are provided for each of the primary services
described in this article. You can investigate each link and the GBean associated
with each.
Conclusion
Apache Geronimo uses Apache Pluto as the portal environment for its management console. Using
Geronimo's managed-bean framework, Pluto services can be wrapped and presented to
components and services to allow a flexible and powerful environment for managing
Pluto components and services.
Download | Description | Name | Size | Download method |
|---|
| Sample code for this article | os-ag-geronpluto.zip | 104KB | HTTP |
|---|
Resources Learn
Get products and technologies
Discuss
About the author  | 
|  | Jeff Hanson has more than 20 years of experience in the software industry,
including working as senior engineer for the Microsoft Windows port of the OpenDoc
project, lead architect for the Route 66 framework at Novell, and chief architect
for eReinsure.com, Inc., where he directed design and implementation of frameworks
and platforms for J2EE-based reinsurance systems. Jeff is currently the CTO for
Max Software, Inc., where he directs efforts to provide desktop and enterprise
applications and platforms for Internet safety and parental controls. Jeff is the
author of numerous articles and books, including .NET versus J2EE Web Services:
A Comparison of Approaches, Pro JMX: Java Management Extensions, and
Web Services Business Strategies and Architectures. |
Rate this page
|