In the first article in this Hello World series, you saw how to create a portlet in Java that spits out "hello, world". While this is instructive, it is not a pragmatic approach to developing portlets. So, what is wrong with it? Solving one of the problems is the subject of this second article.
In the simplest "Hello World!" program, the Java code contains both the text "hello, world" and the logic for displaying it. It would be far better if you could separate the logic of the portlet from how it gets rendered, which would let you create portlets that support different meta languages and national languages. Today, you might not have a requirement to create a portlet for Wireless Markup Language (WML) or in the German language. But what about tomorrow?
You could also be working with a graphic designer who frequently changes the look and feel. If rendering is done in Java code, it takes a developer and a recompilation to change it. The solution is to render your portlet with JSP, which lets you create separate JSP files for each supported meta or national language. The designer can have full control over the JSP and change it without ever needing a developer.
In this article, you first see what it takes to build a portlet that calls a JSP for rendering in for IBM® WebSphere® Portal Version 5. Then, you look at the JSP and a few of the tags from the portlet tag library. Finally, you create deployment descriptors, package everything together, and deploy it into the portal.
Creating the directory structure
To start off, you must create a directory structure in which you store your portlet. Here's what you use for this portlet:
-
helloWorld\com\ibm\portlets\sample- where your source will go. -
helloWorld\WEB-INF- where the deployment descriptor is stored. -
helloWorld\WEB-INF\lib- where the JAR file will go. -
helloWorld\jsp- where the JSP files are stored.
Important: All directory and environment references are based on Windows convention. You need to adjust these accordingly for Unix systems.
The sample directory is where you put
our Java source file. Create a file named HelloWorld.java
in the sample directory and open it in your favorite text
editor. Here's the class that you need to type (or cut and
paste) into the HelloWorld.java file:
package com.ibm.portlets.sample;
//portlet APIs
import org.apache.jetspeed.portlet.*;
//Java stuff
import java.io.*;
public class HelloWorld extends PortletAdapter {
public void service(PortletRequest request, PortletResponse response)
throws PortletException, IOException {
// Include the view jsp
getPortletConfig().getContext().include( "/jsp/view.jsp",
request, response);
}
}
|
After you have created the source file, you are
ready to compile the Java code. You can use the script below
in a batch file to compile the portlet. Start by defining
some environment variables, such as environment variables that
define where the Java is installed (JAVA_HOME). It's
usually a good idea to compile this using the JDK provided with
the WebSphere Application Server, since that is the environment
in which you will run the application.
You also need to set the PATH environment
variable to include the location where the Java compiler is
installed. Set the variable LIBPATH that will
point to the directory where the WebSphere JAR files are found.
Next, set a variable called CP for our compilation classpath. The CP
variable could be built on a single line, but the listing below breakes it up to
show the various JAR files required. You then invoke the Java
compiler and compile our code. The code assumes you are in the helloWorld
directory. Adjust your directory paths as appropriate
for your installation.
set JAVA_HOME=C:\WebSphere\AppServer\java set PATH=%JAVA_HOME%\bin set LIBPATH=C:\WebSphere\AppServer\lib set CP=. set CP=%CP%;%LIBPATH%\j2ee.jar set CP=%CP%;%LIBPATH%\dynacache.jar set CP=%CP%;C:\WebSphere\PortalServer\shared\app\portlet-api.jar javac -classpath %CP% com\ibm\portlets\sample\HelloWorld.java |
If this doesn't compile, you must fix the errors before moving on. Some common errors are:
- Typos - mistyped class names, paths, variable names.
- File name - the file name and the class name must match in
our case the file name is
HelloWorld.java.and the class name itHelloWorld. If you have changed one, change the other. - Editor woes - make sure your editor really saves the file as text. An editor like WordPad does not save as text by default.
After the Java source is compiled, you need to
create a JAR file in the WEB-INF\lib directory.
Again, the code assumes you are in the helloWorld directory. These
statements could be included as part of the batch file you
created above. It relies on having the PATH set to get to the
jar program.
set JAVA_HOME=C:\WebSphere\AppServer\java set PATH=%JAVA_HOME%\bin jar -cv0f .\WEB-INF\lib\HelloWorldFromJSP.jar com/ibm/portlets/sample/*.class |
After the Java source is compiled and the JAR
file is created, you can turn your attention to the JSP file. The
JSP directory is where you put the JSP source file. Create a
file named view.jsp in the JSP directory and open
it in your favorite text editor. Here's the JSP code that you
need to type (or cut and paste) into the view.jsp
file:
Hello world from the JSP! |
This is simple enough. Now, you can get this packaged up and running! You cancome back to the JSP afterwards, to see what more you can do to add support for different national and meta languages.
Creating the deployment descriptors
You will need to create two XML files:
-
helloWorld\WEB-INF\web.xml- the web deployment descriptor. -
helloWorld\WEB-INF\portlet.xml- the portlet deployment descriptor.
web.xml - the web deployment descriptor
The web deployment descriptor is needed for WebSphere Portal. Portlets extend Servlets now, so the web deployment descriptor is needed to declare the Servlet (portlet) class.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web
Application 2.3//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_3.dtd">
<web-app id= "HelloWorldFromJSPWebApp">
<display-name>HelloWorldFromJSPPortlet</display-name>
<servlet id="Servlet_1">
<servlet-name>HelloWorldFromJSP</servlet-name>
<servlet-class>com.ibm.portlets.sample.HelloWorld</servlet-class>
</servlet>
<servlet-mapping id="ServletMapping_1">
<servlet-name>HelloWorldFromJSP</servlet-name>
<url-pattern>/HelloWorldFromJSP/*</url-pattern>
</servlet-mapping>
</web-app>
|
portlet.xml - the portlet deployment descriptor.
The portlet deployment descriptor defines the portlet to the portal. Each portlet is mapped to a Servlet defined in the web deployment descriptor by way of the href attribute on the portlet element. These references are shown below in bold. A portlet must define a unique id that each concrete portlet can reference. Each concrete portlet references a portlet using the given id in the href attribute of the concrete-portlet element. These references are shown below in blue.
<?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 uid="com.ibm.portlets.sample.HelloWorldFromJSP.1" major-version="1"
minor-version="0">
<portlet-app-name>HelloWorldFromJSP0Portlet</portlet-app-name>
<portlet href="WEB-INF/web.xml#Servlet_1" id="Portlet_1" major-version="1"
minor-version="0">
<portlet-name>HelloWorldFromJSP</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 uid="com.ibm.portlets.sample.HelloWorldFromJSP.1.2">
<portlet-app-name>Concrete HelloWorldFromJSP</portlet-app-name>
<context-param>
<param-name>Author</param-name>
<param-value>tcat@us.ibm.com</param-value>
</context-param>
<concrete-portlet href="#Portlet_1">
<portlet-name>HelloWorldFromJSP</portlet-name>
<default-locale>en</default-locale>
<language locale="en">
<title>Hello World from JSP</title>
</language>
</concrete-portlet>
</concrete-portlet-app>
</portlet-app-def>
|
Many things can go wrong when creating these XML files, and you might not find out until you attempt to deploy the portlet into the portal. Here are some things to double check.
- Verify that for every XML element you have a closing element.
- Check for mistyped class names, especially for this
example if you named your class something other than
HelloWorldFromJSP - Make sure your id and href attributes match.
- Make sure your editor really saves the file as text.
Finally, you are ready to create the WAR file
for distribution. You use the standard jar
command to build the WAR file. Run this from the helloWorld
directory.
set JAVA_HOME=C:\WebSphere\AppServer\java set PATH=%JAVA_HOME%\bin jar -cf HelloWorldFromJSP.war WEB-INF jsp |
- Login to the portal as the portal administrator (
wpsadmin). - Select the Administration link in the upper right hand corner of the default theme.
Figure 1. The administration link
- Select the Portlets page on the left and the Install
portlet.
Figure 2. Install portlets administration page
- Click
. - Find the location of WAR file, select it, and click
.
Figure 3. File selection dialog
- Click
. This could
take some time, so wait for it to finish. - Verify Portlet is HelloWorld. Click
. Again, wait
for it to complete.
Figure 4. Portlet install verification screen
- Finally, you should see this confirmation:
.
If you get some sort of error during
deployment, this usually means that you made a mistake in one
of your XML files. Take a look at the error messages you are presented with on the install
page. You can usually figure out the problem from there. These messages are also in the
latest log file:
%WPS_HOME%/log/wps_YYYY.MM.DD-HH.MM.SS.log
Some common mistakes made with the XML files are listed above. You might also check the following:
- The XML declaration must be first line in file (no whitespace).
- The xml files have the correct names, in the correct case.
- Select Portal User Interface page on the left.
- Click the Manage Pages portlet.
Figure 5. Manage pages portlet
- Then select the My Portal page.
- Click
. - Enter a title for the new page.
- Click
. - Click
when you see
. - Click the edit page icon,
,
next to your new page. - Click
. - Search for:
Hello, click
. - Select the Hello World portlet and click
.
Figure 6. Search for portlets
- Click
to finish the page layout.
Figure 7. Edit layout
- Click the My Portal link in the upper right and then select the page that you created.
Figure 8. Portal displaying our portlet
I18N and multiple meta languages
I18N is the common abbreviation for internationalization, a term which refers to designing an application, (your portlet), in such a way that it can be adapted to different languages and regions without code changes. With your current implementation, you have no way to support multiple national languages or multiple meta languages. Portlets that use JSP for rendering are given two types of support for I18N, one of which also helps with multiple meta languages.
This first support is for multiple JSPs to render your portlet. This support allows a portet to have a different layout, colors, images, text, and other presentation specifics for each supported language, region, and meta language.
The directory structure for your JSP
is \jsp\view.jsp. The portal uses
this directory as a base to search for a best fit JSP. Here is
the order which will be searched by a Web browser set to
the US english locale:
\jsp\html\en_US\view.jsp \jsp\html\en\view.jsp \jsp\html\view.jsp \jsp\view.jsp |
The first view.jsp found is
used for rendering the portlet. This convention allows you to specify
different JSPs for different national languages. For example, you
could have a view.jsp in the \jsp\html\de\
directory. It would read, "Hallo Welt" (which I hope
is "Hello World" in German). The general idea is that
each language and region could have its own JSP providing
specialized layout and verbage. What about different meta
languages? You can see from the search path above that \html\
is specified. You could have JSPs for the portlet in the
following paths:
\jsp\html\en_US\view.jsp \jsp\html\en\view.jsp \jsp\html\de\view.jsp \jsp\html\view.jsp \jsp\wml\en_US\view.jsp \jsp\wml\en\view.jsp \jsp\wml\de\view.jsp \jsp\wml\view.jsp \jsp\view.jsp |
Having different JSPs would let your portlet users come in from a WML
browser, and the portlet would use the JSPs in the \wml\
directory structure for searching.So, that is the first level of support for
I18N.
The second level of help is in the form of Java resource bundles. For the purposes of your portlet, Java resouce bundles give the ability to put strings into properties files that are easily translated, separately from the JSP code. You can have the same layout, but have the text in the correct national language. To do this in WebSphere Portal V5, you need to delve into the world of JSTL, the JSP Standard Tab Library. Previously, you would use the IBM portlet tag library provided with WebSphere Portal to access resource bundles from a JSP. You can still do that in V5, but the text tag is deprecated and the vision for the future is JSTL.
An introduction to JSTL for I18N
JSTL provides JSP tags for a variety of functions. In fact JSTL is actually four different tag libraries.
- The core tag library -- which provides an expression language and common control flow tags. Such as and if and looping tags.
- The formatting tag library -- which provides I18N features such as message retrieval from resource bundles, date, time, and other formatting tags.
- The database access tag library -- allow you to access your database directly from you JSP.
- The XML tag library -- various XML tags that allow you to parse and transform XML documents.
I have found that the database and the XML portions of JSTL have a tendency to conflict with other libraries in WebSphere Portal. As an example, when I included the database tag library in a portlet which used a DB2 datasource, I ended up with class conflicts and could no longer access my database. Likewise when I included the XML tag library in a portlet, I found that my JSPs were no longer able to compile.
This little problem only reared its head in WebSphere Portal V5.0.2. I finally figured out it was the JSTL XML tag library that was conflicting. So my suggestion to you is to pare down JSTL to just the formatting and core tag libraries until you feel you have a good handle on which JAR files you actually need.
Speaking of JAR files, you can download the JSTL libraries from Standard tag lib or start at Standard tag lib introduction and find your own mirror site for downloading. This article is illustrating Version 1.0.
When you unzip the downloaded libraries, you find several
directories that have been created. The two you are most interested
in, to start, are the lib and the tld directories. You need to copy two JAR files
from the lib directory to your WEB-INF/lib directory.
They are jstl.jar and standard.jar. All the other libraries are
not needed for the purpose of this exercies and interfere with the execution of your
portlet, as discussed above.
You need to create a WEB-INF/tld
directory as well. Copy c.tld, c-rt.tld, fmt.tld, and fmt-rt.tld
from
the tld
directory to your WEB-INF/tld
directory. These files define
the core (c) tag library and the formatting (fmt) tag libraries.
You are probably wondering about now why you need two
different tld
files. JSTL has a concept of "twin
libraries" and it is really beyond the scope of this article.
The bottom line is that one allows the use of the JSTL expression language
and the other allows one to use JSP expressions.
Yes yes yes, you with the JSTL tattoo and the twisted expression in the back there. Before you whip out your Blackberry and nasty gram me about not doing JSTL justice, I know I am breezing over JSTL, and I encourage you to write an article of you own on JSTL. But you gentle reader, you really should go read about JSTL from a better source than I. Google for it and search in your favorite online bookstore. You'll find plenty of resource, but remember JSTL 1.0!
You got most of the preliminary work done to use JSTL in your
portlets to access resource bundles. You must modify the web.xml
file to declare the tag libraries you are going to use. Take a
look at the taglib tags after the servlet-mapping tags.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web
Application 2.3//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_3.dtd">
<web-app id= "HelloWorldFromJSPWebApp">
<display-name>HelloWorldFromJSPPortlet</display-name>
<servlet id="Servlet_1">
<servlet-name>HelloWorldFromJSP</servlet-name>
<servlet-class>com.ibm.portlets.sample.HelloWorld</servlet-class>
</servlet>
<servlet-mapping id="ServletMapping_1">
<servlet-name>HelloWorldFromJSP</servlet-name>
<url-pattern>/HelloWorldFromJSP/*</url-pattern>
</servlet-mapping>
<taglib id="TagLibRev_JSTL_fmt">
<taglib-uri>http://java.sun.com/jstl/fmt</taglib-uri>
<taglib-location>/WEB-INF/tld/fmt.tld</taglib-location>
</taglib>
<taglib id="TagLibRev_JSTL_fmt_rt">
<taglib-uri>http://java.sun.com/jstl/fmt_rt</taglib-uri>
<taglib-location>/WEB-INF/tld/fmt-rt.tld</taglib-location>
</taglib>
<taglib id="TagLibRev_JSTL_core">
<taglib-uri>http://java.sun.com/jstl/core</taglib-uri>
<taglib-location>/WEB-INF/tld/c.tld</taglib-location>
</taglib>
<taglib id="TagLibRev_JSTL_core_rt">
<taglib-uri>http://java.sun.com/jstl/core_rt</taglib-uri>
<taglib-location>/WEB-INF/tld/c-rt.tld</taglib-location>
</taglib>
</web-app>
|
You have defined all the libraries that you are likely to use. You will not use them all in this article, but I do not think it will do any harm to define them all. Not only that, if I show you here how to define them all, you will not need to guess for your portlets!
Now you get to the actual JSP code. To utilize the JSTL formatting tag library, the following directive is required at the beginning of the JSP to give access to the formatting library:
<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>
|
You can use similar directives to utilize the core library. Now you use the formatting library to retrieve a message from a resource bundle.
<fmt:setBundle basename="nls.labels"/>
<fmt:message key="helloWorldLabel"/>
|
This attempts to get the "helloWorldLabel" from the labels properties file. If no suitable properties file is found, then the default is to render what is between the opening and closing text tag, in our case, "Hello world from the JSP!". The properties files are searched in the same fashion as standard ResourceBundles are searched in Java:
<basename>_<lang>_<country>_<variant> <basename>_<lang>_<country> <basename>_<lang> <basename> |
For this exercise, you create a couple of properties files:
/WEB-INF/classes/nls/labels_en.properties /WEB-INF/classes/nls/labels_de.properties |
They will have the following content:
/WEB-INF/classes/nls/labels_en.properties: helloWorldLabel=Hello World! /WEB-INF/classes/nls/labels_de.properties: helloWorldLabel=Hallo Welt! |
To sum up, the JSP file, /jsp/view.jsp,
has the following content:
<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>
<fmt:setBundle basename="nls.labels"/>
<fmt:message key="helloWorldLabel"/>
|
This file, along with the two properties files, produces the following, when the language is set to English in an HTML browser:
Figure 9. Hello World portlet in English
Then when our language is set to German in our html browser, the portlet will produce:
Figure 10. Hello World portlet in German
Pretty nifty. Ah, but you ask, how do I update the portlet that you already deployed into the portal? One could just delete the portlet and redeploy. But in a real portal environment, you would lose user data and deployment information. The last section of this article will briefly cover how to update a deployed portlet.
- Login to the portal as the portal administrator, (
wpsadmin. - Select the Administration link in the upper right hand corner of the default theme.
Figure 1. The administration link
- Select the Portlets page on the left and the Install portlet.
- Select the Manage Applications portlet
Figure 11. Manage portlets screen
- In the Web Modules list box, select the HelloWorldFromJSP.war entry.
- Click the
button. - Click the
button. - Find the location of WAR file, select it, and click
. - Click
,
this could take some time, so wait for it. - Verify Portlet is HelloWorldFromJSP, click
, again wait
for it to complete. - Finally you should see confirmation that says,
There it is. That's how you render your portlet using a JSP. If you worked along with this article, you wrote, compiled, and packaged Java code for a portlet. You created the deployment descriptors and packaged the portlet for distribution and deployment. You then deployed the portlet into your portal. Finally, you rewrote the JSP, internationalized, and updated the deployed portlet. In the course of portlet development you'll do this time and again. Good luck and happy hacking!





