Showing posts with label Portlet. Show all posts
Showing posts with label Portlet. Show all posts

Thursday, July 05, 2012

Portlet life cycle

 

init(PortletConfig config)
This method is called by the portlet container on the abstract portlet when the
portlet is first loaded. As with servlets, portlets are loaded when they are first
requested. Any subsequent calls to the portlet will not execute this method.
Generally, initialization that is applicable to every concrete portlet based on this
abstract portlet is placed in this method. If you choose to override this method, at
a minimum it should make a call to its parent via super.init(portletConfig). At
this point in the portlet life cycle, no portlet-specific storage objects are available.

initConcrete(PortletSettings settings)
This method is called by the portlet container on the concrete portlet. The
initialization code performed in this method is not shared by other concrete
portlets even though they may be based upon the same abstract portlet. It is in
this method that the PortletSettings object is first available. The PortletSettings
encapsulates the concrete portlet configuration parameter information. From the
PortletSettings object, the PortletApplicationSettings object is available. The
PortletApplicationSettings object encapsulates concrete portlet application
context parameters. In this method, no user-specific objects are yet available.

login(PortletRequest request)
If the concrete portlet has been placed on a page that requires authorization, the
login method is called by the portlet container to associate a user with the portlet.
It is at this point that the PortletData object is first available. The PortletSession is
created by the container for the registered user at this point and is available in
this method via the request object. If the request for the portlet is made by an
anonymous user, this method is not called. If this method is not called, a default
session object can still be created with no user association, though it may be of
little practical use. This method is actually defined in the PortletSessionListener
interface which is implemented by the abstract class Portlet. Since your custom
portlets will extend from Portlet, it is included in this discussion even though other
oft-used listeners are not.

service(PortletRequest request, PortletResponse response)
This method is called on each and every request of the portlet. After the portlet
has been added to a page and initially accessed by a user, this is the only
method that will be called by the portlet container on subsequent requests.
Generally, this method will delegate the request to the appropriate do method to
render content. At this point, all portlets and, if applicable, user-specific objects
are available.

logout(PortletSession session)
Only when a user specifically selects the Log Off button on the portal is this
method called. This method provides you with the opportunity to manage any
user-specific information once the user has logged out and to clean up
user-related resources. If the user removes the portlet from their page, the logout
method is not called until the user actually logs out of the portal, even though
they no longer are accessing the portlet. When the portlet is taken out of service
by the Portal server or the administrator, this method will not be called. The
PortletSettings object is still available in this method, although the PortletRequest
is not. This method is actually defined in the PortletSessionListener interface
which is implemented by the abstract class Portlet. Since your custom portlets
will extend from Portlet, it is included in this discussion even though other
oft-used listeners are not.

destroyConcrete(PortletSettings settings)
This method is called when the concrete portlet is taken out of service either
because of the portal server stopping or the application being uninstalled from
the portal server. The portlet container will call each running concrete portlet in
the application individually when the application is deleted. In this method, the
PortletSettings object is passed in as a parameter and cannot be retrieved from
the normal getPortletSettings method.

destroy(PortletConfig config)
The portlet container executes this method on the abstract portlet when the
portlet is taken out of service. Since it is executed on the abstract portlet and not
the concrete portlets, it is executed only once. This method provides an
opportunity to execute clean-up code on each and every concrete portlet in the
application derived from this abstract portlet.

Wednesday, July 04, 2012

JSR 168 vs IBM Portlet API

The following concepts are very similar in JSR 168 and the IBM Portlet API.
Feature Similarities Differences
Portlet modesBoth support the basic portlet modes: Edit, Help, and View.The config mode is optional in the JSR 168. The other optional JSR 168 modes (About, Edit_defaults, Preview, Print) are not supported by the IBM Portlet API.
Window statesThese window states are supported: Maximized, Normal, and Minimized.The Solo window state is only supported by the IBM Portlet API.
Portlet lifecycleThe lifecycle life cycle is the same: init, process requests, destroy.none
Request processingRequest processing is divided into an action phase for processing user actions and a render phase for producing the markup. none
URL encodingBoth support creating URLs pointing to the portlet or to a resource.none
Include servlets/JSPsServlets and JSPs can be included in the portlet.none
Portlet sessionPortlets can store transient information that should span requests in a session.none
Portlet application packagingBoth package portlet applications as WAR files with an additional deployment descriptor called portlet.xml.The portlet.xml format differs.
Expiration-based cachingThe portlet can support expiration based caching.The APIs use different mechanisms to implement this functionality.
The IBM Portlet API uses a polling mechanism where the portal queries the portlet for how long the markup will be valid, whereas in the JSR 168 the portlet can attach an expiration time to each created markup. Sharing the cache entry across users is only possible in the IBM Portlet API.

