Printing tips Portlet creation


The WebSphere Portal Server runs on a modern application server that makes best-of-breed functionality available to the portal. But even the most advanced portal software is of little use were it not for the content it provides to the user. Because the kind of content can hardly be anticipated for each and every portal installation, the WebSphere Portal Server is designed as a framework that allows extensions to be plugged into the portal. These extensions are called portlets and make use of the infrastructure of the WebSphere Portal Server. In the same way that a servlet is an application within a Web server, a portlet is an application within the WebSphere Portal Server. Therefore, developing portlets is the most important task in making the portal server a portal that functions as the user's window to information.

This section introduces you to portlet creation and takes you through creating a portlet. It also provides information on the sample portlets provided with the WebSphere Portal Server, and gives guidelines for portlet creation.

Introduction

The WebSphere Portal Server is a framework which provides you with a Portlet API for plug-in portlets, thereby extending the functionality of the framework. Those of you who have developed servlets with the Servlet API will find themselves at home because the Portlet API is, conceptually at least, similar to the Servlet API.

With the WebSphere Portal Server, you can write a portlet just by providing a few lines of code in a method, or by writing a fully-fledged application that adheres to typical patterns like model-view-controller. This section introduces you to the concepts of portlet creation, starting with a simple example portlet that is modified throughout.

To write a portlet, refer to Creating a portlet.

The Hello World portlet

Every portlet that you wish to plug into the WebSphere Portal Server has to implement the Portlet interface org.apache.jetspeed.portal.Portlet either directly, or by extending a class that in turn implements the Portlet interface. Extending an existing class, such as AbstractPortlet, makes writing a portlet easier if your portlet does not need a lot of special treatment. Otherwise, implementing the Portlet interface requires you to implement a lot of abstract methods, but it gives you full control over the operation of the WebSphere Portal Server application.

The first portlet you write is the Hello World portlet. The WebSphere Portal Server provides a number of classes that implement the Portlet interface with the most common functionality, leaving only a few methods to be implemented by you. The AbstractPortlet class is the simplest of these predefined classes.

To start with, the Hello World portlet you write should look like this:

import org.apache.jetspeed.portal.portlets.AbstractPortlet;
 
import org.apache.turbine.util.RunData;
 
import org.apache.ecs.*;
 
public class HelloWorldPortlet extends AbstractPortlet
{
    public ConcreteElement getContent (RunData aRunData)
    {
        return (new StringElement ("Hello World!"));
    }   
}
 

Now, you need to compile this portlet and copy the class files into the appropriate path. Once you have configured the portlet into the WebSphere Portal Server application (see Portal configuration), the user can choose this portlet from the list of selectable portlets when customizing personalized pages.

As you can see, the most important method to override with a useful implementation is the getContent() method. The getContent() method takes the RunData object which is passed through from the internal component Turbine. The RunData class is one of two classes of Turbine that you deal with, therefore, the import statement can include just that. Except for requesting the user object (which is described later), there should not be any other reason for accessing elements of the RunData object. The main reason for passing the RunData object to the getContent() is that it needs to be passed on to many other methods of the portal framework.

Another important component in the Portlet interface is the Element Construction Set (ECS), an object-based markup generator. It uses Java objects to construct the elements of the respective markup. Admittedly, this approach is better than hard-coding markup tags, but it still places markup information into compiled code. Therefore, we generally recommend using a page template mechanism of your choice, rather than using ECS. For more information on ECS, refer to http://jakarta.apache.org/ecs.

Note: At the time of this writing, ECS is limited to HTML, WML, and generic XML markup. Therefore, a portlet you develop is limited to these markup types. While the WebSphere Portal Server Version 1 Release 1.1 supports PC browsers, i-mode and WAP phones, future versions of the product are likely to support additional markup and device types.

The next step in your portlet example is to make the "World" more specific. That is, instead of writing out a static string, the greeting is personalized according to the user settings.

import org.apache.jetspeed.portal.portlets.AbstractPortlet;
 
import org.apache.turbine.util.RunData;
import org.apache.turbine.om.security.User;
 
