Portal Guide

CHAPTER 13

Strategies for Developing Portlets

This chapter describes strategies for developing portlets, with an emphasis on using the exteNd Director portlet tools and API for implementing value-added features. The following topics are covered:

For more informationFor detailed information about the Java Portlet 1.0 API, see the Java Community Process Web site:

  http://jcp.org/aboutJava/communityprocess/final/jsr168/index.html

 
Top of page

The portlet development cycle

When developing a portlet to run with the exteNd Director portal, the following steps are recommended:

  1. Create the portlet class using exteNd Director development tools, as described in Portlet development tools.

  2. Create at least one instance of the portlet class—called a portlet definition, as described in the section on creating a portlet definition.

  3. Register at least one of your portlet definitions to create a portlet registration, as described in the section on registering a portlet definition.

  4. Test the portlet by running the portlet registration directly in a browser, as described in the section on testing a portlet.

  5. Add the portlet registration to the appropriate portal pages, as described in the section on adding portlets to portal pages.

For more informationFor more information about portlet classes and portlet definitions, see the section on the portlet object model.

 
Top of page

Portlet development tools

exteNd Director provides several tools for developing portlets:

 
Top of section

Pageflow design tools

exteNd Director provides design tools for developing pageflows. As the name suggests, pageflows are portlets that implement a flow of control between activities within a portlet session. These activities can model a sequence of user interactions or background processing tasks. The design tools in exteNd Director facilitate the process of defining and linking activities in a pageflow without requiring you to write Java code.

Types of pageflow design tools

There are several pageflow design tools to choose from:

Tool

What it does

Pageflow Modeler

Allows you to create generic pageflow processes

Database Pageflow Wizard

Allows you to create Database pageflows, which are specialized flows that allow users to find, display, and modify records in a database during their portlet session

Web Service Pageflow Wizard

Allows you to create pageflows that execute Web Services

Composer Pageflow Wizard

Allows you to create pageflows that execute exteNd Composer services

For more informationFor an in-depth discussion about pageflows and how to use these design tools, see the Pageflow and Form Guide.

When to use pageflow design tools

Consider using pageflow design tools for developing your custom logic when:

 
Top of section

Portlet Wizard

Although you can implement most of your portlet application logic using pageflows, there are situations in which you may want to write custom portlet classes. The Portlet Wizard in exteNd Director simplifies the process by

For more informationTo learn how to create custom portlet classes using the Portlet Wizard, see the section on using the Portlet Wizard.

When to use the Portlet Wizard

Consider using the Portlet Wizard for developing your custom logic when:

 
Top of page

Anatomy of a portlet class

This section discusses the logic requirements for a portlet class and describes what the Portlet Wizard generates automatically.

 
Top of section

Minimum code requirements

At a minimum, a portlet class must include the following logic:

Required logic

What the Portlet Wizard generates

Include Java imports

Imports:

  • java.io.PrintStream

  • java.io.PrintWriter

  • javax.portlet.*

Implement javax.portlet.Portlet or extend javax.portlet.GenericPortlet

Extends javax.portlet.GenericPortlet

Get initialization parameters from the portlet.xml deployment descriptor

Adds method signature for the init() method

Implement mandatory View (when extending GenericPortlet)

Adds method signature for the doView() method, along with code that:

  • Sets the content type for the portlet

  • Gets the Writer of the RenderResponse object

  • Creates a string buffer to build portlet content

Process portlet requests

Adds method signature and basic code for the processAction() method

 
Top of section

Required imports for working with the exteNd Director portal

The Portlet Wizard automatically generates code for importing packages that are required for working with the exteNd Director portal:

 
Top of section

Code example

