Portlet Concepts Detailed Examples Tutorial – PART II

Filed Under: Portal and Portlets

At the Portlet concepts detailed Tutorial – PART I, we’ve explained a lot details about concepts like PortletRequest, PortletResponse, RenderRequest, ActionRequest, RenderResponse, ActionReponse and all their respective functionality as we saw how can they play roles when they’re coming to handle users’ requests.

This tutorial is a follow-up for what already we’ve started at the PART-I. Portlet Context, Sessions, Inter-portlet communication and Caching, all of these concepts would be discussed here as well as a set of samples have to be introduced making these concepts very simple to understand.

Portlet Context

Just like Servlets, Portlet uses the Portlet Context object to get access for logging, resources, attributes, and initialization parameters that are defined in the Portlet application (WAR).

The Portlet context object is available for every deployed Portlet application, in case you’ve deployed more than one Portlet in the Portlet application, they can share the Portlet context object as they can use it for set or retrieve application-wide data.

Similar for Servlets and JSPs, they are also sharing the Portlet context instance through using of ServletContext. In case you’ve provided a Servlets and JSPs inside your Portlet application, they (Portlets, JSPs, Servlets) are able of getting the same Portlet context.

Following sample shows you a simple demonstration of how can access the Portlet context from within different resources got deployed at the same Portlet application.

HelloPortlet.java


package com.journaldev.portlet;

import java.io.IOException;

import javax.portlet.GenericPortlet;
import javax.portlet.PortletConfig;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

public class HelloPortlet extends GenericPortlet{

	public void init(PortletConfig config) throws PortletException {
		super.init(config);
		// Set variable along context scope
		config.getPortletContext().setAttribute("anonymousVariable", "Just Variable");
	}

	public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException{
		response.getWriter().print("<p>Hello Portlet</p>");
	}
}

HelloServlet.java


package com.journaldev.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class HelloServlet
 */
public class HelloServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public HelloServlet() {
        super();
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.getWriter().print("<p>Portlet context anonymous variable value Is "+getServletContext().getAttribute("anonymousVariable")+"</p>");
	}

}

Set Context Variable Using Portlet ContextRead Portlet context variable via Servlet context object

Here’s detailed explanation for the code listed above:

  • You can get PortletContext instance by accessing getPortletContext() against config object that’s already provided by the Portlet container while init() the Portlet. Also, any Portlet that extends the GenericPortlet has the ability to access the Portlet context by calling this.getPortletContext() from anywhere inside the Portlet.
  • Setting variables along context scope would be accessible via all Portlets, Servlets and JSPs that are located within the same Portlet application (WAR).
  • Servlet context is the way that you must use for accessing the Portlet context variables as both of them is relevant for the same Portlet application. At the same way, Portlet context can be access any variables that already set by the Servlet context.
  • The attributes on the Portlet context are shared data for Portlets and Servlets in a Portlet application. These attributes are pairs of name/value, name is a String object and value is an Object that can be any type of objects inside your domain.
  • SetAttributes(), getAttributes(), getAttributesNames() and removeAttributes() are methods used for setting, reading and removing the attributes along context scope.

Context Initialization Parameters

Context initialization parameters are those variables defined inside web.xml file. As being of Portlets and Servlets can be defined at the same Portlet application, it’s also possible for the Portlet to access the context initialization parameters. Following sample is just a trivial update for the sample shown above, but this time a context parameter will be read by both of Servlet and Portlet.

HelloPortlet.java


package com.journaldev.portlet;

import java.io.IOException;

import javax.portlet.GenericPortlet;
import javax.portlet.PortletConfig;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

public class HelloPortlet extends GenericPortlet{

	public void init(PortletConfig config) throws PortletException {
		super.init(config);
	}

	public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException{
		response.getWriter().print("<p>Anonymous Context Variable Value Is "+this.getPortletContext().getInitParameter("contextParam")+"</p>");
	}
}

HelloServlet.java


package com.journaldev.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class HelloServlet
 */
public class HelloServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public HelloServlet() {
        super();
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.getWriter().print("<p>Portlet context anonymous variable value Is "+getServletContext().getInitParameter("contextParam")+"</p>");
	}

}

web.xml


<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <servlet>
  	<servlet-name>HelloServlet</servlet-name>
  	<servlet-class>com.journaldev.servlet.HelloServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>HelloServlet</servlet-name>
  	<url-pattern>/hello</url-pattern>
  </servlet-mapping>
  <context-param>
  	<param-name>contextParam</param-name>
  	<param-value>contextValue</param-value>
  </context-param>
</web-app>