import org.apache.ecs.*;
 
public class HelloWorldPortlet extends AbstractPortlet
{
    public ConcreteElement getContent (RunData aRunData)
    {
        StringBuffer text = new StringBuffer ();
 
        text.append ("Hello ");
 
        String name = aRunData.getUser ().getFirstName ();
 
        if (name == null)
            name = "World";
 
        text.append (name);
        text.append ("!");
 
        return (new StringElement (text.toString ()));
    }   
}
 

With this example, you have learned about the only other class of Turbine that you use with the WebSphere Portal Server, the user object (aRunData.getUser). It captures important information about the user who is currently logged on. While using the portal anonymously, the user object has all null values.

To incorporate information about the user is just one option to dynamically adapt the content that the portlet displays. Another, more general, path is the configuration of the portlet itself. In our example, the "Hello" string is hard-coded into the portlet; the next step is where you make the string configurable. You can soft-code this string by replacing the line

        text.append ("Hello ");

with access to the portlet configuration

        text.append (getPortletConfig ().getInitParameter ("greeting"));

Along with this change, you have to put a parameter entry into the jetspeed-config.jcfg for the HelloWorldPortlet portlet, for example:

<portlet-entry ....>
 
   <classname>...HelloWorldPortlet<classname/>
   <parameter name="greeting" value="Hello, "/>
    ...
</portlet-entry>
 

You can only put configuration into the portlet configuration that is identical for all usages of that portlet, regardless of the user and page. If a portlet requires two different sets of configuration settings then, quite possibly, you are dealing with two different portlets. They share the same code but, by means of two different configurations, they are different portlets.

The multidevice capability

One of the main features of the WebSphere Portal Server is its support for multiple device capabilities. Version 1 Release 1.1 of the WebSphere Portal Server supports PC browsers, i-mode and WAP phones, and future versions of the product are likely to support additional device types. The challenge with supporting multiple devices is to render content differently depending on the characteristics of the browser. One browser may accept HTML 4.0, another WML, and one WAP phone may have four lines with twenty-five characters while another phone has its own PDA-style interface.

Firstly, to enable a WebSphere Portal Server portlet for multiple devices, you need to implement or override the supportsType() method. As default, only HTML is a supported MimeType. A typical implementation could look like this:

import org.apache.jetspeed.util.MimeType;
 
public class HelloWorldPortlet ...
{
    ...
 
    public boolean supportsType (MimeType aMimeType)
    {
        return (MimeType.HTML.equals (aMimeType) || 
                MimeType.WML.equals (aMimeType));
    }
 
    ...
}								

Secondly, you need to modify the portlet so that different markup is generated depending on the MimeType that the client device requests. The most straightforward approach is an if-then-else statement that branches out to the different markup generation paths. The following example illustrates this:

import org.apache.jetspeed.portal.portlets.AbstractPortlet;
 
import org.apache.turbine.util.RunData;
import org.apache.turbine.om.security.User;
 
import org.apache.ecs.*;
 
import org.apache.jetspeed.capability.*;
import org.apache.jetspeed.util.MimeType;
 
public class HelloWorldPortlet extends AbstractPortlet
{
    public ConcreteElement getContent (RunData aRunData)
    {
        StringBuffer text = new StringBuffer ();
 
        text.append (getPortletConfig ().getInitParameter ("greeting"));
 
        String name = aRunData.getUser ().getFirstName ();
 
        if (name == null)
            name = "World";
 
        text.append (name);
        text.append ("!");
 
        ElementContainer base = new ElementContainer ();
 
        CapabilityMap cap = CapabilityMapFactory.getCapabilityMap (aRunData);
 
        // here we go different ways
 
        if (cap.getPreferredType ().equals (MimeType.HTML))
        {
            base.addElement (new org.apache.jetspeed.ecs.html.P ()
                                 .addElement (text.toString ()));
        }
        else if (cap.getPreferredType ().equals (MimeType.WML))
        {
            base.addElement (new org.apache.jetspeed.ecs.wml.P ()
                                 .addElement (text.toString ()));
        }
        
        return (base);
    }
 
