Apache Pluto, Portlet Bridge & JSF 2.0 Integration Example Tutorial

Filed Under: JSF

In the previous Developing Portlets Using JSP & Servlet we clarified you how can we use a Portlets, JSPs & Servlets for creating an MVC architectual application that’s easy to maintain, easy to debug and easy to develop.

But why we would waste a lot of time in developing such that orchestration while others were already did. JSF framework are MVC compliant framework, as its components contained the concept of Separation of concern (SoC).

Facelets technology are used for handling the view purposes, its backing bean act as controllers and you can use its Expression Language for glue your views with the proposed models.

It’s elegant framework as you can use it within your Portlets, that will make them JSF-based Portlets. For this purpose, Java Community (JC) has proposed two different JSR (Java Specification Request) to simplify integrating your Portals with the well-know JSF framework.

JSR-301 is a Portlet container specification that defines the required behavior of a JSR-168,286 (Portlet Specification) that proxies for JSF artifacts. Meanwhile, JSR-329 is for Portlet container 2.0 bridge for JavaServer Faces (JSF) 1.2 Specification that defines the required behavior for allowing the JSF Application/View to be accessed as a Java Portlet.

Until writing these lines, no specification has been released for JavaServer Faces 2.0, though the implementation is already provided. This tutorial will provide you detailed information that help you getting all these technologies integrated each together as they work efficiently.

  • Any Portal (Portlet container 2.0 compliance) Like Apache Pluto.
  • JSF 2.0 (Either by using MyFaces 2.0 or by using Reference Implementation JSF Mojarra 2.0).
  • Any Portlet Bridge that’s compliant with JSR-329 like MyFaces 2.0 Portlet Bridge.

Employee registration operation is the process for which the integration will be achieved, as no need for using of Standard Java Portlet, Java Server Pages and Servlet for doing so.

Database Design & Required Model

For explaining purposes, it’s good for you to know what’s the form of the database table that we would use for retaining the registered employees.

Employee Table

Employee.sql