Here is an example of a portlet class generated by the Portlet Wizard, based on its default settings:

  /**
   * Generated by Novell XSLT Code Generator, version 1.0.
   * This generated source file may be freely modified.
   */
  
  
  package com.novell.portlets;
  
  // Java imports
  import java.io.PrintStream;
  import java.io.PrintWriter;
  import javax.portlet.*;
  
  // Portal/Framework imports
  import com.sssw.fw.api.*;
  import com.sssw.portal.api.*;
  
  // Portlet API imports
  import com.novell.afw.portlet.api.EbiPortletConstants;
  
  
  /**
   * MyPortlet
   */
  public class MyPortlet extends GenericPortlet {
  
      // an Instance of a log for error/trace reporting
      private static EbiLog m_log =  com.sssw.fw.log.EboLogFactory.getLog(com.sssw.fw.log.EboLogFactory.PORTLET);
  
      /**
       * Get the initialization parameters from the portlet.xml file
       */
      public void init() throws PortletException {
      }
   
      /**
       * Helper method to serve up the mandatory view mode
       * @param request           an portlet request object
       * @param response          an render response object
       */
      public void doView( RenderRequest request, RenderResponse response ) throws PortletException, java.io.IOException {                                                            
   	         
           try {         
             
              // Uncomment the code below when access to portal subsystems is needed
              /*
              // EbiContext stores information about the user's environment
              EbiContext ebiContext = com.sssw.fw.factory.EboFactory.createEbiContext( request, response, getPortletContext() );
              
              // Get a reference to the Portal Context object 
              EbiPortalContext ebiPortalContext = ( EbiPortalContext ) request.getAttribute( EbiPortletConstants.EBI_PORTAL_CONTEXT );
              */
                          
              PortletURL renderUrl = response.createRenderURL();
              response.setContentType( EbiPortletConstants.MIME_TYPE_HTML );
              renderUrl.setPortletMode( PortletMode.VIEW );
                        
  PrintWriter writer = response.getWriter();
                                 
              // Build the screen of HTML, set it as the content
              StringBuffer sb = new StringBuffer();           
              
              // Output code goes here
              sb.append( "View Mode" );
              sb.append( "<br></br>" );
            
              writer.print( sb.toString() ); 
          } 
          catch ( Throwable e ) {
              // Log any errors generated
              m_log.error(e);
              new PortletException( e );
          }
      }
   
      /**
       * Process any requests that the portlet may have.
       * @param request           an action request object
       * @param actionResponse    an action response object
       */
      public void processAction (ActionRequest request, ActionResponse response) throws  PortletException, java.io.IOException {
          
          try {
              PortletContext portletContext = getPortletContext();
              
              // only log items if the log level indicates we should
              if ( m_log.isTrace() ) {
                  m_log.trace( "MyPortlet in processAction method" );
              }            
              // Do "save" processing here if necessary, and then
              // set the portlet mode to be "View" after completion.
              response.setPortletMode( PortletMode.VIEW );
          }
          catch ( Throwable e ) {
              // Log any errors generated
              m_log.error( e );
              new PortletException( e );
          }   
      } 
  }

 
Top of page

The Portlet interface

All portlets implement the Portlet interface, as defined by Java Portlet 1.0. The Portlet interface provides methods that the portlet container uses to manage the life cycle of each portlet:

Method

Description

init()

Places a portlet into service

processAction()

Notifies the portlet to respond to an action request sent by a client and triggered by an action URL.

This method can be called only if the portlet has created an action URL with RenderResponse.createActionURL

render()

Notifies the portlet to respond to a render request sent by a client by generating content.

The portlet renders content based on its current state and the request/response pair passed in as parameters.

destroy()

Takes a portlet out of service

Portlets can implement the Portlet interface directly or extend the GenericPortlet class, which implements the Portlet interface and also provides helper methods, as described in The GenericPortlet class.

 
Top of page

The GenericPortlet class

When you develop portlets, you can extend the GenericPortlet class, rather than implement the Portlet interface directly.

The GenericPortlet class provides a default implementation for the Portlet interface. The advantage of extending GenericPortlet is that you gain access to its helper methods which simplify coding for the following tasks:

 
Top of section

Implementing standard portlet modes

The following methods defined in the GenericPortlet interface implement the standard portlet modes, as described in Portlet modes. When you write portlets, you can override these methods with custom processing logic as needed for each mode you implement:

Method

Description

doView()

Implements portlet behavior in View mode. This is the default mode in which the portlet generates markup that reflects its current window state.

doHelp()

Implements portlet behavior in Help mode. This is an optional mode that provides help information about the portlet.

doEdit()

Implements portlet behavior in Edit mode. This is an optional mode that provides content and logic to allow users to customize portlet behavior.

These methods perform the render operation in each mode.

NOTE:   exteNd Director provides a default implementation for Edit mode, as described in Default implementation for Edit mode.

 
Top of section

Portlet life cycle methods

The following methods defined in the GenericPortlet interface implement portlet life cycle phases, as described in Portlet life cycle:

Method

Description

init()

Called by the portlet container to place the portlet into service

processAction()

Notifies the portlet that an action request was issued

render()

Notifies the portlet that a render request was issued

destroy()

Called by the portal container to take the portlet out of service

 
Top of section

Getting portlet configuration parameters

The following get methods defined in the GenericPortlet interface provide access to portlet configuration parameter:

