Apache Pluto Portlet & Struts 2 Integration Example Tutorial

Filed Under: Portal and Portlets

In earlier tutorials, we’ve developed different types of Portlet. Portlets are developed using of JSP & Servlet at once and then we learned using of JSF with Portlets. This time we’re going to develop a Portlet using another famous framework like Apache Struts.

Srtuts framework is an MVC-based one, we’ve already covered a lot of topics onto Apache Struts as you can refer for all of them, but this is the first time you will get a Struts application deployed into a Portlet container like Apache Pluto.

You’re likely going to use Apache Struts Bridge that is already maintained by Apache itself. However, the same application that you’ve implemented before (Employee Registration Form) will be used in this tutorial but with Struts2 framework.

The main goal of this application is to help you know all the details required for getting the application deployed and running properly onto any JSR-168/JSR-286 compliant Portlet container.

Final Project Structure

Struts Project - Final Project Structure

Employee Table Design

This section would clarify you what the Employee Table is and what are these columns used.

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;

Let’s see the Employee entity (Model) that would be used for holding the data that are going back and forth between the application and the database store.


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;
	}
}

Create Template Application Using Eclipse IDE

You may save your time instead of getting delve into creating the project by yourself, by using an Apache Struts Archetype. Following steps will help you creating a Struts Portlet application easily.

  • Add Remote Archetype Catalog http://struts.apache.org/ into your Maven Archetypes.

Apache Struts CatalogRemote Apache Struts Catalog Is Added

  • Create a new Maven project. This time you will get stopped into Catalog selection, instead of using All Catalogs, you must select that’s one registered.

Select Remote Catalog

  • Fill in the all required information, GroupId, ArtifactId, version, and Package.

Fill in Maven Project Properties

  • Click Finish and waiting your Eclipse displaying created application into your Project Explorer.
  • Though the application is created successfully, but it’s likely want some of in-hand adjustment as the Archetype’s Maven dependencies isn’t updated somehow. That’s why you may notice some errors in the created application.

Created Application

  • Delete all undesired Java files under com.journaldev package.
  • Delete all undesired JSP files/folders under WEB-INF/jsp.

Modify Maven Dependencies

The Maven dependency file has got modified to serve two wanted features:

  • Add required dependencies for Struts2 and its relevant Portlet container Bridge.
  • Add all required Apache Pluto accompanies that would lead us for a healthy deployment onto Apache Pluto itself.

pom.xml


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

