Portlet Lifecycle

Filed Under: Portal and Portlets

As we’ve seen previously, Portlet is conceptually very similar to Servlet as they can only operate within a container. Both Servlet and Portlet have an obligations that their design must satisfy to allow them interact with their containers.

As you should implement doGet(), doPost(), doDelete(), etc, you must also implement the Portlet’s specific methods like doView(), doHelp(), doEdit(), etc.

Let’s firstly starting by developing our first Portlet by implementing the Portlet interface than using of GenericPortlet and highlights the most important things.

Following sections would help cover these concepts:

Implementing Portlet Interface

Generally, you can develop your Portlet by extending the GenericPortlet, any class that’s extending the GenericPortlet or by implementing the Portlet interface.


package com.journaldev.portlet;

import java.io.IOException;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.Portlet;
import javax.portlet.PortletConfig;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

public class LifecyclePortlet implements Portlet {
	private static int renderCount = 0;
	private static int actionCount = 0;
	private static int initCount = 0;

	@Override
	public void init(PortletConfig config) throws PortletException {
		initCount++;
	}
	@Override
	public void processAction(ActionRequest request, ActionResponse response)
			throws PortletException, IOException {
		synchronized(this){
			actionCount++;
		}
	}
	@Override
	public void render(RenderRequest request, RenderResponse response)
			throws PortletException, IOException {
		synchronized(this){
			renderCount++;
		}

		response.getWriter().print("<form action="+response.createActionURL()+">"
				+ "<p> The number of initiated Portlets by the container is :: "+initCount+"</p>"
						+ "<p> The number of processed actions by the container is :: "+actionCount+"</p>"
								+ "<p> The number of achieved render by the container is :: "+renderCount+"</p>"
									+"<input value='Submit' type='submit'/><br/>"
										+ "<a href='"+response.createRenderURL()+"'>Render Again</a>"
											+ "</form>");
	}
	@Override
	public void destroy() {
		initCount--;
		System.out.println("The number of Portlets get deployed :: "+initCount);
	}
}

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.journaldev</groupId>
	<artifactId>LifecyclePortlet</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>LifecyclePortlet</name>
	<url>http://maven.apache.org</url>
	<properties>
		<deployFolder>D:/Apache Pluto/pluto-2.0.3/webapps</deployFolder>
	</properties>
	<dependencies>
		<!-- Java Portlet Specification V2.0 -->
		<dependency>
			<groupId>org.apache.portals</groupId>
			<artifactId>portlet-api_2.0_spec</artifactId>
			<version>1.0</version>
			<scope>provided</scope>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<!-- bind 'pluto2:assemble' goal to 'process-resources' lifecycle -->
			<!-- This plugin will read your portlet.xml and web.xml and injects required
				lines -->
			<plugin>
				<groupId>org.apache.portals.pluto</groupId>
				<artifactId>maven-pluto-plugin</artifactId>
				<version>2.1.0-M3</version>
				<executions>
					<execution>
						<phase>generate-resources</phase>
						<goals>
							<goal>assemble</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
			<!-- configure maven-war-plugin to use updated web.xml -->
			<!-- This plugin will make sure your WAR will contain the updated web.xml -->
			<plugin>
				<artifactId>maven-war-plugin</artifactId>
				<version>2.1.1</version>
				<configuration>
					<webXml>${project.build.directory}/pluto-resources/web.xml</webXml>
				</configuration>
			</plugin>
			<plugin>
				<artifactId>maven-antrun-plugin</artifactId>
				<executions>
					<execution>
						<id>copy</id>
						<phase>integration-test</phase>
						<configuration>
							<tasks>
								<copy file="target/${project.build.finalName}.war" tofile="${deployFolder}/${project.build.finalName}.war" />
							</tasks>
						</configuration>
						<goals>
							<goal>run</goal>
						</goals>
					</execution>
					<execution>
						<id>delete</id>
						<phase>clean</phase>
						<configuration>
							<tasks>
								<delete file="${deployFolder}/${project.build.finalName}.war" />
								<delete dir="${deployFolder}/${project.build.finalName}" />
							</tasks>
							<detail>true</detail>
						</configuration>
						<goals>
							<goal>run</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.1</version>
				<configuration>
					<source>1.7</source>
					<target>1.7</target>
				</configuration>
			</plugin>
		</plugins>
	<finalName>${project.artifactId}</finalName>
	</build>
</project>

portlet.xml


<?xml version="1.0" encoding="UTF-8"?>

<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
	version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd
                        http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd">

	<portlet>
		<description>First Portlet</description>
		<portlet-name>PortletOne</portlet-name>
		<display-name>First Portlet</display-name>

		<portlet-class>com.journaldev.portlet.LifecyclePortlet</portlet-class>

		<supports>
			<mime-type>text/html</mime-type>
			<portlet-mode>VIEW</portlet-mode>
		</supports>

		<portlet-info>
			<title>Lifecycle Portlet</title>
			<short-title>Lifecycle Portlet</short-title>
			<keywords>Lifecycle</keywords>
		</portlet-info>

	</portlet>	

	<portlet>
		<description>Second Portlet</description>
		<portlet-name>PortletTwo</portlet-name>
		<display-name>Second Portlet</display-name>

		<portlet-class>com.journaldev.portlet.LifecyclePortlet</portlet-class>

		<supports>
			<mime-type>text/html</mime-type>
			<portlet-mode>VIEW</portlet-mode>
		</supports>

		<portlet-info>
			<title>Lifecycle Portlet</title>
			<short-title>Lifecycle Portlet</short-title>
			<keywords>Lifecycle</keywords>
		</portlet-info>

	</portlet>