Differences
The JSR 168 and the IBM Portlet API differ in the following ways.
Feature IBM Portlet API JSR 168
Portlet application entitiesLets you define an abstract portlet application and different instance of this portlet application as concrete portlet applications via the deployment descriptor. This allows reusing settings of the abstract portlet application and only overwriting the parts that are unique for each concrete portlet application. The deployment descriptor follows the web.xml deployment descriptor and defines one portlet application and the portlet definitions for this application.
Portlet entityThere is one portlet object instance per portlet configuration in the Web deployment descriptor. There may be many PortletSettings objects parameterizing the same portlet object according to the Flyweight pattern, provided on a per-request basis. Changes in the PortletSettings apply to all portlet instances of this concrete portlet. The user can also have personal views of concrete portlets that are rendered using the PortletData for customization of the output. PortletSettings and PortletData are merged into one object called PortletPreferences.
Request/Response objectsThe request/response object that the portlet receives in the render call is the same as the one received in the action call. In the JSR 168 these are two different objects.
Exclusive to JSR 168
These items are only available in the JSR 168.
Feature Description
Render parametersRender parameters allow the portlet to store its navigational state.
Render parameters stay the same for subsequent render requests and only change when the portlet receives a new action. This enables bookmarkability and solves the browser back button problem.
Global HttpSession scopePortlets can store data not only with the visibility of the portlet, but also with the visibility of the whole Web application.
RedirectPortlets can redirect to other Web resources in the action phase.
Exclusive to the IBM Portlet API
The following concepts are only available in the IBM Portlet API.
Feature Description
EventingEvents can be sent between portlets.
Additional lifecycle listenersLifecycle listeners besides action and render, (such as begin page) are not available in the first version of the JSR 168.
Portlet menusLets the portlet contribute content to a menu bar to facilitate navigation through portal pages.
Invalidation based cachingLets the portlet explicitly invalidate cached content.
Example Portlets
This section shows a HelloWorld portlet implemented in each of the two APIs. The key differences are highlighted in the second portlet.
The two example portlets implement the same functions:
  • Use JSPs for rendering the output
  • Customize the portlet output, based on user-specific data
  • Handle actions to allow the user to change these
This example shows a hello world portlet which uses personalization. It addresses the user by name, and it allows the user into edit mode to set a new user name. In the action method (called actionPerformed in the IBM Portlet API and processAction in JSR 168), the portlet persistently stores the new user name which the user enters.

 IBM Portlet API example portlet
First look at the portlet implemented using the IBM Portlet API.
public class HelloWorld extends AbstractPortlet implements ActionListener
{
€¦
  public void doView (PortletRequest request, PortletResponse response)
   throws PortletException, IOException
    {
   //Get the user's name to display from persistent storage
   PortletData portletData = request.getData();
   String stringToDisplay=(String)portletData.getAttribute("userName");

   if (stringToDisplay == null) {
       stringToDisplay = defaultString;    // set default string
   }

   // Add the display string to the portlet request to make it 
   // accessible by the view JSP
   request.setAttribute("userName", stringToDisplay);

   // Get a context for the current session for invoking the JSP
   PortletContext context = getPortletConfig().getContext();
   context.include(viewJSP, request, response);
    }