Method

Gets

getInitParameter()

Value of a named portlet initialization parameter

getInitParameterNames()

Names of all portlet initialization parameters

getPortletConfig()

Configuration object for the portlet

getPortletContext()

Portlet application context, as described in Portlet context

getPortletName()

Name of the portlet

getResourceBundle()

Resource bundle for a given locale

 
Top of page

Working with context objects

In addition to supporting the standard context objects defined in Java Portlet 1.0, exteNd Director provides proprietary context objects that allow portlets to interact with the exteNd Director portal and communicate with other exteNd Director subsystems:

 
Top of section

EbiContext

EbiContext, defined in the exteNd Director Framework system, is the interface through which all exteNd Director subsystems communicate. EbiContext stores information about the user environment, including the user's ID, session, and the response and request objects appropriate to the current user agent or browser.

You can also access information about other exteNd Director subsystems through the EbiContext, as described in Using EbiContext to access information about other subsystems.

The EbiContext object exists for the duration of a request. With each new request, the exteNd Director portal instantiates a new context object. Information that persists between requests is stored in the EbiSession object, available by calling a getEbiSession() method on EbiContext.

By contrast, there is one standard javax.portlet.PortletContext per portlet application. The standard PortletContext object does not provide access to exteNd Director-specific information in the portlet application.

Getting a reference to EbiContext

Portlets can reference EbiContext objects by calling createEbiContext() methods on the EboFactory class for the Framework subsystem. To get an EbiContext context object, use:

  EbiContext context = com.sssw.fw.factory.EboFactory.createEbiContext(req, res, getPortletContext());

Getting EbiContext for specific types of portlet requests and responses

You can get an EbiContext associated with a particular type of portlet request and response, as follows:

Using EbiContext to access information about other subsystems

There are several ways for a portlet to access information about other exteNd Director subsystems through EbiContext:

 
Top of section

EbiPortalContext

Like the standard javax.portlet.PortalContext, the EbiPortalContext object gives portlets access to portal-specific information. The difference is that EbiPortalContext provides methods that return information specific to the exteNd Director portal, such as data relating to personal, shared, and container pages.

Getting a reference to EbiPortalContext

Portlets can reference EbiPortalContext objects by calling createEbiContext() methods on the EboFactory class for the Framework subsystem. To get an EbiPortalContext context object, use:

  // Get a reference to the Portal Context object 
  EbiPortalContext ebiPortalContext = ( EbiPortalContext )   request.getAttribute( EbiPortletConstants.EBI_PORTAL_CONTEXT );

 
Top of page

Setting content type

You must set the content type on the render response for each portlet by calling the setContentType() method on the EbiResponse interface in the Framework subsystem.

IMPORTANT:   Modes are based on content types. Therefore, It is strongly recommended that you set the content type before you set the mode in the doView(), doEdit(), and doHelp() methods—or in the render() method—of your portlet. This order of operations allows exteNd Director to validate modes against content type.

 
Top of page

Synchronous versus asynchronous processing

You can set portlets to run synchronously or asynchronously. In exteNd Director, portlets run asynchronously by default. Each portlet runs in its own thread so content rendering can occur in parallel. The exteNd Director portal waits for each portlet on a page to complete the render operation or to time out (whichever comes first), then aggregates the rendered output onto the page.

Here are guidelines for determining whether portlets should run synchronously or asynchronously:

If you determine that one or more portlets should not run asynchronously in your environment, you can disable asynchronous portlet rendering, as described in the section on turning off asynchronous portlet rendering.

 
Top of section

Asynchronous rendering of portlets

Asynchronous rendering of portlets is controlled by property settings in the following files:

This section describes the various settings that control asynchronous rendering.

NOTE:   The service.xml and config.xml files for the Framework are located in WEB-INF\lib\ConfigService\FrameworkService-conf. The config.xml file for the Portal is located in WEB-INF\lib\ConfigService\PortalService-conf\config.xml.

Portlet thread pool settings

The service.xml file for the Framework specifies which class should be loaded as the thread pool implementation. The thread pool implementation class implements the EbiThreadPoolManager interface:

  <service>
  	 <interface>com.sssw.fw.api.EbiThreadPoolManager</interface>
  	 <impl-class>com.sssw.fw.core.EboThreadPoolManagerImpl</impl-class>
  	 <description>The thread pool manager for dealing with multithreading</description>
  	 <max-instances>1</max-instances>
  	 <startup>M</startup>
  </service>

The max-instances setting is ignored. This class is always handled as a singleton.