    public boolean supportsType (MimeType aMimeType)
    {
        return (MimeType.HTML.equals (aMimeType) || 
                MimeType.WML.equals (aMimeType));
    }
}
								

In this case, the markup differences are minimal--either path creates a Hello World paragraph. But you can easily imagine how complex hard-coded markup can become. Writing ECS for complex markup can be cumbersome. To minimize the amount of hard-coded markup, you can also use the class org.apache.jetspeed.util.servlet.EcsServletElement which allows you to embed other resources for markup generation. You can also use Java Server Pages (JSP) as a useful template mechanism. The WebSphere Studio 3.5 supports creating JSPs in WYSIWYG fashion.

To utilize template resources, you need to propagate data to those resources. This can be done by getting the HttpServletRequest from RunData and setting one or more attributes. Always use a unique name because other portlets may use the same request to communicate with their resources, for example:

import org.apache.jetspeed.portal.service.*;
 
public class HelloWorldPortlet ...
{
    public ConcreteElement getContent (RunData aRunData)
    {
        ...
 
        aRunData.getRequest ().setAttribute ("HelloWorldPortlet.text", text);
 
        if (cap.getPreferredType ().equals (MimeType.HTML))
        {
            base.addElement (new EcsServletElement ("/path.to/HelloWorldHTML.jsp"));
        }
        else if (cap.getPreferredType ().equals (MimeType.WML))
        {
            base.addElement (new EcsServletElement ("/path.to/HelloWorldWML.jsp"));
        }
        
        return (base);
    }
}
    

This Hello World example is for demonstration purposes only, and it is by no means the only, or best way to prepare a portlet for multidevice markup generation. Every new device type requiring a different markup means that you need to change and recompile your portlet accordingly.

The WebSphere Portal Server provides two classes, MDPortlet and EditableMDPortlet, which provide multidevice capabilities as abstract classes. The former is an extension of the AbstractPortlet class mentioned earlier. Additional devices are supported by this class by implementing and configuring so-called renderers. The latter is a further extension, which already implements the EditablePortlet interface, and is therefore geared for writing portlets that need an edit mode to configure the user settings of the portlet.

The persistence service

Ultimately, a portlet should render its content in as personalized and as specific a manner as possible. To allow you to do this, the WebSphere Portal Server Portlet API contains the persistence service PersistenceService. This grants read and write access to the portlet configuration of a particular user. Through this mechanism, you can have the same portlet render personalized content for different users. Imagine that the Hello World portlet is to show an optional nick name instead of the first name. The nick name is not captured by the general user object, therefore it has to be captured by the portlet itself and stored separately for each user.

The WebSphere Portal Server persistence service has methods to set, remove, store, and retrieve attributes on a per-user, per-page basis. The following example shows how the Hello World portlet uses these to introduce the nick name:

import org.apache.jetspeed.portal.service.*;
public class HelloWorldPortlet ...
{
    ...
 
    public ConcreteElement getContent (RunData aRunData)
    {
        StringBuffer text = new StringBuffer ();
 
        text.append (getPortletConfig ().getInitParameter ("greeting"));
 
        String name = null;
 
        try
        {
            PersistenceService service = (PersistenceService) 
                ServiceFactory.getService (PersistenceService.class, 
                                           aRunData, new Object [] { this });
 
            PersistenceService.Page page = service.getPage ();
 
            name = page.getAttribute ("nick name");
        }
        catch (ServiceException exc)
        {
            // Plan B: use first name
 
            name = aRunData.getUser ().getFirstName ();
        }
 
        if (name == null)
            name = "World";
 
        text.append (name);
        text.append ("!");
 
        ...
    }
 
    ...
}								

Firstly, the persistence service needs to be created. The service factory internally resolves the interface name against a suitable implementation. The portlet reference is the only parameter passed to the factory. The persistence service requires only this reference in order to attach the relevant attributes for that portlet.