    public void doEdit(PortletRequest portletRequest, 
        PortletResponse portletResponse )
      throws PortletException, IOException
    {
   // Create the cancel return URI for the edit page
   PortletURI cancelURI = portletResponse.createReturnURI();
   // Preserve the Cancel URI in the request to make it 
   // accessible by the edit JSP
   portletRequest.setAttribute("cancelURI", cancelURI.toString());

   // Create the save URI for the edit page
   PortletURI saveURI = portletResponse.createReturnURI();
   // For the "Save" button the return URI must include the "Save" action
   //    so the Action Listener for this portlet will be invoked       
   SimpleActionHelper.
   addSimplePortletAction(getPortletConfig().getContext(), saveURI, "save");

   // Preserve the Save URI in the request to make it accessible by 
   // the edit JSP
   portletRequest.setAttribute("saveURI", saveURI.toString());

   //Get the user's name to display from persistent storage
   String stringToDisplay = (String) 
        portletRequest.getData().getAttribute("userName");
   if (stringToDisplay == null) {
       stringToDisplay = defaultString;    // none found, set default string
   }

   // Add the display string to the request to make it accessible by the 
   // edit JSP as an inital value of the input field on the edit form
   portletRequest.setAttribute("userName", stringToDisplay);

   // Get a context for the current session for invoking the JSP
   PortletContext context = getPortletConfig().getContext();
   context.include(editJSP, portletRequest, portletResponse);
    }
    
public void actionPerformed(ActionEvent event) {
    String action = 
    SimpleActionHelper.getActionString(getPortletConfig().getContext(),
            event);
    HelloWorld helloPortlet = (HelloWorld)event.getPortlet();
    PortletLog log = helloPortlet.getPortletLog();

    // If this is a save action, then see if the user specified a name
    if ( action!=null ) {
      if ( action.equals("save") ) {
       PortletRequest request = event.getRequest();
       PortletData portData = request.getData();
       String userName = request.getParameter("userName");
       try {
       // Save the name specified by the user
         if ( userName != null ) {
         portData.setAttribute("userName", userName);
         portData.store();
      }
      } catch ( AccessDeniedException ade ) {
      } catch ( IOException ioe ) {
       log.error( "
     Couldn't write the user date to 
persistence because an I/O Error occurred.
    " );
      }
     }
    }
  }
}     


JSR example portlet
Now, look at the same portlet that has been modified to use JSR 168. The changed text is marked in bold.
public class HelloWorld extends GenericPortlet
{
€¦
  public void doView (RenderRequest request, RenderResponse response)
   throws PortletException, IOException
   {
   //Get the user's name to display from persistent storage
   PortletPreferences portletData = request.getPreferences();
  String stringToDisplay = (String) portletData.getValue("userName",defaultString);

   // Add the display string to the portlet request to make it 
   // accessible by the view JSP
   request.setAttribute("userName", stringToDisplay);

   // Get a context for the current session for invoking the JSP
   PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher(viewJSP);      
   rd.include(request, response);

    }
    public void doEdit(RenderRequest portletRequest, 
        RenderResponse portletResponse )
      throws PortletException, IOException
    {
   // Create the cancel URI for the edit page
   PortletURL cancelURI = portletResponse.createActionURL();

   // Preserve the Cancel URI in the request to make it 
   // accessible by the edit JSP
   portletRequest.setAttribute("cancelURI", cancelURI.toString());

   // Create the save URI for the edit page
   PortletURL saveURI = portletResponse.createActionURL();

   // For the "Save" button the return URI must include the "Save" action
   // so the Action Listener for this portlet will be invoked
   saveURI.setParameter("action", "save");

   // Preserve the Save URI in the request to make it accessible by 
   // the edit JSP
   portletRequest.setAttribute("saveURI", saveURI.toString());

   //Get the user's name to display from persistent storage
   String stringToDisplay = portletRequest.getPreferences().getValue("userName", 
                             defaultString);

   // Add the display string to the request to make it accessible by the edit JSP
   // as an inital value of the input field on the edit form
   portletRequest.setAttribute("userName", stringToDisplay);

       // Get a context for the current session for invoking the JSP
   PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher(editJSP);
   rd.include(portletRequest, portletResponse);
    }

  public void processAction(ActionRequest request, ActionResponse response) 
    throws PortletException, IOException 
  {
    String action = request.getParameter("action");

  // If this is a save action, then see if the user specified a name
  if ( action!=null ) {
      if ( action.equals("save") ) {
   PortletPreferences portData = request.getPreferences();
   String userName = request.getParameter("userName");
   // Save the name specified by the user
   if ( userName != null ) {
     portData.setAttribute("userName", userName);
     portData.store();
   }
  }  

The major differences to the IBM Portlet API version of the portlet are:
  1. Request dispatcher usage The request dispatcher usage differs slightly between JSR 168 and the IBM Portlet API. JSR 168 uses the same mechanism to get a request dispatcher from context with the path as parameter as the servlet API.
  2. Persistent portlet data JSR 168 persistent data, PortletPreferences, have an API similar to the JDK 1.4 Preferences and allows specifying a default value for the get methods. The code to check for a null return value and explicitly set a default value are no longer necessary . JSR 168 only allows String and String arrays as values of preferences; arbitrary objects are allowed by the IBM Portlet API.
  3. Action handling The action handling in JSR 168 is simplified and does not need specific action objects to be created. Creating an action URL automatically triggers a call to the processAction method.