The config.xml file for the Framework specifies several parameters that control the behavior of the thread pool:

  <property>
          <key>com.sssw.fw.api.threadpool.buffersize</key>
          <value>10</value>
      </property>
      <property>
          <key>com.sssw.fw.api.threadpool.maxthreads</key>
          <value>100</value>
      </property>
      <property>
          <key>com.sssw.fw.api.threadpool.minthreads</key>
          <value>4</value>
      </property>
      <property>
          <key>com.sssw.fw.api.threadpool.initialthreads</key>
          <value>10</value>
      </property>
      <property>
          <key>com.sssw.fw.api.threadpool.keepalifetime</key>
          <value>300000</value>
      </property>
      <property>
          <key>com.sssw.fw.api.threadpool.enabled_at_startup</key>
          <value>true</value>
      </property>

Each of these settings is described below:

Property

Description

com.sssw.fw.api.threadpool.buffersize

Defines how many portlet render requests should be buffered if the pool is busy.

Once this limit is reached, the pool will no longer accept new render requests until it frees up again.

Incoming requests will be diverted to the calling thread. In the case of the exteNd Application Server, this is the server's client thread.

com.sssw.fw.api.threadpool.maxthreads

The maximum number of threads to which the thread pool can grow.

com.sssw.fw.api.threadpool.minthreads

The minimum number of threads that will always be kept in the pool.

com.sssw.fw.api.threadpool.initialthreads

The number of threads immediately available in the pool after the pool has been started.

com.sssw.fw.api.threadpool.keepalifetime

The time (in milliseconds) a thread will be kept alive when it is idle.

com.sssw.fw.api.threadpool.enabled_at_startup

Determines whether the thread pool is enabled. This property must set to true if you want the thread pool to be enabled.

If the thread pool is disabled, all parallel processing defaults to synchronous processing

Portal settings

The config.xml file for the Portal includes several properties that control asynchronous processing for the Portal as a whole:

  <property>
   <key>com.novell.afw.portal.aggregation.default_request_timeout </key>
   <value>2000</value>
  </property>
  <property>
   <key>com.novell.afw.portal.aggregation.max_request_timeout</key>
   <value>2500</value>
  </property>
  <property>
   <key>com.novell.afw.portal.aggregation.render_synch_in_main_thread </key>
   <value>true</value>
  </property>

Each of these settings is described below:

Property

Description

com.novell.afw.portal.aggregation.default_request_timeout

This is the default time (in milliseconds) that a request will wait before it times out.

If none of the asynchronous portlets defines a timeout, or none of the portlets defines a timeout that is bigger then this value, this default value will be used.

If one or more of the portlets to render defines a timeout that is bigger than this default value, the bigger one will be used instead of the default.