The persistence service grants access to all the pages of the user that contain the particular portlet. The Hello World portlet needs only to access the attributes for this particular portlet on the current page, therefore, getPage() is sufficient. Through getter and setter methods for attributes with one or more values, the respective properties can easily be extracted.

Because the Hello World portlet does not yet have an edit mode, the nick name cannot be configured by the user. Therefore, to test this portlet, you need to provide the relevant parameter in the user's page configuration, for example:

    <entry type="ref" parent="HelloWorld">
        ...
        <parameter name="nick name" value="Hank"/>
        ...
    <entry/>						

To change the user's page configuration, refer to Changing page configuration.

The editable portlet

Obviously, adding parameter entries to a PSML structure in the WebSphere Portal Server is not an option for the end user because the page structure is not available to the user. Instead, the page layout and portlet selection is done through the Customizer while the portlet configuration depends on the content that the portlet generates. A portlet that renders stock information needs configuration that is different from the configuration that a sports news portlet requires. Therefore, the portlet knows best what to configure and what not to configure.

At this stage, the Hello World example portlet has only one markup-generating method which is the getContent() method. This method needs to be overridden in a portlet to generate the content for which the portlet is responsible. To generate something other than the normal content, the portlet would need a differentiator. In the following example, the URILookup class provides this:

import org.apache.jetspeed.util.URILookup;
 
public class HelloWorldPortlet ...
{
    public ConcreteElement getContent (RunData aRunData)
    {
        int uriType = URILookup.getURIType (this, aRunData);
 
        switch (uriType)
        {
 
            case URILookup.TYPE_HOME:
 
                // business as usual 
                ...
 
                break;
 
            case URILookup.TYPE_EDIT_PORTLET:
                // your configuration goes here
                ...
                break;
 
        }
    }
}

The URILookup class resolves the URI that called this portlet in order to identify the context in which the portlet is running. The default context is TYPE_HOME, but as you can see others are also possible. In this case, TYPE_EDIT_PORTLET identifies the edit mode of the portlet. If the edit mode has been identified as the current context, the portlet now has to render whatever is required to acquire the configuration of the portlet. In the Hello World example, this should be a simple form that captures the user's nick name. When the form gets posted to the portlet, again the portlet is run in edit mode. The difference is that the HTTP method is set to POST, for example:

if (aRunData.getRequest ().getMethod ().equals ("POST"))
{
    String nickName = aRunData.getRequest.getParameter ("nickName");
 
    try
    {
    PersistenceService service = (PersistenceService)
        ServiceFactory.getService (PersistenceService.class,
                                   aRunData, new Object [] { this });
 
        PersistenceService.Page page = service.getPage ();
 
        if (nickName == null || nickName.size () == 0)
            page.removeAttribute ("nick name");
        else
            name = page.setAttribute ("nick name", aRunData);
    }
    catch (ServiceException exc)
    {
    }     
}
else
{
    // do the normal configuration stuff
 
    ...
}
 

For a complete illustration of how the different modes are implemented, refer to the sample portlets provided with the WebSphere Portal Server.

Now that you have implemented the edit mode of the portlet, the last thing to enable is the Edit button which appears in the title bar of every editable portlet. This button appears if a portlet is derived from the (empty) org.apache.jetspeed.portal.EditablePortlet interface. This example shows you how to make the Edit button visible:

public class HelloWorldPortlet implements Portlet, EditablePortlet
{
    ...
}
 

The Edit button is only visible if you are logged on because the anonymous user is not allowed to configure any of the portlets at this stage.

Creating a portlet

The Portlet API supplied with the WebSphere Portal Server allows for the creation of portlets, and because much of the coding involved is similar for each new portlet, the portlet framework provides a sample extension for multidevice portlets that handles these basic functionalities.

Use the multidevice portlet extension to create your portlets. This section introduces the multidevice portlet extension and provides instructions for creating a portlet using this extension.

The multidevice portlet extension

The multidevice portlet extension consists of the following elements:

MDPortlet class

This class provides you with the following basic functionality for portlets:

This class uses JLog classes for log and trace handling. For further information, refer to Logging management.

