In this article, we'll back away from the main MetroSphere application in favor of a no-nonsense look at exactly what all of those items in the web.xml and portlet.xml files really mean. To follow along, you'll need a text editor for looking at and editing these files, as well as a Java compiler for compiling the sample class and as a way to create a WAR file. WebSphere Studio Application Developer (Application Developer) is perfect for these tasks. You should also have a basic understanding of what portlets are and how they work.
As you might know, a portlet is a subclass of a servlet, so I'll start by creating the simplest of portlets:
Listing 1. A simple portlet that outputs text
package files;
import org.apache.jetspeed.portlet.*;
public class TestPortlet extends PortletAdapter {
public void init(PortletConfig portletConfig)
throws UnavailableException
{
super.init( portletConfig );
}
public void doView (PortletRequest request, PortletResponse response)
throws PortletException, java.io.IOException
{
response.getWriter().println("Hi!");
}
}
|
In the portlet application, this portlet simply outputs the text.
If you create this servlet in Application Developer by choosing New > Servlet, Application Developer populates the web.xml file with basic information about the class and how it fits into the overall Web application. If you simply created the class, however, this doesn't happen. In either case, it's good to understand what all of the information in the file means. Take a look at the default data generated by Application Developer:
Listing 2. Default data generated by Application Developer
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
<web-app id="WebApp">
<display-name>PortletTest>/display-name>
<servlet id="Servlet_1">
<servlet-name>TestPortlet>/servlet-name>
<display-name>TestPortlet>/display-name>
<servlet-class>files.TestPortlet>/servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TestPortlet>/servlet-name>
<url-pattern>TestPortlet>/url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html>/welcome-file>
<welcome-file>index.htm>/welcome-file>
<welcome-file>index.jsp>/welcome-file>
<welcome-file>default.html>/welcome-file>
<welcome-file>default.htm>/welcome-file>
<welcome-file>default.jsp>/welcome-file>
</welcome-file-list>
</web-app>
|
By default, Application Developer calls the Web application by the name of the project and uses the name of the class for the servlet name, display name, and URL pattern. You don't, however, have to follow this pattern. You could, for example, construct your file like this:
Listing 3. Sample file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
<web-app id="WebApp">
<display-name>PortletTest</display-name>
<servlet id="Servlet_1">
<servlet-name>Servlet-name</servlet-name>
<display-name>Display-name</display-name>
<servlet-class>files.TestPortlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet-name</servlet-name>
<url-pattern>TestPortlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
|
For a portlet application, the name of the Web application is irrelevant; it's not used anywhere. The servlet-name elements for servlet and servlet-mapping must match, because that's how they're related together. (Yes, current practice might lean more toward an id attribute, but that's just the way it is.) The url-pattern technically doesn't have to match the servlet-class, but in practice, it works more reliably for a portlet application.
So, take look at what's been done here. First, a servlet has been defined, providing information on how to identify it internally (through the servlet-name) and for the user (through the display-name), should this Web application be accessed directly in a Web application server such as WebSphere Application Server. A class that serves as the basis for the servlet has also been defined, complete with any package information.
Next, mapping information has been provided that tells the application server what servlet to run based on the URL being accessed. Once the URL is matched to the url-pattern, the servlet-name maps back to the original servlet definition. In this way, the URL is mapped back to the actual class to execute.
Before moving on to the portlet.xml file, I'll cover one more useful function in web.xml -- adding JavaServer Pages (JSP) tag libraries:
Listing 4. Adding JSP tag libraries
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
<web-app id="WebApp">
<display-name>PortletTest</display-name>
<servlet id="Servlet_1">
<servlet-name>Servlet-name</servlet-name>
<display-name>Display-name</display-name>
<servlet-class>files.TestPortlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet-name</servlet-name>
<url-pattern>TestPortlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<taglib>
<taglib-uri>/tld/blogtaglib.tld</taglib-uri>
<taglib-location>/WEB-INF/tld/blogtaglib.tld
</taglib-location>
</taglib>
</web-app>
|
The taglib-uri defines the URL that is listed in the actual taglib tag in a JSP page. It doesn't have to match the actual URL in any way, though here it's similar. The taglib-location is the actual location of the definition file, relative to the current application. This distinction is important. This web.xml file applies only to the PortletTest application. When we made the tag library available to the general portal, we added this information to the overall portal application's web.xml file, where it was relative to that application.
When the servlet has been created and the Web application server has been told about it, the portal application must be told to treat it as a portlet. I'll talk about how to do this in the section discussing the portlet.xml file.
The first step in creating the portlet.xml file is to define the actual portlet application. To do that, you actually need to create the portlet application itself, which is a kind of template, and the concrete portlet application, which gets instantiated:
Listing 5. Creating the portlet application
<?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="Portlet-app_uid">
<portlet-app-name>Portlet-app-name</portlet-app-name>
</portlet-app>
<concrete-portlet-app uid="concrete-portlet-app_uid">
<portlet-app-name>Concrete portlet-app-name</portlet-app-name>
</concrete-portlet-app>
</portlet-app-def>
|
Now, before going any further, acknowledge two facts. First, these are obviously not names that you would put on an actual application. It's not that they don't work -- they do -- but they're certainly not descriptive. Because the whole point of this article is to show you what all of these pieces actually mean, I've intentionally chosen names that are easy to trace back.
Second, notice the two uid values. Notice that they are completely different. The uid for the concrete portlet application does not point back to the actual portlet application, though in practice the concrete portlet application typically mirrors the uid for the original application, with some digit or character appended to it to make it unique.
Before you add any actual portlets, you can add information about the concrete application itself. In the MetroSphere application, we used this capability to provide database connection information, for example. The information is part of the concrete-portlet-app:
Listing 6. Adding concrete application information
<?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="Portlet-app_uid">
<portlet-app-name>Portlet-app-name</portlet-app-name>
</portlet-app>
<concrete-portlet-app uid="concrete-portlet-app_uid">
<portlet-app-name>Concrete portlet-app-name</portlet-app-name>
<context-param>
<param-name>Context-param param-name</param-name>
<param-value>Context-param param-value</param-value>
</context-param>
</concrete-portlet-app>
</portlet-app-def>
|
Later, you'll see how this information interacts with WebSphere Portal's browser-based administration and with the portlet API.
Now that you've created the portlet application, look at how the portlet itself fits in. First, you need to add it to the portlet application:
Listing 7. Adding the portlet to the portlet application
<?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="Portlet-app_uid">
<portlet-app-name>Portlet-app-name</portlet-app-name>
<portlet id="Portlet_1" href="WEB-INF/web.xml#Servlet_1">
<portlet-name>Portlet-name</portlet-name>
<cache>
<expires>0</expires>
<shared>NO</shared>
</cache>
<allows>
<maximized/>
<minimized/>
</allows>
<supports>
<markup name="html">
<view/>
<edit/>
</markup>
</supports>
</portlet>
</portlet-app>
<concrete-portlet-app uid="concrete-portlet-app_uid">
<portlet-app-name>Concrete portlet-app-name</portlet-app-name>
<context-param>
<param-name>Context-param param-name</param-name>
<param-value>Context-param param-value</param-value>
</context-param>
</concrete-portlet-app>
</portlet-app-def>
|
This section is defining both the portlet itself and the capabilities it will have when it's instantiated. In some ways, this is like the class definition; it's a template for the object you'll eventually create.
Now, start with the portlet element itself. The id attribute is how you'll identify the portlet; you'll refer to it in the next section when you create the concrete portlet. The href is how you determine the servlet that represents the portlet. The URL:
WEB-INF/web.xml#Servlet_1 |
tells the portal to look inside this application's web.xml file for a servlet with an id attribute of Servlet_1. If you look back at Listing 2, you'll see that that's the TestPortlet servlet. (For those of you who keep track of these things, this is actually an XPointer reference.)
Now that I've identified the servlet I'm talking about, I can make some statements about it. The first is the portlet name. Next, I'm determining whether the portlet is to be cached, and for how long, in seconds. To expire a portlet immediately, use 0. To cause the server to cache the portlet indefinitely, use -1. I'm also determining whether that cache is to be shared between user sessions.
The allows and supports elements determine the buttons that appear in the upper-right corner of the portlet window. The allows element lets you determine whether the portlet window can be minimized or maximized.
The supports element lets you determine whether the edit, configure, and help buttons will appear, assuming the user has the proper permissions. In other words, if the portlet doesn't support the edit mode, the user won't see the edit icon, even if he or she has the appropriate privileges. The supports element lets you make these decisions based on the markup in use at the time, so you can even determine the markups for which the portlet would appear. For example, if you were viewing the portal in WML on a cell phone, this portlet would not appear because it doesn't support the view mode for the WML markup. (Or any other mode, for that matter.) A portlet must support at least one markup, and the view mode is required for each markup the portlet supports.
Now, the actual concrete portlet needs to be defined.
You've got the base portlet, so now you need to define the concrete portlet that serves as the basis for the actual instantiated portlet:
Listing 8. Defining the concrete portlet
<?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="Portlet-app_uid">
<portlet-app-name>Portlet-app-name</portlet-app-name>
<portlet id="Portlet_1" href="WEB-INF/web.xml#Servlet_1">
<portlet-name>Portlet-name</portlet-name>
<cache>
<expires>0</expires>
<shared>NO</shared>
</cache>
<allows>
<maximized/>
<minimized/>
<resizing />
<closed />
</allows>
<supports>
<markup name="html">
<view/>
</markup>
</supports>
</portlet>
</portlet-app>
<concrete-portlet-app uid="concrete-portlet-app_uid">
<portlet-app-name>Concrete portlet-app-name</portlet-app-name>
<context-param>
<param-name>Context-param param-name</param-name>
<param-value>Context-param param-value</param-value>
</context-param>
<concrete-portlet href="#Portlet_1">
<portlet-name>Concrete Portlet-name</portlet-name>
<default-locale>en</default-locale>
<language locale="en">
<title>Concrete-portlet title</title>
<title-short>Title-short</title-short>
<description>Description</description>
<keywords>keywords</keywords>
</language>
</concrete-portlet>
</concrete-portlet-app>
</portlet-app-def>
|
Now, notice that the href attribute on the concrete-portlet points back to the id value from the portlet element. That linkage is how the concrete portlet is related back to the actual portlet. From here, determine the name of the portlet, as it will appear when the portlet application is installed or updated, as shown in Figure 1.
Figure 1. The concrete portlet app and concrete portlet show on install
The rest of the new information here relates to localization. First, I'm setting a default locale for the portlet, and then I'm setting information such as the title (which appears on the portlet window itself), the short-title, and the description, which appears when the user is adding the portlet to the page, as shown in Figure 2.
Figure 2. The concrete portlet title and description appear when searching for portlets
You can also set multiple languages, so if the user is looking for a language other than, in this case, English, you can provide information in the appropriate language.
The portlet application versus the concrete portlet application
It's important to understand that while the portlet application defines the basic template for each portlet, it is actually the concrete application and concrete portlets that get instantiated. Notice how Figure 2 shows that it's the concrete portlet application that is displayed when the application is installed, and not the portlet application itself.
Note also that you can have any number of concrete portlets based on a single portlet, and they can have their own title, descriptions, and so on. You can also add concrete portlet-specific information or context parameters:
Listing 9. Adding concrete portlet-specific information
<?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="Portlet-app_uid">
<portlet-app-name>Portlet-app-name</portlet-app-name>
<portlet id="Portlet_1" href="WEB-INF/web.xml#Servlet_1">
<portlet-name>Portlet-name</portlet-name>
<cache>
<expires>0</expires>
<shared>NO</shared>
</cache>
<allows>
<maximized/>
<minimized/>
<resizing />
<closed />
</allows>
<supports>
<markup name="html">
<view/>
</markup>
</supports>
</portlet>
</portlet-app>
<concrete-portlet-app uid="concrete-portlet-app_uid">
<portlet-app-name>Concrete portlet-app-name</portlet-app-name>
<context-param>
<param-name>Context-param param-name</param-name>
<param-value>Context-param param-value</param-value>
</context-param>
<concrete-portlet href="#Portlet_1">
<portlet-name>Portlet-name</portlet-name>
<default-locale>en</default-locale>
<language locale="en">
<title>Concrete-portlet title</title>
<title-short>Title-short</title-short>
<description>Description</description>
<keywords>keywords</keywords>
</language>
<config-param>
<param-name>
Concrete-portlet config-param param-name
</param-name>
<param-value>
Concrete-portlet config-param param-value
</param-value>
</config-param>
</concrete-portlet>
</concrete-portlet-app>
</portlet-app-def>
|
At this point, I've set two different types of parameters: application settings and portlet settings. I'll discuss the application settings first.
I created application parameters by adding them to the definition of the concrete portlet application. This action makes them available for editing through the administration pages. In the Portal Administration section, click Portlet Applications and highlight the PortletTest.war application. Clicking Modify Parameters gives you an opportunity to change these values, as shown in Figure 3.
Figure 3. The web interface enables you to modify concrete app parameters
You can access both the application setting parameters and the portlet setting parameters from within the portlet itself (some lines in this example have been split for display here):
Listing 10. Accessing the application and portlet setting parameters
package files;
import org.apache.jetspeed.portlet.*;
import org.apache.jetspeed.portlets.*;
public class TestPortlet extends PortletAdapter {
public void init(PortletConfig portletConfig)
throws UnavailableException
{
super.init( portletConfig );
}
public void doView (PortletRequest request, PortletResponse response)
throws PortletException, java.io.IOException
{
String value =
(String)request.getPortletSettings()
.getApplicationSettings().getAttribute(
"Context-param param-name"
);
response.getWriter().println("Context-param param-name =
"+value+"<br />");
String portletvalue =
request.getPortletSettings()
.getAttribute(
"Concrete-portlet config-param param-name
");
response.getWriter().println(
"Concrete-portlet config-param param-name = "
+ portletvalue
);
}
}
|
When you put it all together and install the portlet application, adding the portlet to a page shows the concrete portlet title, as well as the parameters you told it to output, as shown in Figure 4:
Figure 4. The final installed portlet instance
Although it seems like a lot of extraneous information, the web.xml and portlet.xml files actually give you a great deal of control over what users can do with your portlets and how they appear to users. The web.xml file defines the actual servlet that forms the basis for the portlet. The portlet.xml file creates the portlet application (with its portlet definitions) along with the concrete portlet application and the concrete portlet definitions that link back to it to define what the user sees.
- Participate in the discussion forum.
- Keep up-to-date with The making of MetroSphere.
- Learn more about WebSphere Portal administration with "Part 6, Tutorial: Getting started with WebSphere Portal - Express" (developerWorks, April 2003).
- Get comfortable with adding portlets to pages with "Part 7, Tutorial: Customizing pages with WebSphere Portal - Express" (developerWorks, April 2003).
- Learn how to install a portlet with "Part 13: Install an existing portlet" (developerWorks, June 2003).
- Get more information on using JSP tag libraries in general with the following developerWorks articles:
- "JSP best practices: Intro to taglibs" (developerWorks, July 2003)
- "Part 15: Make tag libraries available throughout the portal" (developerWorks, July 2003)
- Browse for books on these and other technical topics.

Nicholas Chase, a Studio B author, has been involved in Web site development for companies such as Lucent Technologies, Sun Microsystems, Oracle, and the Tampa Bay Buccaneers. Nick has been a high school physics teacher, a low-level radioactive waste facility manager, an online science fiction magazine editor, a multimedia engineer, and an Oracle instructor. More recently, he was the Chief Technology Officer of an interactive development firm in Clearwater, Florida, and is the author of four books on Web development, including XML Primer Plus (Sams).