This setting can be used to protect the application from getting too many messages indicating that portlets have timed out (which might happen if the portlet's descriptor, novell-portlet.xml, defines values that are too small).

NOTE:   In the event that all portlets can be rendered before this default timeout occurs, the request will immediately return to the client.

com.novell.afw.portal.aggregation.max_request_timeout

This is the maximum time (in milliseconds) that a request will be held back from finishing. This means that after this amount of time, every request will return to the client, regardless of whether any portlet defines a bigger timeout value.

This setting can be used to make sure that the Portal responds in a timely fashion even if one or more of the portlets define a large timeout value.

com.novell.afw.portal.aggregation.render_synch_in_main_thread

Determines whether synchronous portlets are executed within the application server's client thread.

This is set to true by default, meaning that all synchronous portlets are executed in the application server's client thread.

Setting this property to true can present some problems. For example, if one of the synchronous portlets uses an IO operation and blocks on a Socket read indefinitely, the application server thread will be blocked indefinitely as well. To prevent the application server's client thread pool from such a situation, you can set this property to false.

When this property is set to false, all synchronous portlets are still be processed sequentially by the same thread, but get a new thread from the portlet thread pool, so they don't execute in the application server's client thread.

Portlet max-timeout setting

The novell-portlet.xml file includes a property called max-timeout that determines the maximum timeout interval for each portlet:

  <portlet name="StockQuotePortlet">
   <style>
    <name>StockQuotePortletDefault</name>
    <display-name>Default StockQuote Portlet Style</display-name>
    <user-agent>
     <device-name>Generic_HTML</device-name>
     <file-name>$RESOURCE_SET$/portlet-style/StockQuote.xsl
     </file-name>
    </user-agent>
   </style>
    <requires-authentication>0</requires-authentication>
    <auto-register enabled="true">
     <category>General Portlets</category>
    </auto-register>
    <max-timeout>1000</max-timeout>
  </portlet>

The max-timeout property sets the maximum time (in milliseconds) that the Portal should wait for a portlet's render request to finish.

NOTE:   A value of 0 is interpreted as -1, which indicates that this portlet does not have a timeout value and the default request timeout will be applied.

How the request timeout is determined

The timeout of a request is determined as follows:

  1. The timeout of each asynchronous portlet is read and the greatest value is determined.

  2. If the value from step 1 is between the default_request_timeout and the max_request_timeout, it will be used as this request's maximum timeout.

  3. If the value from step 1 is below the default_request_timeout, the timeout for this request will be set to the default_request_timeout.

  4. If the value from step 1 is above the max_request_timeout value, the max_request_timeout value will be used as the timeout value for the current request.

The max_request_timeout setting applies to synchronous portlets, as well as asynchronous portlets. Since synchronous portlets are processed sequentially, the timeout is checked after each portlet returns. If the max_request_timeout value is reached, no new render process is started and the default timeout message is used as the portlet's content for all remaining, unprocessed synchronous portlets.

NOTE:   You should not confuse the request timeout settings with the expiration cache setting in the portlet.xml file. The expiration cache setting is used for content caching.

 
Top of page

Getting information about portlets

This section describes how to get information about portlet preferences and settings.

 
Top of section

Getting and storing portlet preferences

exteNd Director provides a flexible paradigm that allows you to apply portlet preferences at four levels of priority, listed here from lowest to highest priority:

For more informationFor more information, see the section on portlet preferences.

To get and set preferences, you typically call methods on the standard javax.portlet.PortletPreferences interface. These methods get and set values for any given preference at the highest level of priority that is available.

For more advanced customization—for example to get and set preferences at specific levels of priority—see the methods provided by the EbiPortletInfoManager.

 
Top of section

Getting and setting portlet settings

exteNd Director defines a group of settings that determine how portlets interact with the portal, as described in the section on portlet settings. You can get and set these values by calling methods on the EbiPortletSettings interface.

 
Top of page

Styling portlets that generate XML content

In exteNd Director, you can style a portlet that generates XML content by specifying the <style> element in the novell-portlet.xml deployment descriptor or in the associated portlet fragment deployment descriptor.

You can specify one <style> element per portlet, but each style can contain multiple user agents that point to device-specific XSL style sheets.

For more informationFor more information about how to specify the <style> element, see the section that presents a look inside novell-portlet.xml or look at the novell-portlet.xml schema in:

  extend5 install directory\Common\Resources\SchemaCatalog\novell-portlet.xsd

 
Top of page

Default implementation for Edit mode

exteNd Director provides a default implementation for Edit mode.

If you enable the Edit option for a portlet, but don't support the Edit mode explicitly, exteNd Director displays a preference sheet of all the preferences that have been defined for the portlet and that can be edited by the end-user.

If you want to use this default implementation, follow these guidelines:

IMPORTANT:   If you enable the Edit option and do support the Edit mode by implementing a doEdit() method, be sure to enable the Edit mode and Edit option in the portlet fragment deployment descriptor as follows:

 
Top of page

Specifying a secure port for portlet URLs

When you create a render or action URL by calling the appropriate method on javax.portlet.RenderResponse, you can set whether or not the URL is a secure URL by calling PortletURL.setSecure(true).

By default, the secure port is 443. If you have configured your server to use a different secure port, you can instruct the exteNd Director portal to use your port when creating portlet URLs. add a property to the PortalService config.xml as follows:

Procedure To specify a secure port for portlet URLs:

 
Top of page

Getting and setting cookies on a portlet

The exteNd Director API allows you to get and set cookies on a portlet by using methods in the EboCookieUtil class of the Framework subsystem.

To get cookies, you can call methods that propagate headers from the HTTP request down to the portlet request properties:

Method

Description

getCookieValue()

Gets the value of a specified cookie

getCookie()

Gets a specified cookie from the HTTP request

getCookies()

Returns an array of cookies from the HTTP request

To set cookies, you can call the addCookieToResponse() method, which propagates the set-cookie header from the PortletResponse properties to the HTTP response back to the client.

You can also get and set cookies by using the Request and Response scoped paths, as described in the chapter on working with scoped paths and XPaths.



Copyright © 2003 Novell, Inc. All rights reserved. Copyright © 1997, 1998, 1999, 2000, 2001, 2002, 2003 SilverStream Software, LLC. All rights reserved.  more ...