EditableMDPortlet class

This class offers the same functionality as MDPortlet. Furthermore, it implements the EditablePortlet interface. In doing so, it enables the developer to implement a configuration page for the portlet in the renderEdit() method. A configuration button is provided when the portlet is displayed on a user's personalized page. This button triggers the execution of the renderEdit() method of the portlet renderers.

PortletRenderer interface

This interface describes the basic functionalities of a portlet renderer. The main methods are:

The PortletRenderer objects implement the actual behavior of the portlets. A portlet object receives an HTTP request, analyzes the URI, and calls the corresponding method in the PortletRenderer object. The doCancel() and doSave() methods are called before renderEdit() and renderContent(). The following table shows which methods are called, based on the type and subtype of the URI:

Renderer methods

URI Renderer method
renderEdit renderContent doCancel doSave
TYPE_ EDIT_ PORTLET SUBTYPE_ NONE X      
SUBTYPE_ CANCEL X   X  
SUBTYPE_ SAVE X     X
TYPE_* (1) SUBTYPE_ NONE   X    
SUBTYPE_ CANCEL   X X  
SUBTYPE_ SAVE   X   X

(1) All URI types except TYPE_EDIT_PORTLET.

The following example, from the Stock sample portlet, shows how methods are called:

stockEditBean.setEditURI(
   URILookup.getURI(
      URILookup.TYPE_EDIT_PORTLET,
      URILookup.SUBTYPE_SAVE,
      getPortlet(),
      rundata));
 

The URILookup class handles all communication to and from the portlet. In the example, a URI is created that has the type TYPE_EDIT_PORTLET and the subtype SUBTYPE_SAVE. This means that the doSave() and renderEdit() methods are called, respectively, when the URI is used in an HTTP request. In the example, this request is made by the portlet configuration JSP.

AbstractPortletRenderer class

This default implementation of the portlet renderer implements methods that are common to all portlet renderers. It manages log and trace handling, initializing the renderer, and implementing the getPersistenceService() method to contact the portal's persistence service. It also implements a basic national language support functionality in its getPreferredLanguage() method.

Creating a portlet using the multidevice portlet extension

Follow these instructions to create a portlet using the multidevice portlet extension:

  1. Create a portlet entry for MDPortlet or EditableMDPortlet in the configuration file jetspeed-config.jcfg:
    <portlet-entry type="abstract" name="EditableMDPortlet">
    <classname>com.ibm.wep.portlets.EditableMDPortlet</classname>
    </portlet-entry>
     
    <portlet-entry type="abstract" name="MDPortlet">
    <classname>com.ibm.wep.portlets.MDPortlet</classname>
    </portlet-entry>
    

    MDPortlet and EditableMDPortlet are abstract portlet entries that can exist only once in the configuration file.

  2. Create a portlet entry for your portlet, such as one derived from MDPortlet:
    <portlet-entry type="ref" parent="MDPortlet" name="HelloWorldPortlet">
    <parameter name="renderer.html"
    value="com.ibm.wep.portlets.helloworld.HelloWorldHtmlRenderer"/>
    <parameter name="renderer.wml"
    value="com.ibm.wep.portlets.helloworld.HelloWorldWmlRenderer"/>
    <meta-info>
    <title>helloWorldTitleKey</title>
    <description>helloWorldDescriptionKey</description>
    </meta-info>
    </portlet-entry>
    

    In this example, the portlet can be used with HTML and WML access devices because it implements a renderer for each type. The configured portlet title is used when displaying the portlet in all mime-types, but WML renderers have to specify the <card> tag and set the portlet title there.

  3. Implement the portlet renderer code by writing subclasses of the class AbstractPortletRenderer that implement the required functionality of the portlet. The simplest implementation would be a renderer with just the init() and renderContent() methods, as shown in the HelloWorld sample portlet.

    The sample stock portlet is a more sophisticated example of using portlet renderers. It implements renderContent and renderEdit, and also a doSave and a doCancel action.

  4. Copy the required portlet resources, such as images, JSPs, and style sheets to the correct location. Copy image files to the relevant /portlet_resources subdirectory. For example, copy rainy.gif to the subdirectory wep/app/web/portlet_resources/weather .

    Copy JSPs and style sheets to the relevant /portlets subdirectory. For example, copy Stock2HTML.jsp to the subdirectory wep/app/web/WEB-INF/portlets/stocks/jsp/en, which is the English language subdirectory.

  5. Copy the JAR file containing the portlet code to the relevant /portlets subdirectory. For example, copy stocks.jar to the subdirectory wep/app/web/WEB-INF/portlets/stocks .