</portlet-app>

Here’s detailed explanation for code listed above:

  • Executing mvn clean integration-test package will get your project to be packaged and deployed against your Apache Pluto.
  • LifecyclePortlet has implemented the Portal interface, as it’s obvious all contract methods must be implemented.
  • Portlet deployment descriptor portlet.xml has defined two different Portlets that are referenced the same Portlet class. Such that deployment is acceptable as it can be deployed any number of Portlets that refer the same Portlet class with different names. It could also be to deploy two Portlets have the same name but make sure you are got deployed them into two different contexts.
  • When it create a Portlet by implementing Portlet interface, render(), processAction(), init(), destroy() should be overridden.
  • When the Portlet get deployed, the Portlet container would call the init() at the initialization phase.
  • When the client has activated submit button that’s displayed at the Portlet, the Portlet container has received such that call and it’s called processAction() method by its turn.
  • When the client has activated the renderAgain link that’s rendered at the Portlet, the Portlet container has received such that call and it’s called render() method by its turn.
  • If you’ve execute mvn clean against LifecyclePortlet project, you should notice that your WAR file and its un-packaged format (WAR folder) are deleted. Deletion the context will cause that your defined Portlets to be destroyed.
  • To get your WAR file removed a new execution has been added at the maven-antrun-plugin.

Portlet Lifecycle

Portlet Lifecycle Project Deployment Console Messages

Now, let’s see what might happen if we have removed the deployed WAR and its unpackaged folder. Absolutely, removing your deployed application will get the context listener to be invoked as it will destroy the all resources that are deployed including these defined Portlets inside the portlet.xml file.

Portlet Clean deployed project

Portlet Lifecycle context destruction console messages

As we have two deployed Portlets (PortletOne, PortletTwo), we print out the numbers of remaining Portlets inside the destroy() method. This method has invoked similar to Servlet’s destroy() method that’s invoked once the contained project has undeployed.

If you’ve looked deeply at the console messages, you should notice the Portlet context /LifecyclePortlet-0.0.1-SNAPSHOT be removed. Usually, the concepts of undeploy and context removal are used interchangeably.

Portlet Lifecycle

As simple as that, we can break down the Portlet lifecycle into these below stages:

  • Creation of Portlet.
  • Processing of a number of user requests (or it might be none).
  • Removal and garbage collection of the Portlet.

Let’s delve thoroughly to discuss these stages deeply.

Portlet Creation Stage

The creation of the Portlet is the most expensive and complicated phase among mentioned phases as it consists of three distinct steps: loading the classes, invoking the constructors and initializing the Portlet.

Generally, the container is able to load the classes required by the Portlet before constructor invocation. The Portlet that’s loaded is considered as a minor part in compare with the whole application that might contain a lot of classes and libraries. As such the specification demands that the loading of the Portlet class must be done using the same classloader as the rest of the Portlet application that the loaded Portlet referred to.

The Portlet container may decide to create an instance of your loaded Portlet’s class either when the Portlet container starts the Portlet application (WAR) or when the container determines that Portlet is used to serve certain request.

The most important thing that you must take care of is the time needed of Portlet’s resources to be initialized, for which the Portlet would wait until it’s finished to serve the first request. Once the first request has served, every request that’s coming after so would be served normally.

While initialization the Portlet is passed an Object instance of PortletConfig interface that’s considered unique to the Portlet definition and provides access to the initialization parameters and the resource bundle configured for the Portlet in the Portlet definition.

Until the init() method has been invoked successfully, the Portlet isn’t considered as an active Portlet. In case your Portlet class has provided some of static initialization blocks, they must not trigger any methods that make this assumption.

You can use the Portlet configuration object (PortleConfig) for providing a lot of configurations that’s meant for the Portlet itself like a database connection URL and others.

Init() method is error-prone by its nature, you may access a database that’s already down or you don’t have a proper permission over it. For such cases, init() has defined as it throws a PortletException. You may also can throw an UnavailableException in between, but regardless of the exception type being thrown, you must ensure that all resources that been acquired are released as the destroy() method won’t be called subsequently. However, failure of initialization does mean that the Portlet container won’t place the Portlet object into active service and it must release the Portlet object.

According to Java Portlet Specification 2.0, the Portlet container may reattempt to instantiate and initialize the Portlets at any time after failure. In case you’ve used UnavilableException and provided a wait time, the Portlet container must wait for the specified time before creating and initializing a new Portlet object. Practically, this feature

In case you’ve got a RuntimeException during initialization, it must be handled as a PortletException.

Request Handling Stage