Get context param from ServletGet context param from PortletHere’s detailed explanation for the code listed above:

  • It’s very trivial for getting context parameters accessed through Servlet. But you must use the PortletContext object that already passed to your Portlet for get read of context parameters.
  • Use of getInitParameterNames() against of PortletContext instance will list to you all defined context parameters.
  • Portlets may have their own initialization parameters that could be accessed via using of getInitParameter() against PortletConfig() object. You can find below sample Portlet deployment descriptor that has defined an initialization parameters.

portlet.xml


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

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

	<portlet>
		<init-param>
			<name>PortletParam</name>
			<value>ParamValue</value>
		</init-param>
		<display-name>Hello Portlet</display-name>
		<portlet-name>Hello</portlet-name>
		<portlet-class>com.journaldev.portlet.HelloPortlet</portlet-class>
		<description>Hello Portlet</description>
		<portlet-info>
			<title>Hello Portlet</title>
			<keywords>Hello, Portlet</keywords>
			<short-title>Hello Portlet</short-title>
		</portlet-info>
	</portlet>

</portlet-app>

Access Resources

Beside all of these discussed facilities that the PortletContext provides, it’s also applicable for you to access resources either defined within your web application or located at any path within your system folder using the getResource(), getResourceAsStream() and getRealPath(). Following sample shows you how can we use PortletContext object for reading resources that are defined differently.

HelloPortlet.java


package com.journaldev.portlet;

import java.io.IOException;
import java.io.InputStream;

import javax.portlet.GenericPortlet;
import javax.portlet.PortletConfig;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

public class HelloPortlet extends GenericPortlet{

	public void init(PortletConfig config) throws PortletException {
		super.init(config);
	}

	public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException{
		System.out.println("Got File :: "+this.getPortletContext().getResource("/index.html"));
		System.out.println("Got File :: "+this.getPortletContext().getRealPath("file:///c:/index.html"));
		InputStream input = this.getPortletContext().getResourceAsStream("/index.html");
		byte [] bytes = new byte[input.available()];
		input.read(bytes, 0, input.available());
		response.getPortletOutputStream().write(bytes);
	}
}

Reading ResourcesWriting read resources into Portlet output streamHere’s detailed explanation for code listed above:

  • Get resources is applicable via using of Portlet Context instance.
  • When it comes to read the resources via getResources or any methods relevant for, you should provide a forward slash before the remaining path.
  • GetRealPath is used for reading the files located at the externally (i.e outside of Portlet application).
  • GetResourcePaths() method it takes partial path as argument and returns all resources’ paths that start with the path.

Logging

The Portlet may write the messages using logging mechanism. Like Servlet logging, the location of the log messages is dependent on the implementation of the container as it may be file, database entry, console or any other way the container may choose.

Apache Pluto has been configured to print messages out onto your console. Apache has always preferred to use Apache’s Log4j instead of using default provided implementation. Following sample shows you how can we use both of APIs (either default logging messages or Log4j) for getting messages logged.

HelloPortlet.java


package com.journaldev.portlet;

import java.io.IOException;
import java.io.InputStream;

import javax.portlet.GenericPortlet;
import javax.portlet.PortletConfig;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

import org.apache.log4j.Logger;

public class HelloPortlet extends GenericPortlet{
	Logger logger = Logger.getLogger(HelloPortlet.class);

	public void init(PortletConfig config) throws PortletException {
		super.init(config);
	}

	public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException{
		this.getPortletContext().log("Got File :: "+this.getPortletContext().getResource("/index.html"));
		this.getPortletContext().log("Got File :: "+this.getPortletContext().getRealPath("file:///c:/index.html"));
		logger.debug("Got File :: "+this.getPortletContext().getResource("/index.html"));
		logger.debug("Got File :: "+this.getPortletContext().getRealPath("file:///c:/index.html"));
		InputStream input = this.getPortletContext().getResourceAsStream("/index.html");
		byte [] bytes = new byte[input.available()];
		input.read(bytes, 0, input.available());
		response.getPortletOutputStream().write(bytes);
	}
}

log4j.xml


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration debug="true"
	xmlns:log4j='http://jakarta.apache.org/log4j/'>

	<appender name="console" class="org.apache.log4j.ConsoleAppender">
	    <layout class="org.apache.log4j.PatternLayout">
		<param name="ConversionPattern"
		  value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
	    </layout>
	</appender>

	<appender name="file" class="org.apache.log4j.FileAppender">
		<param name="file" value="${catalina.home}/logs/log.log" />
	    <layout class="org.apache.log4j.PatternLayout">
		<param name="ConversionPattern"
		  value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
	    </layout>
	</appender>

	<root>
		<level value="ALL" />
		<appender-ref ref="console" />
		<appender-ref ref="file" />
	</root>

</log4j:configuration>

log.log