The user can now choose this portlet from the list of selectable portlets when customizing personalized pages. If this portlet implements the EditablePortlet interface, you can also configure the portlet.

Sample portlets

The WebSphere Portal Server provides you with a set of sample portlets that demonstrate how to generate markup for different content sources. The sample portlets cover stock quotes, weather information, news headlines, and more. The portlets are intended to give you a general impression of the different techniques that can be deployed to write a portlet. This section gives you a brief description of the purpose and functionality of the sample portlets.

Stock portlet

The stock portlet shows delayed or real-time stock quotes for a given list of stock symbols. These stock quotes are retrieved from a content provider who is contracted to deliver stock quotes and other stock market information. With every reload of the page, the stock quotes are updated to show the latest information.

Each user has a list of stock symbols to track. For the anonymous user, the list is immutable and predefined by the portal administrator.

The stock portlet is derived from the class AbstractPortletRenderer. This portlet, along with the weather and news portlets, uses a derivative of the model-view-controller pattern to generate the content for which it is responsible.

This pattern has the following characteristics:

The renderer receives an XML representation of the relevant stock data from the connector. It is then converted into object form and is passed to a JSP. The JSP uses the model to fill its template with the data contained in the model.

For legal reasons, the connector does not really connect to a content provider; it adds fake data from a data file.

The properties and other resources, such as images and JSPs, of the stock portlet are located in the directories wep/app/web/WEB-INF/portlets/stocks and wep/app/web/portlet_resources/stocks . The source code is located at wep/src/portlets/com/ibm/wep/portlets/stocks .

News portlet

The news portlet shows headlines from a configurable set of categories. When a headline is clicked on, the full news text is loaded.

The news portlet uses the same mechanisms as the stock portlet. In addition, it illustrates how to implement a multipage edit mode for a portlet.

For legal reasons, the connector does not really connect to a content provider; it adds fake data from a data file.

The properties and other resources, such as images and style sheets, of the news portlet are located in the directories wep/app/web/WEB-INF/portlets/news and wep/app/web/portlet_resources/news . The source code is located at wep/src/portlets/com/ibm/wep/portlets/news .

Weather portlet

The weather portlet renders weather information for a configurable set of cities. For each city, it shows the current temperature (in Fahrenheit) and the general outlook (for example, sunny or overcast). Similar to the stock and news portlets, the data is collected from the content provider through a connector and is updated with every reload of the page.

In contrast to these portlets, the weather portlet does not convert the weather information from XML format to a Java object. Instead, it passes the XML document as-is to Xalan, which is used to execute an XSL style sheet on the XML document. The style sheet differs with the renderer being used. The generated output is returned by the portlet for aggregation by the portal.

For legal reasons, the connector does not really connect to a content provider; it adds fake data from a data file.

The properties and other resources, such as images and style sheets, of the weather portlet are located in the directories wep/app/web/WEB-INF/portlets/weather and wep/app/web/portlet_resources/weather . The source code is located at wep/src/portlets/com/ibm/wep/portlets/weather .

WPers portlet

The WPers portlet uses WebSphere Personalization to create JSPs for rendering its content. This portlet retrieves information about the current user from the LDAP directory and displays content, depending on WebSphere Personalization rules.

For information on WebSphere Personalization and on installing the WPers portlet, refer to WebSphere Personalization support.

Portlet creation guidelines