CREATE TABLE `employee` (
  `EMP_ID` int(11) NOT NULL AUTO_INCREMENT,
  `EMP_NAME` varchar(45) DEFAULT NULL,
  `EMP_JOB` varchar(45) DEFAULT NULL,
  `EMP_SALARY` int(11) DEFAULT NULL,
  PRIMARY KEY (`EMP_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

Employee entity (Model) that would be created according for employee Table figured above will be:


package com.journaldev.data;

public class Employee {
 private String id;
 private String name;
 private String job;
 private String salary;

 public String getId() {
 return id;
 }

 public void setId(String id) {
 this.id = id;
 }

 public String getSalary() {
 return salary;
 }

 public void setSalary(String salary) {
 this.salary = salary;
 }

 public String getName() {
 return name;
 }

 public void setName(String name) {
 this.name = name;
 }

 public String getJob() {
 return job;
 }

 public void setJob(String job) {
 this.job = job;
 }

}

Design View

The design view for the operation of employee registration is just as JSF framework has done, the process of bridging has eliminated the need of walking through Portlet container accompanies.

Design View

The figured design depicts you for how the flow of execution have to proceed, it’s just like any JSF application you may be made in the past.

Register Employee XHTML

JSF 2.0 has used a Facelets as view technology instead of JSP that’s supported by JSF 1.x. Registration employee page would look like below:

register.xhtml


<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">
	<h:head>
		<title>Register Employee</title>
	</h:head>
	<h:body>
		<h:messages showSummary="true" errorStyle="color:red;" infoStyle="color:green;"/>
		<h:form prependId="false">
			<h:panelGrid columns="2" style="width:100%">
					<h:outputLabel for="id" value="Identity"></h:outputLabel> 
					<h:inputText id="id" value="#{registerEmployeeManagedBean.employee.id}" required="true" requiredMessage="ID is mandatory">
						<f:validateRegex pattern="[0-9]*"></f:validateRegex>
					</h:inputText>			
					<h:outputLabel for="name" value="Name"></h:outputLabel> 
					<h:inputText id="name" value="#{registerEmployeeManagedBean.employee.name}"></h:inputText>
					<h:outputLabel for="job" value="Job"></h:outputLabel> 
					<h:inputText id="job" value="#{registerEmployeeManagedBean.employee.job}"></h:inputText>
					<h:outputLabel for="salary" value="Salary"></h:outputLabel> 
					<h:inputText id="salary" value="#{registerEmployeeManagedBean.employee.salary}" requiredMessage="Salary is mandatory">
						<f:validateRegex pattern="[0-9]*"></f:validateRegex>
						<f:validateLength minimum="2" maximum="4"></f:validateLength>
					</h:inputText>																								
			</h:panelGrid>
			<h:commandButton value="Register" actionListener="#{registerEmployeeManagedBean.registerListener}" style=""></h:commandButton>
		</h:form>
	</h:body>
</html>

Here’s detailed explanation for the code listed above:

  • Registration page has used the XHML format. Facelets has supported the XHML as a format of its view.
  • The user need to fill in all required information fields like identity and salary, in case you’ve missed them out, an error message would be flagged. These error messages are shown by the JSF framework itself as we’ve used a <f:validateRegex/> and required attributes.
  • In case you’ve entered a Not Number value within identity or salary fields, a JSF error message would be displayed tell you that you’re entering an invalid value.
  • All fields are associated with their respective attributes against employee property that’s already defined in the RegisterEmployeeManagedBean. As so, no submitted values are extracted from the request object.

Register Employee Managed Bean

As JSF promised, everything will get retained into your bean, no need for orchestrating a lot of components that you’ve used before for extracting the user submitted parameters as no need for handling much issues you may do in case you’ve decided to not use a JSF framework like messages, locales and so on.


package com.journaldev.beans;

import java.io.IOException;
import java.sql.SQLException;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;

import org.apache.log4j.Logger;

import com.journaldev.dao.EmployeeDAO;
import com.journaldev.data.Employee;

@ManagedBean
@SessionScoped
public class RegisterEmployeeManagedBean {
	private static Logger logger = Logger.getLogger(RegisterEmployeeManagedBean.class);
	private Employee employee = new Employee();

	public Employee getEmployee() {
		return employee;
	}

	public void setEmployee(Employee employee) {
		this.employee = employee;
	}

	public void registerListener(ActionEvent event){
		try {
			// Register Employee
			this.employee = EmployeeDAO.getInstance().createEmployee(employee);
			logger.debug("Employee Has Registered");
			FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO,
					"Employee has regisered successfully !",""));
			// Reset employee
			this.employee = new Employee();
		} catch (IllegalAccessException | ClassNotFoundException | SQLException | IOException e) {
			logger.debug("Registration Process Has Failed",e);
			FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR,
					"Unforunately!, employee hasn't registered cause to : "+e,""));
		}
	}
}

Here’s detailed explanation for the bean code figured out:

  • A plain old Java object (POJO) employee is used for binding purpose. In JSF, each component may be associated with a value provided by the Managed Bean. Once the form has been submitted, JSF framework has been started and the submitted values are transferred magically into the binded bean.
  • As we’ve JSF 2.0, no need for faces configuration file (faces-config.xml), and so, we used the newly added annotations for declaring the managed bean and its scope.
  • Remember as no JSR proposed for JSF 2.0, but it’s already implemented and you may get used in a lot of Portlet container that’s supported JSR-286.
  • You may notice using of EmployeeDAO and ConnectionUtility, if you remember what we have discussed at the Developing Portlets Using JSP & Servlet where in, your good design lead you for easy-to-maintain code, easy-to-debug and easy-to-develop (i.e. Separation of concern). Look at now, you have the ability to re-use the code you made. Really !! nothing touched with these two utilities.
  • All of these classes that are relevant for the database communication have been got isolated to be used later on by any presentation layer. So, you either use the JSF, default JSP/Servlet, normal Java Desktop application or you may wrap them up to be SOAP-based service or Restful-based service.
  • The user will get a confirmation messages either the registration process has been finished successfully or it’s being failed.
  • In case the registration process has failed, the confirmation message would show you the main cause for this failure.

JSF-Portlet Bridge Dependencies

As we’ve mentioned before in that the Portlet Bridge is just a specification, so a lot of vendors have implemented it. We will use the MyFaces 3.0.0-alpha version that’s provided for Portlet Container 2.0. Two dependencies listed below must be added into your Maven build file to get Portlet Bridge implementation involved and used.

MyFaces-PortletBridge


<dependency>
	<groupId>org.apache.myfaces.portlet-bridge</groupId>
	<artifactId>portlet-bridge-api</artifactId>
	<version>3.0.0-alpha</version>
</dependency>
<dependency>
	<groupId>org.apache.myfaces.portlet-bridge</groupId>
	<artifactId>portlet-bridge-impl</artifactId>
	<version>3.0.0-alpha</version>
</dependency>

JSF Implementation & Deployment Descriptor

JSF is a standard specification, that’s mean different vendors have already provided their own implementation. However, this part of tutorial is very important one as we would show you how can use two different implementations for getting JSF implementation used and what’s the impact of that usage on the deployment descriptor file.

Let’s firstly choose the most standard JSF implementation, it’s for sure a JSF Mojarra 2.0. You must add these below dependencies into you own maven for make use of JSF Mojarra.

JSF - Reference Implementation - Mojaraa Dependencies


<!-- Faces Implementation -->
<dependency>
	<groupId>com.sun.faces</groupId>
	<artifactId>jsf-impl</artifactId>
	<version>2.1.15</version>
</dependency>
<!-- Faces Library -->
<dependency>
	<groupId>com.sun.faces</groupId>
	<artifactId>jsf-api</artifactId>
	<version>2.1.15</version>
</dependency>

And so, your web.xml file should be like this:

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>Employee Registration</display-name>
	<servlet>
		<servlet-name>Faces Servlet</servlet-name>
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.xhtml</url-pattern>
	</servlet-mapping>
	<context-param>
		<description>State saving method: 'client' or 'server' (=default). See
			JSF Specification 2.5.2</description>
		<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
		<param-value>server</param-value>
	</context-param>
	<listener>
		<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
	</listener>
</web-app>

But let’s see now what are these dependencies required for making MyFaces 2.0 get used instead of Reference Implementation JSF Mojarra 2.0.

JSF - MyFaces Dependencies


<dependency>
	<groupId>org.apache.myfaces.core</groupId>
	<artifactId>myfaces-api</artifactId>
	<version>2.1.15</version>
</dependency>
<dependency>
	<groupId>org.apache.myfaces.core</groupId>
	<artifactId>myfaces-impl</artifactId>
	<version>2.1.15</version>
</dependency>

And so, you must have the same entries listed above in the web.xml but with major change, in that the listener mentioned must be removed.

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>Employee Registration</display-name>
	<servlet>
		<servlet-name>Faces Servlet</servlet-name>
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.xhtml</url-pattern>
	</servlet-mapping>
	<context-param>
		<description>State saving method: 'client' or 'server' (=default). See
			JSF Specification 2.5.2</description>
		<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
		<param-value>server</param-value>
	</context-param>
</web-app>

Full Maven Build File

Find below full maven build file that will be used for implementing a JSF/Mojarra Portlet.

pom.xml


<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>EmployeeRegistration-JSFBridge</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>EmployeeRegistration-JSFBridge</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>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.17</version>
		</dependency>
		<dependency>
			<groupId>org.apache.pluto</groupId>
			<artifactId>pluto-taglib</artifactId>
			<version>1.1.7</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.32</version>
		</dependency>
		<dependency>
			<groupId>org.apache.myfaces.portlet-bridge</groupId>
			<artifactId>portlet-bridge-api</artifactId>
			<version>3.0.0-alpha</version>
		</dependency>
		<dependency>
			<groupId>org.apache.myfaces.portlet-bridge</groupId>
			<artifactId>portlet-bridge-impl</artifactId>
			<version>3.0.0-alpha</version>
		</dependency>
		<!-- Faces Implementation -->
		<dependency>
			<groupId>com.sun.faces</groupId>
			<artifactId>jsf-impl</artifactId>
			<version>2.1.15</version>
		</dependency>
		<!-- Faces Library -->
		<dependency>
			<groupId>com.sun.faces</groupId>
			<artifactId>jsf-api</artifactId>
			<version>2.1.15</version>
		</dependency>
	</dependencies>
	<build>
		<finalName>${project.artifactId}</finalName>
		<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.artifactId}.war" tofile="${deployFolder}/${project.artifactId}.war" />
							</tasks>
						</configuration>
						<goals>
							<goal>run</goal>
						</goals>
					</execution>
					<execution>
						<id>delete</id>
						<phase>clean</phase>
						<configuration>
							<tasks>
								<delete file="${deployFolder}/${project.artifactId}.war" />
								<delete dir="${deployFolder}/${project.artifactId}" />
							</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>
	</build>
</project>

EmployeeDAO & ConnectionUtility

Now, it’s time to make a fast look at the EmployeeDAO and ConnectionUtility classes. These classes are used to handle all of these issues that are relevant for Database connectivity.


package com.journaldev.dao;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import com.journaldev.dao.utility.ConnectionUtility;
import com.journaldev.data.Employee;

public class EmployeeDAO {

	public static EmployeeDAO employeeDAO = null;

	private EmployeeDAO(){

	}

	public static EmployeeDAO getInstance(){
		synchronized(EmployeeDAO.class){
			if(employeeDAO == null){
				employeeDAO = new EmployeeDAO();
			}

		}
		return employeeDAO;
	}

	public Employee createEmployee(Employee employee) throws SQLException, IllegalAccessException, IOException, ClassNotFoundException{
		// Get connection instance
		Connection connection = ConnectionUtility.getInstance().getConnection();
		// Create Prepared Statement
		PreparedStatement query = connection.prepareStatement("INSERT INTO EMPLOYEE VALUES (?,?,?,?)");
		// Set variables
		query.setInt(1, Integer.parseInt(employee.getId()));
		query.setString(2, employee.getName());
		query.setString(3, employee.getJob());
		query.setInt(4, Integer.parseInt(employee.getSalary()));

		try {
			// Execute
			query.execute();
			// Return employee instance
			return employee;
		}
		catch(Exception e){
			// Close statement
			query.close();
			// Close connection
			connection.close();
			// Throw another exception for notifying the Servlet
			throw new SQLException(e);
		}
	}

	public boolean deleteEmployee(Employee employee){
		return false;
	}

	public boolean updateEmployee(Employee employee, int employeeId){
		return false;
	}
}


package com.journaldev.dao.utility;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

public class ConnectionUtility {

	private static ConnectionUtility connectionUtiliy = null;

	private Connection connection = null;

	private ConnectionUtility() {
	}

	public static ConnectionUtility getInstance() throws IOException, IllegalAccessException, SQLException, ClassNotFoundException{
		// Synchronized against connectionUtility instance
		synchronized(ConnectionUtility.class){
			// Check whether the connectionUtility is null or not
			if(connectionUtiliy == null){
				// Create a properties instance
				Properties properties = new Properties();
				// Load properties from classpath
				properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("connection.properties"));
				// Set connection with connectionUtility
				connectionUtiliy = new ConnectionUtility();
				// Load driver class
				Class.forName("com.mysql.jdbc.Driver");
				// Create connection
				connectionUtiliy.setConnection(DriverManager.getConnection("jdbc:mysql://localhost:3306/journaldev", properties));
			}
			return connectionUtiliy;
		}
	}

	public Connection getConnection() throws ClassNotFoundException, SQLException, IOException {
		if(connection.isClosed()){
			// Create a properties instance
			Properties properties = new Properties();
			// Load properties from classpath
			properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("connection.properties"));
			// Load driver class
			Class.forName("com.mysql.jdbc.Driver");
			// Create connection
			connectionUtiliy.setConnection(DriverManager.getConnection("jdbc:mysql://localhost:3306/journaldev", properties));
		}
		return connection;
	}

	public void setConnection(Connection connection) {
		this.connection = connection;
	}

}

Register Employee Demo

The demonstration starts by deploying your developed WAR into your Apache Pluto Portlet container 2.0. Log in into your Apache Pluto and navigating into JournalDev page that’s already implemented in the previous introduced tutorials.

Register Employee Page

Let’s see how JSF served you in case you’ve entered an invalid values, for that just put a character values inside both of id and salary fields.

Invalid Values

But what’s happened if we’ve tried to register already registered employees.

Try to register already registered employee

What’s happened if we register a new employee.

Register a new employee - before got employee saved

Register a new employee - while invoking register listener action

Database records Employee is registered succesfully

Summary

This tutorial is a unique one as it’s summarized the all required information for getting used a JSF-based application onto Portlet container. The all required configuration, dependencies, accompanies classes and much more, they are listed completely here. Contribute us by commenting below and find downloaded source code.

Comments

  1. Vinay says:

    Nice article. Thanks. Please also write on angularjs

    1. Pankaj says:

      Thanks, will write on AngularJS in coming months.

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