2014-09-22 21:31:26 DEBUG HelloPortlet:24 - Got File :: jndi:/localhost/PortletConceptsPartTwo/index.html
2014-09-22 21:31:27 DEBUG HelloPortlet:25 - Got File :: D:\Apache Pluto\pluto-2.0.3\webapps\PortletConceptsPartTwo\file:\c:\index.html

Logged Messages - Using Both of Default Apache Pluto Logging And Log4JLogging File - Log4j Auto Creation

Here’s important notes you should notice:

  • We’ve used default logging mechanism that’s provided by Apache Pluto, in that the messages will be logged out onto your console as you’ve seen with INFO messages above.
  • We’ve also logged out the same messages using the Log4J API. Apache has always recommended you to adopt it into your application. You can see the messages onto your console beside newly created file log.log. Those DEBUG messages are printed out using Log4J logging mechanism.
  • Log4j requires defining of Appenders, as such, two Appenders are defined; one for console logging while other for file purpose.
  • Take in your consideration that the log4j.xml file should be located beneath your WEB-INF/classes to be considered once the logger object get initialized.

Sessions

Portlet application can use PortletSession for tracking the user across multiple client requests for Portal page. PortletSession tracking mechanism that Portlet adopts is very similar for what’s already defined in the Servlet API.

A Portlet can get access for the PortletSession object by calling getPortletSession() method against PortletRequest instance (i.e RenderRequest or ActionRequest). Similar for Servlet, getPortletSession() has been provided with two different favors; getPortletSession() and getPortletSession(boolean). Invoking the first method will aid you get the already created PortletSession, in case there is no PortletSession created, a new one will be created. Second method is useful to determine whether there is a current PortletSession or not.

True value will make the getPortletSession(boolean) similar for getPortletSession(), while False value won’t allow the PortletSession to be created in case there is no default one. Null value will be returned in case no PortletSession there.

Every Portlet application has its own PortletSession as you can’t share the PortletSession between different Portlet applications. Beside that, every users has its own PortletSession object as you can’t share the same instance of PortletSession between more than one user.

Sessions – Portlet Scope Vs Application Scope

As we’ve stated earlier, Portals don’t share the PortletSession object neither between users nor between Portlet applications. But it’s important to know that when it comes to use the PortletSession for getting your attributes retained, that the attributes would be retained at the PortletScope level unless you’ve mentioned something else.

Following sample shows you how can we use the PortletSession for retaining objects against PortletSession/PortletScope level and what’s the effect that way could made for other Portlets.

HelloPortlet.java


package com.journaldev.portlet;

import java.io.IOException;
import java.util.Enumeration;

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

import org.apache.log4j.Logger;

public class HelloPortlet extends GenericPortlet{
	Logger logger = Logger.getLogger(HelloPortlet.class);

	public void init(PortletConfig config) throws PortletException {
		super.init(config);
	}

	public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException{
		Enumeration<String> names = request.getPortletSession().getAttributeNames();
		StringBuffer buffer = new StringBuffer();
		while(names.hasMoreElements()){
			String name = names.nextElement();
			buffer.append(name+" :: "+request.getPortletSession().getAttribute(name)+"\n");
		}
		response.getWriter().print("<form action="+response.createActionURL()+">"
				+ "<p>Portlet Session Attributes</p>"
				+ buffer
				+ "<input type='submit' value='Just Do Action'/>"
				+ "</form>");
	}

	public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException{
		if(this.getPortletName().equals("HelloOne")){
			request.getPortletSession().setAttribute("anonymousObject", "PortletSession Attribute");
		}
	}
}

portlet.xml


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

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

	<portlet>
		<init-param>
			<name>PortletParam</name>
			<value>ParamValue</value>
		</init-param>
		<display-name>Hello Portlet One</display-name>
		<portlet-name>HelloOne</portlet-name>
		<portlet-class>com.journaldev.portlet.HelloPortlet</portlet-class>
		<description>Hello Portlet One</description>
		<portlet-info>
			<title>Hello Portlet One</title>
			<keywords>Hello, Portlet, One</keywords>
			<short-title>Hello Portlet One</short-title>
		</portlet-info>
	</portlet>

	<portlet>
		<init-param>
			<name>PortletParam</name>
			<value>ParamValue</value>
		</init-param>
		<display-name>Hello Portlet Two</display-name>
		<portlet-name>HelloTwo</portlet-name>
		<portlet-class>com.journaldev.portlet.HelloPortlet</portlet-class>
		<description>Hello Portlet Two</description>
		<portlet-info>
			<title>Hello Portlet Two</title>
			<keywords>Hello, Portlet, Two</keywords>
			<short-title>Hello Portlet Two</short-title>
		</portlet-info>
	</portlet>	

</portlet-app>

Retain Attributes - PortletSession - PortletScope