The Portlet API and the multidevice portlet extension of the WebSphere Portal Server are designed to give you, the portlet developer, maximum flexibility for developing portlets. Some guidelines apply, largely to ensure optimal performance of your portlet. Those of you who have developed servlets with the Servlet API will find that the guidelines are very similar for portlet creation.

No instance and class variables

The most important rule of thumb is not to use any instance or even class variables in a portlet. Within the WebSphere Portal Server, there only ever exists one object instance of each portlet. That is, even if different users have the same portlet on their pages, it is the same portlet object instance that generates the markup. Therefore, each portlet instance has to be treated like a singleton. The implication is that you should not use any instance or class variables to store anything between calls. Being a singleton, each instance variable of a portlet effectively becomes a class variable with similar scope and similar multithreading issues. It is better to avoid these problems by not having instance or class variables. Otherwise, reentrance or thread safety may be compromised.

This rule is of particular importance for the persistence service. While you may wish to reduce calls to the service factory, you still have to let the service factory create the persistence service for every call because you do not know the user or page that needs to be displayed during the next call.

There is an exception to this rule in that you can use instance variables. Variables whose values do not change can be stored safely in instance variables. For example, on initialization of the portlet, its configuration is set within the portlet. Because the configuration does not change for different users or between calls, you can store it in an instance variable.

Do not use Turbine RunData

Except for accessing the user object and the HTTP request object, you should not adjust the settings or content of this class.

Restrict access to the portal server

The WebSphere Portal Server is based on an open source project called Jetspeed, which means it is possible for you to gain access to the internal components of the portal server. It is recommended that you do not do this because it may affect the internal operations of the WebSphere Portal Server and damage your portlet code.

Improve portlet efficiency

The WebSphere Portal Server uses the same portlet instance to generate the markup for different pages for different users. There is a limited number of threads that perform these tasks. It is imperative to implement the portlet to do its job as quickly as possible so that response time for a whole page is optimized.

General tips for markup fragments

Portlets are only allowed to render markup fragments, which are then assembled by the portlet framework for a complete page. Therefore, be sure to exclude all page-level tags, such as <html>, <head>, <body>, <link>, <title>, <meta>, <base>, <wml>, and so on.

Because HTML, WML, and cHTML code fragments are embedded into other code fragments, make sure that they are complete, contain no open tags, and only contain valid HTML, WML, or cHTML. This helps to prevent the portlet's HTML code, for example, from corrupting the portal's aggregated HTML code. It is recommended to use a validation tool, such as that in the WebSphere Studio.

Refer to Tips for more detailed tips on HTML, WML, and cHTML markup fragments.

Sample HTML code

The following HTML code is generated by controller JSPs which are provided with the WebSphere Portal Server to ensure a consistent look and feel for each portlet and Portlet configuration page. Every portlet is contained in a table with two rows. The first row has two cells containing the title bar and the interaction icons. The second row has a single cell containing specific HTML code for the portlet.

<TABLE class = "Portlet" width="100%" border="0" cellspacing="0" cellpadding="0">
 
    <TR>
        <!-- Portlet Title -->
        <TD class="PortletConfigurationTitle">Weather Configuration</TD>
 
        <!-- Icons -->
        <TD class="PortletConfigurationTitle "ALIGN="right">
        <!-- Edit Icon --> <A HREF="..." ><IMG SRC="[wep]/web/images/edit.gif"
                              ALT="Configure Portlet"> </A>
        <!-- Maximize Icon --><A HREF="..." >IMG SRC="[wep]/web/images/maximize.gif"
                                 ALT="Maximize Portlet"></A>
 
        </TD>
    </TR>
 
    <TR>
        <TD colspan="2">
 
                <!-- Your portlet-specific code is inserted here -->
 
        </TD>
    </TR>
</TABLE>
 

The controller JSP ensures that your portlet is rendered consistently. The JSP uses the file portlets.css, a central Cascading Style Sheet (CSS), to control the look and feel. It is recommended that you reuse the styles in this file rather than using tags or attributes to specify colors, fonts, or other visual elements. The aggregated personalized page should contain the link to the central CSS file in its header section. For further information, refer to Customizing the look and feel.


Related information