<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-StrutsBridge</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<name>EmployeeRegistration-StrutsBridge</name>

	<properties>
		<struts2.version>2.3.16.3</struts2.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<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>
		<!-- Apache Struts & Core -->
		<dependency>
			<groupId>org.apache.struts</groupId>
			<artifactId>struts2-core</artifactId>
			<version>${struts2.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.struts</groupId>
			<artifactId>struts2-config-browser-plugin</artifactId>
			<version>${struts2.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.struts</groupId>
			<artifactId>struts2-portlet-plugin</artifactId>
			<version>2.3.16.3</version>
		</dependency>
		<dependency>
			<groupId>org.apache.struts</groupId>
			<artifactId>struts2-junit-plugin</artifactId>
			<version>${struts2.version}</version>
			<scope>test</scope>
		</dependency>
		<!-- Commons logging -->
		<dependency>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
			<version>1.1.3</version>
		</dependency>
		<!-- Log4j -->
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.17</version>
		</dependency>

		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.5</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.4</version>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.0</version>
			<scope>provided</scope>
		</dependency>
		<!-- Apache Struts Portlet Bridge -->
		<dependency>
			<groupId>org.apache.portals.bridges</groupId>
			<artifactId>portals-bridges-struts-1.2.7</artifactId>
			<version>1.0.4</version>
		</dependency>
		<!-- MySQL driver -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.32</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>

Employee Registration Views

As you may know, Apache Struts has considered JSP as a view technology, so we would add a three distinct files, register.jsp, success.jsp and failure.jsp.

According for Apache Struts Archetype, the files would be added under WEB-INF/jsp/employee folder.

register.jsp


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Register Employee</title>
</head>
<body>
	<s:form action="register">
		<s:textfield name="id" label="Identifier"></s:textfield>
		<s:textfield name="name" label="Name"></s:textfield>
		<s:textfield name="job" label="Job"></s:textfield>
		<s:textfield name="salary" label="Salary"></s:textfield>
		<s:submit value="Register"></s:submit>
	</s:form>
</body>
</html>

failure.jsp


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Failure</title>
</head>
<body>
	<span style="color:red">Unfortunately! The Employee hasn't been registered successfully</span>
	</br>
	<a href="<s:url action="index" portletMode="view"/>">Try Again!</a>
</body>
</html>

success.jsp


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Success</title>
</head>
<body>
	<span style="color:green">Congratulations! The Employee has been registered successfully</span>
	<br/>
	<a href="<s:url action="index" portletMode="view"/>">Register Another</a>
</body>
</html>

As you’ve noticed, we used a Struts Tag library for providing a form component and its relevant parameters. If you’re not so good with a Struts, it’s so good for you return here to read some articles about it as it’s very elegant framework.

Struts Tag library has provided a <url/> Tag for creating a Struts-based link. Struts-based link is a link that uses the Struts framework vocabulary like action.

One important thing you should notice that and it’s the action attribute for the form that’s referred for action it’s name is register. That name would be provided by the struts.xml file that would be discussed later on.

Register Action

It’s may be known for you that a Struts is an action-based framework. In that, every form submission should be delegated into action based class that’s implemented to be extended from DefaultActionSupport class. Following RegisterAction Struts action class.


package com.journaldev.action;

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

import javax.portlet.PortletPreferences;

import org.apache.log4j.Logger;
import org.apache.struts2.dispatcher.DefaultActionSupport;
import org.apache.struts2.portlet.interceptor.PortletPreferencesAware;

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

public class RegisterAction extends DefaultActionSupport implements PortletPreferencesAware {
	private static Logger logger = Logger.getLogger(RegisterAction.class);
	private static final long serialVersionUID = 1L;
	private PortletPreferences preferences;
	private String id;
	private String name;
	private String job;
	private String salary;

	public PortletPreferences getPreferences() {
		return preferences;
	}

	public void setPreferences(PortletPreferences preferences) {
		this.preferences = preferences;
	}

	@Override
	public void setPortletPreferences(PortletPreferences prefs) {
		this.preferences = prefs;
	}

	@Override
    public String execute() throws Exception {
		try {
			Employee employee = new Employee();
			employee.setId(id);
			employee.setName(name);
			employee.setJob(job);
			employee.setSalary(salary);
			// Register Employee
			employee = EmployeeDAO.getInstance().createEmployee(employee);
			logger.debug("Employee Has Registered");
			return "SUCCESS";
		} catch (IllegalAccessException | ClassNotFoundException | SQLException | IOException e) {
			logger.debug("Registration Process Has Failed",e);
			return "FAILURE";
		}
    }

	public String getId() {
		return id;
	}

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

	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;
	}

	public String getSalary() {
		return salary;
	}

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

}

Here’s detailed explanation for the RegisterAction class figured out:

  • Notice the class’s properties id, name, job and salary are analogous for these parameters’ names that are provided by the register.jsp page.
  • RegisterAction has overridden an execute method for serving the employee registration purposes.
  • Struts framework will binded all form’s parameters with those corresponding ones at the action class. Id, name, job and salary will be passed automatically.
  • RegisterAction has used the EmployeeDAO (The same utility class that we’ve impelemnted previously, that it would handle the all database manipulation code) for registering the employee instance.
  • In case the registration process has failed the Struts framework would take you into failure page. The page success.jsp is that one, the Struts framework will redirect you into as soon as the registration has finished successfully.

Struts Application Configuration & Portlet.xml

Struts.xml file is an XML-based file that used by the Apache Struts framework for getting connected the different components that you’re developed.

Wiring of mentioned actions within your <s:form/> with the Struts-action must be defined as an entries within struts.xml file. Following Struts configuration file required:

struts.xml


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

	<package name="default" extends="struts-portlet-default"
		namespace="/employee">
		<action name="index">
			<result>/WEB-INF/jsp/employee/register.jsp</result>
		</action>
	</package>

	<package name="employee" namespace="/employee" extends="struts-portlet-default">
		<action name="register" class="com.journaldev.action.RegisterAction">
			<result name="SUCCESS">/WEB-INF/jsp/employee/success.jsp</result>
			<result name="FAILURE">/WEB-INF/jsp/employee/failure.jsp</result>
		</action>
	</package>
</struts>

Integration of Apache Struts with the given Portlet container has been done through using of portlet.xml file. In that, a new init-param should be used for this purpose. Following the Portlet.xml file that’s used.

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
                                 http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd">

    <portlet>
        <description>Register Employee</description>
        <portlet-name>RegisterEmployee</portlet-name>
        <portlet-class>org.apache.struts2.portlet.dispatcher.Jsr286Dispatcher</portlet-class>

		<init-param>
	        <name>actionPackages</name>
	        <value>com.journaldev.action</value>
	    </init-param>

		<!-- The namespace for the actions configured for view mode -->
		<init-param>
			<name>viewNamespace</name>
			<value>/employee</value>
		</init-param>

         <!-- The default action to invoke in view mode. -->
        <init-param>
            <name>defaultViewAction</name>
            <value>index</value>
        </init-param>

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

        <supported-locale>en</supported-locale>

        <portlet-info>
            <title>Register Employee</title>
            <short-title>Register Employee</short-title>
            <keywords>Employee,Registration</keywords>
        </portlet-info>
    </portlet>    

</portlet-app>

Here’s detailed explanation for both of the Struts and Portlet configuration files listed above:

  • Your Portlets must be an instance of JSR286Dispatcher class.
  • We’ve defined three additional parameters, actionPackages, viewNamespace and defaultViewAction.
  • Defined defaultViewAction will be used once you’ve opened the Portal page that’s contained the deployed Portlet. As being index is the value, the index should be defined as an action in the struts.xml file.
  • Defined actionPackages will be used for determining the Java package that contains the Struts-actions classes.
  • Defined viewNamespace will determine the namespace for the actions configured for view mode. It’s also applicable to define actions for edit and help modes.
  • Struts configuration file has defined an register action that would be used as soon as the user has submitted the form’s register.
  • Defined register action has had two different results, success and failure are used to determine the next view that Struts framework uses after finishing the calling of execute against action class.

Deployment Descriptor

web.xml


<?xml version="1.0" encoding="UTF-8"?>
<!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>RegisterEmployee</display-name>

  <filter>
    <filter-name>struts2</filter-name>
    <filter-class>
      org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
    </filter-class>
  </filter>

  <filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

EmployeeDAO & ConnectionUtility

Following below both of EmployeeDAO and ConnectionUtility that help you getting database connection and creating the user after then.


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;
	}

}

Registration Employee Demo

To get started showing your Portlet, you must logged into your Apache Pluto and navigating into JournalDev page. Typically, we have added a Portal page that’s contained for our developed Portlet. The process of creating a Portal page and add the Portlets upon it is discussed at Apache Pluto Introduction Tutorial.

Employee Registration - Initial View

Employee Registration - Fill in Employee data

Employee Registration - Success Operation

Employee Registration - Failure Operation

Summary

Apache Struts is an elegant framework that’s used for creating an MVC-based enterprise application. Apache has also provided you a ready made Portlet bridge that could be used for creating JSR-168/286 Struts-based Portlet. Contribute us by commenting below and find the 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