Here’s some important points you may have to notice:

  • We’ve defined two different Portlets using the same HelloPortlet instance. HelloOne and HelloTwo are two different Portlets have used the same Portlet instance.
  • Both of them have defined a submit action. Just one Portlet is able of adding a new attribute against PortletSession and it’s for sure that one has the name HelloOne.
  • HelloTwo Portlet can’t read the PotletSession’s attribute that was set by HelloOne. Render phase of HelloTwo Portlet can’t find any attributes registered against PortletSession, although an anonymousObject attribute has been set by HelloOne.
  • Calling of setAttribute(name,value) against PortletSession will retain the attributes against PortletSession/PortletScope scope.
  • PortletScope attributes are stored for a given instance of the Portlet on the Portal page, if there is more than one instance of the Portlet on a page, the PortletScope will be different for each.
  • When an object is saved on the Session in the PortletScope, it has a namespace prefixed appended to the attribute name. The name space is different for each instance of the Portlet on the page.

Now, let’s see what’s the difference that can we make if the attributes are got saved on PortletSession/ApplicationScope. Following sample shows you how can we retain an Object against PortletSession/ApplicationScope using one Portlet and read it using another one.

HelloPortlet.java


package com.journaldev.portlet;

import java.io.IOException;
import java.util.Enumeration;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.GenericPortlet;
import javax.portlet.PortletConfig;
import javax.portlet.PortletException;
import javax.portlet.PortletSession;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

import org.apache.log4j.Logger;

public class HelloPortlet extends GenericPortlet{
	Logger logger = Logger.getLogger(HelloPortlet.class);

	public void init(PortletConfig config) throws PortletException {
		super.init(config);
	}

	public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException{
		// Get all attributes' names that are defined along side of Application Scope
		Enumeration<String> names = request.getPortletSession().getAttributeNames(PortletSession.APPLICATION_SCOPE);
		StringBuffer buffer = new StringBuffer();
		while(names.hasMoreElements()){
			String name = names.nextElement();
			// Get the attribute's value
			buffer.append(name+" :: "+request.getPortletSession().getAttribute(name,PortletSession.APPLICATION_SCOPE)+"\n");
		}
		response.getWriter().print("<form action="+response.createActionURL()+">"
				+ "<p>Portlet Session Attributes</p>"
				+ buffer
				+ "<input type='submit' value='Just Do Action'/>"
				+ "</form>");
	}

	public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException{
		if(this.getPortletName().equals("HelloOne")){
			// Define attribute along side of Application Scope
			request.getPortletSession().setAttribute("anonymousObject", "PortletSession Attribute",PortletSession.APPLICATION_SCOPE);
		}
	}
}

Before Attribute Got SavedAfter Attribute Got Saved

Here’s detailed explanation for code listed above:

  • Instead of using default setAttribute(), we’ve used overloaded method which accepts a scope as parameter.
  • PortletSession defines two constants; PORTLET_SCOPE and APPLICATION_SCOPE.
  • HelloOne has set the attribute and HelloTwo has read it.
  • Any Portlet in the Portlet application can retrieve or modify any attributes in the user’s session stored as application scope.
  • You can use getAttributesNames() to get all names of the attributes that are defined along side of PortletSession.
  • To remove attribute from the PortletSession you can use removeAttributes().
  • For each PortletSession’s attribute method, an overloaded version that takes scope as a parameter.
  • PortletSession has integrated seamlessly with the Servlet session and JSP. This concept would be discussed intensively later on.

Interportlet Communication

Before initiating a Java Portlet Specification, each Portal vendor has provided its own proprietary mechanism for getting interportelt communication achieved.  After Java Portlet Specification got released, the interportlet communication has been organized in a standard way.

PortletSession has been used for this purpose as you must be aware of the following issues:

  • The Portlet places the parameters in the sessions’s application scope.
  • In case you’ve used Portlet container that’s supported the cache mechanism, be sure not to enable caching for the Portlets. Some Portals won’t implement caching, if a Portlet that supports caching runs on a Portal that doesn’t support caching, the Portlet will run normally.
  • Portlet’s modifications must occur during action request to guarantee that the updates propagate to every Portlet during render request phase.

Summary

As being Portal contains a lot of APIs that you must be aware of. This tutorial has focused on the remaining APIs that you should take care of when it comes to deal with any Portal providers and especially Apache Pluto. Contribute us by commenting below and find downloaded source code.

Comments

  1. Mohammed Sarfaraz says:

    Nice article.Can you write few more in this Topic showing small application in use with portlet .

    1. Mohammad says:

      Thank you Mohammad,

      Actually i had written many tutorials about Portal concepts as you may find that listed beneath the Portlet and Portal category. By clicking that category, you should see all of these tutorials and articles. Hope you find what you want listed there and in case you don’t, just notify us and follow to cover it for you soon.

      Thank you again for this nice words and hope you return back to us soon.

      Mohammad Amr

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