Create a simple portlet
To create a simple portlet...
- Write the portlet code
- Compile Java source
- Create the JAR file
- Write the portlet descriptors
- Set up the WAR file directory structure
- Package and deploy the portlets
Configure RAD or RSA with a test environment, used to run and debug the portlets without having to manually deploy them to the server. We can set up the run time environment for debugging portlets on the local development machine or on a remote server. RAD and RSA provide wizards to help build, test, and deploy portlets using all of the APIs, and related classes and interfaces, available in the portlet run time environment.
HelloWorld portlet
The Hello World portlet is provided, along with source, in the IBM Portlet Samples package, available from the portlet catalog by searching for navcode 1WP10017Z. Hello World provides the fewest methods required for a portlet, using the portlet response object to write simple output directly to the portal page.
package com.ibm.wps.samples.jsr; import javax.portlet.*; import java.io.*; public class HelloWorld extends GenericPortlet { public void init (PortletConfig portletConfig) throws UnavailableException, PortletException { super.init(portletConfig); } public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException { // set return content type response.setContentType("text/html"); PrintWriter writer = response.getWriter(); writer.println("<p class='wpsPortletText'>Hello Portal World!</p>"); } }
API element IBM portlet API Java Portlet Specification import statements org.apache.jetspeed.portlet javax.portlet Portlet class PortletAdapter GenericPortlet, which also can throw a PortletException Request object PortletRequest RenderRequest Response object PortletResponse RenderResponse Also, notice the content type must be set in the response.
Compiling Java source
First set the class path for the compiler to find the JAR files for any portlet packages the portlet uses...
. ./setupcmdLine.sh
The following JAR files must be set in the class path to compile portlets:
- Standard portlets
JAR file Purpose portletapi_20.jar Complies with Java Portlet Specification v2.0. public_api.jar Use services from the Public API Javadoc package. public_api.jar + public_spi.jar Use services from the Public SP Javadoc package. These files are in the directory...
PORTAL_HOME/doc/compile
- IBM portlets
JAR file Purpose wp.pe.api.legacy.jar IBM portlet API wp.portletservices.api.legacy.jar Portlet services wp.pe.rt.api.jar Portlet menus
Compile the portlet using the fully qualified path to the Java portlet source.
cd WAS_HOME/java/bin
javac -classpath %WAS_CLASSPATH%;path_to\portletapi_20.jar com.ibm.wps.samples.jsr.HelloWorld.java
javac -classpath %WAS_CLASSPATH%;path_to\portletapi_20.jar com.ibm.wps.samples.v4.HelloWorld.java
- Loading classes for portlets
Class loading follows the WAS hierarchy for class paths and search orders. We can reference a class if the parent class loader can reference it, or our own class loader can reference it. We cannot reference a class if a child class loader references it. The graphic illustrates where HCL WebSphere Portal and portlet applications fit into the class loading hierarchy.
In the following graphic runtime class path patches (RCP) are at the beginning of the hierarchy. Runtime class path (RP) branches from runtime class path patches. Runtime extensions (RE) branches from runtime class path, and application extensions (AEX) branch from runtime extensions. Application class loaders (AC1), application class loaders (AC2), and application class loaders (AC3) are portlet applications that branch from application extensions.
As illustrated, HCL WebSphere Portal is an application extension (AEX) in WebSphere Application Server. The HCL WebSphere Portal core classes are in the class path PORTAL_HOME/shared/app. If an installed portlet application includes a class loader, the portlet application class loader is an application class loader (ACx) in HCL WebSphere Portal.
If we suspect a classloading problem, ensure the required classes are in the appropriate class path according to the classloading hierarchy.
Create the JAR file
Next, the portlet must be packaged in the JAR file format...
jar -cf HelloWorld.jar HelloWorld.class
Writing the portlet descriptors
The following samples can be packaged with the Hello World portlet.
- Web application deployment descriptor (web.xml) for standard portlets:
According to the Java Portlet Specification, only web resources that are not portlets must be declared in the web.xml. However, the following properties must be set to correspond to the portlet descriptor:
<description/> Describes the portlet application. <display-name/> Portlet application name. <security-role/> Portlet application security role mapping. Optional. Web application deployment descriptor (web.xml) for Hello World (standard portlets)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app > <display-name>Hello World (JSR)</display-name> <description>Basic JSR 168 portlet</description> </web-app>
If we are familiar with the web.xml for IBM portlets, the key difference is the required <servlet/> element in the web.xml for IBM portlets.
- Standard portlet deployment descriptor (portlet.xml):
Minimum elements required for the standard portlet deployment descriptor (portlet.xml).
Example: Portlet deployment descriptor (portlet.xml) for Hello World (standard)
<?xml version="1.0" encoding="UTF-8"?> <portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"> <portlet> <portlet-name>HelloWorld portlet name</portlet-name> <display-name>Hello World portlet (JSR)</display-name> <display-name xml:lang="en">Hello World portlet (JSR)</display-name> <portlet-class>com.ibm.wps.samples.jsr.jsrHelloWorld</portlet-class> <supports> <mime-type>text/html</mime-type> <portlet-mode>view</portlet-mode> </supports> <supported-locale>en</supported-locale> <portlet-info> <title>Hello World (JSR)</title> </portlet-info> </portlet> </portlet-app>
The standard portlet descriptor is defined by an XML schema and does not require a DTD.
. Set up the WAR file directory structure
Before you package the portlet, the class files and resources must be arranged in the WAR file directory structure described here. A portlet application exists as a structured hierarchy of directories.
Do not package .tld files for tag libraries provided by the portal or application server installation with the portlet application WAR file. This includes the IBM portlet API tags, JSR 168 and 286 portlet tags and the Java Standard Tag Library (JSTL).
- /
- The root directory of the portlet file structure.
- /images
- Location for any images the required by the portlet.
- /WEB-INF
- Location for all protected resources. The /WEB-INF directory stores the portlet descriptor document and all of the run time executable JAR files and classes the packaged portlet requires. The portlet information directory is not part of the public document tree of the application. Files in /WEB-INF are not served directly to a client.
- /WEB-INF/lib
- Location for storing portlet JAR files.
- /WEB-INF/jsp
- Location for JSP files. Suggested path name. Your JSPs can be packaged in any location. JSPs included inside the portlet markup must be placed under the /WEB-INF directory. Place them outside the /WEB-INF directory if we create direct links to them.
- /WEB-INF/classes
- Location for portlet class files. Individual class file must be stored in a directory structure within /WEB-INF/classes that reflects the class package. For example, the class HelloWorld.class, in package com.ibm.wps.samples, would be stored in...
/WEB-INF/classes/com/ibm/wps/samples/HelloWorld.class
- /META-INF
- Location for the manifest file, manifest.mf, and the Java 2 security file, was.policy (if present). The manifest is in the standard JAR file format as defined by the Java 1.3 specification. The Java 2 security policy file is used to allow a portlet to execute operations that might be restricted if Java 2 security is enabled. The contents of the /META-INF directory is not served to clients.
The application server searches for security policy files in the location of the enterprise application archive rather than the web application archive. Therefore, the portal server copies was.policy from the directory...
appname.war/META-INF
...to the generated directory...
appname.ear/META-INF
...during deployment of a portlet WAR file.
Packaging and deploying portlets
To deploy a portlet and run it on the server, it must be packaged in the form of a Web application archive (WAR) file, containing the Java classes and resources that make up one or more portlets in a portlet application. The resources can be images, JSP files, Writing the portlet descriptors, and property files containing translated message text. Packaging portlet classes, resources, and descriptive information in a single file makes distribution and deployment of portlets easier.
HCL WebSphere Portal includes an administrative portlet for installing, uninstalling, and updating portlets. Portlets contained in WAR files have the advantage of being dynamically downloaded and installed. The portal administrator can download a WAR file from the Internet and then use the portal administration interface to install the portlet to HCL WebSphere Portal. After installation, the portlet is ready for use and does not require the server to be restarted. Use the JAR file utility to package the portlet into a WAR file.
Because Windows limits the maximum path length to 260 characters, the name of the WAR file must be fewer than 25 characters. On a portal server running on Windows, installing a WAR file with a name that is more than 25 characters results in an error.
We can also run the build-war-file or build-ear-file tasks to build the .war and .ear files.
- Packaging a portlet and resources into a WAR file
Examples of how to use the JAR file utility provided by WebSphere Application Server...
- Create a WAR file with the name HelloWorld.war, and include all of the files in the /WEB-INF and /images directories:
jar -cf HelloWorld.war images WEB-INF
- Update an existing WAR file, HelloWorld.war with a revised portlet descriptor:
jar -uf HelloWorld.war WEB-INF/portlet.xml
- Extract the portlet descriptor from the WAR file, HelloWorld.war:
jar -xf HelloWorld.war WEB-INF/portlet.xml
- Extract all files from an existing WAR file, HelloWorld.war:
jar -xf HelloWorld.war
After the WAR file is created, it can be installed to HCL WebSphere Portal
- Prepare the portlet application for installation
To facilitate deployment of portlet applications and complex portlets, we can provide a portlet configuration file that can be invoked by xmlaccess.sh. This allows the portlet developer to specify places, pages, themes, skins, supported markups and clients, and other settings for a portlet application. This is especially useful for portlets that use messaging because these portlets must be placed on the same page.
xmlaccess.sh values for standard portlets...
- uid attribute for the <web-app> element:
Use the uid attribute of the <portlet-app/> subelement with a .webmod suffix. The uid attribute of the <portlet-app/> subelement is dependent on the presence of the id attribute of the <portlet-app/> element from the portlet.xml.
- uid attribute for the <portlet-app> element:
Use the id attribute of the <portlet-app/> element from the portlet.xml. If this value has not been specified, specify the WAR file name of the portlet application in its place. For portlet updates, the WAR file name must be the original name of the WAR file used to install the portlet application. That is, the WAR file name can be changed, but the uid must indicate the original uid used during portlet installation.
- name attribute for the <portlet> element:
Use the content of the <portlet-name/> element from the portlet.xml.
- referenceid attribute of the <servlet> element:
Use the content of the <portlet-name/> element from the portlet.xml appended with the .servlet suffix.
For example, a portlet application might use a portlet descriptor as follows:
Example <portlet-app/> element in portlet descriptor
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd" version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"> <portlet> <portlet-name>Banner Ad</portlet-name> ...
In this example, there is no id attribute provided on the <portlet-app/> element. Therefore, the <portlet-app/> element of the xmlaccess script would use the WAR file name, as follows:
Example <web-app/> element in xmlaccess
<web-app action="update" active="true" u> <url>file:///$server_root$/bp/wp.bp.that isad/installableApps/that isad.war</url> <servlet action="update" active="true" reference/> <portlet-app action="update" active="true" u> <portlet action="update" active="true" name="Banner Ad"> </portlet-app> </web-app>
IBM portlet API examples for Hello World
Example: Java source for Hello World portlet (IBM)
package com.ibm.wps.samples.v4; import org.apache.jetspeed.portlet.*; import java.io.*; public class HelloWorld extends PortletAdapter { public void init (PortletConfig portletConfig) throws UnavailableException { super.init(portletConfig); } public void doView(PortletRequest request, PortletResponse response) throws PortletException, IOException { PrintWriter writer = response.getWriter(); writer.println("<p class='wpsPortletText'>Hello Portal World!</p>"); } }
Example: Web application deployment descriptor (IBM)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app > <display-name>HelloWorld</display-name> <servlet > <servlet-name>HelloWorld</servlet-name> <servlet-class>com.ibm.wps.samples.v4.HelloWorld</servlet-class> </servlet> <servlet-mapping > <servlet-name>HelloWorld</servlet-name> <url-pattern>/HelloWorld/*</url-pattern> </servlet-mapping> </web-app>
As described in Deployment descriptors, the href attribute of the <portlet/> element references the servlet ID from web deployment descriptor.
The portlet deployment descriptor (portlet.xml) references the portlet_1.1.dtd, which portal server finds in...
PORTAL_HOME/installer/wp.ear/installableApps/wps.ear/wps.war/dtd
Do not package the DTD with the portlet application WAR file.
Example: Portlet deployment descriptor (IBM)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE portlet-app-def PUBLIC "-//IBM//DTD Portlet Application 1.1//EN" "portlet_1.1.dtd"> <portlet-app-def> <portlet-app u major-version="1" minor-version="0"> <portlet-app-name>HelloWorld application</portlet-app-name> <portlet href="WEB-INF/web.xml#com.ibm.wps.samples.HelloWorld.a0ae41f2d3c1001710b7b313e1a97" major-version="1" minor-version="0"> <portlet-name>HelloWorld portlet</portlet-name> <cache> <expires>0</expires> <shared>NO</shared> </cache> <allows> <maximized/> <minimized/> </allows> <supports> <markup name="html"> <view/> </markup> </supports> </portlet> </portlet-app> <concrete-portlet-app u> <portlet-app-name>HelloWorld application</portlet-app-name> <concrete-portlet href="#com.ibm.wps.samples.HelloWorld"> <portlet-name>HelloWorld portlet</portlet-name> <default-locale>en</default-locale> <language locale="en"> <title>HelloWorld portlet</title> <title-short></title-short> <description></description> <keywords></keywords> </language> </concrete-portlet> </concrete-portlet-app> </portlet-app-def>
Parent Portlet creation basicsRelated tasks:
HCL WebSphere Portal Zone
Build .ear and .war files