Once the Portlet get initialized, it’s become waiting for users interactions. The interactions with the Portlets can be done through set of requests, these requests are translated into render() and processAction() requests.

Action requests are are asking the Portlets to change the state of its underlying application, while the render requests are displaying the Portlet with its current states. Practically, a subsequent render() request has been initiated once the processAction() got finished.

As we’ve stated previously, you can make a render request and action request by calling createRenderURL() and createActionURL() respectively against passed response object.

Generally, RenderRequest that’s passed for render() method is responsible for providing:

  • The state of the Portlet window (minimized, maximized, etc.)
  • The mode of the Portlet (e.g VIEW, EDIT, etc.)
  • The context of the Portlet.
  • The session associated with the Portlet (including authorization information).
  • The preferences information associated with the Portlet.
  • Any render parameters that have been set on a render URL from a posted form or that have been set during the processAction() method.

RenderResponse is also responsible of writing the Portlet’s content fragment into Portal page as it’s also capable to render URLs into that content, which will invoke actions to the Portlet (e.g createActionURL(), createRenderURL(), etc).

ActionRequest object represents the opportunity to change the state of the Portlet, it provides everything that’s already offered by PortletRequest along with direct access to the content of the HTTP request made by the user of the Portal. To respond to processAction() the Portlet should update its ActionResponse object which provides methods to:

  • Redirect the client to a new Page.
  • Change the mode of the Portlet.
  • Add or modify rendering parameters for the user’s session.

The processAction() proposed above makes a trivial change for the actionCount counter and so it doesn’t have to inform the container of any changes via the response. Following sample shows you how can use the ActionResponse to make a change in the response.


package com.journaldev.portlet;

import java.io.IOException;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.Portlet;
import javax.portlet.PortletConfig;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

public class LifecyclePortlet implements Portlet {
	private static int renderCount = 0;
	private static int actionCount = 0;
	private static int initCount = 0;

	@Override
	public void init(PortletConfig config) throws PortletException {
		initCount++;
	}
	@Override
	public void processAction(ActionRequest request, ActionResponse response)
			throws PortletException, IOException {
		synchronized(this){
			actionCount++;
		}
		response.sendRedirect(request.getContextPath()+"/index.html");
	}
	@Override
	public void render(RenderRequest request, RenderResponse response)
			throws PortletException, IOException {
		synchronized(this){
			renderCount++;
		}

		response.getWriter().print("<form action="+response.createActionURL()+">"
				+ "<p> The number of initiated Portlets by the container is :: "+initCount+"</p>"
						+ "<p> The number of processed actions by the container is :: "+actionCount+"</p>"
								+ "<p> The number of achieved render by the container is :: "+renderCount+"</p>"
									+"<input value='Submit' type='submit'/><br/>"
										+ "<a href='"+response.createRenderURL()+"'>Render Again</a>"
											+ "</form>");
	}
	@Override
	public void destroy() {
		initCount--;
		System.out.println("The number of Portlets get deployed :: "+initCount);
	}

}

index.html


<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>ActionResponse Sample</title>
</head>
	<body>
		<p>ActionResponse redirects the client into this page</p>
	</body>
</html>

Portlet Lifecycle ActionResponse - Redirect Facility

Here’s some of important points need to notice:

  • Determine of context path of Portlet application has been done through using of ActionRequest.
  • ActionResponse does redirect the action request to be served by using different content (i.e index.html).

Portlet Destroying Stage

As we’ve stated earlier, the destroy() method won’t be invoked as a subsequent phase when the initialization phase is failed. To allow Portlet container from destroying a certain Portlet, the Portlet must be instantiated and initialized successfully and all processing threads on the Portlet’s instance have completed.

If you’ve integrated with third parties, the destroy() method is the best place to notify those third parties about the Portlet is becoming unavailable. According for Java Portlet Specification 2.0, after destroy() method completes, the Portlet container must release the Portlet object so that it’s eligible for garbage collection. Portlet implementations shouldn’t use finalizers.

Threading Issues

According to Java Portlet Specification 2.0, The Portlet container is able to handle the requests concurrently. Portlet developers must design their Portlets to handle concurrent execution from multiple threads from within the processAction() and render() methods or any of the optional lifecycle methods, like prcoessEvent() or serveResource(), at any particular time.

Actually, implementations of the request and response objects aren’t guaranteed to be thread safe. This means that they must only be used within the scope of thread invoking the processAction(), render(), processEvent() and serveResource() methods.

To remain Portable, Portlet applications shouldn’t give references of the request and response objects to objects executing in other threads as the resulting may be non-deterministic.

In other words, any combination and number of simultaneous calls to render() and/or processAction() would be safe unless the Portlet has used an instance variables and/or external resources.

As we’ve stated earlier at the provided sample, all counters had defined as an instance variables and so, they’re not safe when it comes to be processed by concurrent threads. For handling increments for all of them concurrently, we’ve stated them within a synchronized block.

Portlet Lifecycle Summary

Similar for Servlet, user requests for Portlet are handled through well-defined lifecycle that’s maintained by the Portlet container. This tutorial has focused on the lifecycle and its details as well as for threading issue. Contribute us by commenting below and find downloaded source code.

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages