Perl is a family of high level language that adapted willingly with the Web as it’s used a Text-based processing. For such that integration we used the Portlet Perl bridge with some modifications that we already achieved on the source code that’s provided by Apache SVN for that Bridge.
Perl integration isn’t an easy mission as you may face a lot of issues raised once you’re getting the default library of Apache Perl Bridge used. The direct use of Perl bridge without any modifications will throw a ClassCastException as the bridge expects that your RenderResponse instance that’s passed is of type HttpServletResponseWrapper which is actually not.
It seems that’s working nicely when it comes to use it within Portlet Container Specification 1.0. Regardless of that, we are now here; Portlet Container Specification 2.0 and we must provide you a library for doing that.
However, you won’t be working on the Bridge modifications as it’s already modified and ready for your use. Instead, you will get the latest JAR downloadable here and it will be installed into your Maven repository just like any library for being referenced then from your Pom file.
This tutorial intended to provide you the same sample of Employee Registration that’s already covered in a lot of Tutorials we’ve provided before. As the integration of Perl is so complicated mission, so we will focus on the way in which you may get that done instead of focusing on the way in which you may use Perl effectively.
Project Directory Structure
Employee Table
As being of our suggested business model is just a process of employee registration, it’s very trivial to know that we have one Table called employee and it looks like below:
As you can create that Table into your database using the below SQL statement:
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=2 DEFAULT CHARSET=utf8;
Employee Model
According for MVC design pattern, the data that’s should be served must be located in a data model. For employee registration process, Employee data model should look like below:
Employee.java
package com.journaldev.data;
public class Employee {
// Employee Identification
private int id;
// Employee Name
private String name;
// Employee Job
private String job;
// Employee Salary
private int salary;
public int getId() {
return id;
}
public void setId(int 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 int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
Download Apache Perl Bridge
Multiple choices are introduced for you to get install Apache Perl bridge library; you can reference it directly from the Maven repository, fetch the source code from the Apache source code control or download JournalDev Release directly.
We’ve preferred you to download JournalDev release as it’s being modified to prevent you from getting the mentioned exception above.
Referencing Apache Perl library from Maven repository should make it available into your local repository and so no need for further Maven commands execution. In case you chose to fetch Apache Perl from the source code control, then you need to execute mvn clean install to get a ready JAR upon pom.xml file that’s located on the fetched folder.
But in case you’re downloading JournalDev release you must follow the below steps to make sure you’re able of referencing the library from your project’s maven file:
- Save downloaded ZIP file into your local directory.
- Change file extension from ZIP into JAR.
- Navigate into your download JAR location through using of command line and execute
mvn install:install-file -DgroupId=org.apache.portals.bridges -DartifactId=portals-bridges-perl -Dversion=1.0.4 -Dpackaging=jar -Dfile={PATH-TO-FILE}
. - Make sure that you were finished Maven installation successfully.
Maven Build File
Once you finished previous library installation, let’s glance the maven build file required:
pom.xml
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.journaldev</groupId>
<artifactId>PerlBridge</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>PerlBridge</name>
<url>https://maven.apache.org</url>
<properties>
<deployFolder>D:/ApachePluto/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>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>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>commons-digester</groupId>
<artifactId>commons-digester</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>commons-digester</groupId>
<artifactId>commons-digester</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.5</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-tools</artifactId>
<version>2.0</version>
</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.portals.bridges</groupId>
<artifactId>portals-bridges-perl</artifactId>
<version>1.0.4</version>
<exclusions>
<exclusion>
<groupId>org.apache.portals.jetspeed-2:</groupId>
<artifactId>jetspeed-rewriter</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.portals.jetspeed-2</groupId>
<artifactId>jetspeed-rewriter</artifactId>
<version>2.1.4</version>
<exclusions>
<exclusion>
<groupId>castor</groupId>
<artifactId>castor</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>castor</groupId>
<artifactId>castor</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.apache.portals.bridges</groupId>
<artifactId>portals-bridges-common</artifactId>
<version>2.0</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.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
As you may notice, the downloaded Apache Perl bridge has already listed inside the Maven file as being it’s now located inside your local repository.
Perl Portlet & Portlet Deployment Descriptor
Just like any other type of Portlets, your Perl Portlet must should look like below:
PerlPortlet.java
package com.journaldev.portlet;
import java.io.IOException;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletException;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.PortletSession;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import org.apache.portals.bridges.perl.PerlParameters;
public class PerlPortlet extends org.apache.portals.bridges.perl.PerlPortlet{
public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException{
if(request.getParameter("status") != null && request.getParameter("status").equals("success")){
PerlParameters perlParam =
(PerlParameters)request.getPortletSession().getAttribute(PerlParameters.PERL_PARAMETER, PortletSession.APPLICATION_SCOPE);
if(perlParam == null){
perlParam = new PerlParameters();
perlParam.setScriptName("success.cgi");
perlParam.setApplicationName("PerlPortlet");
request.getPortletSession().setAttribute(PerlParameters.PERL_PARAMETER,perlParam, PortletSession.APPLICATION_SCOPE);
}
super.doView(request, response);
}
else if(request.getParameter("status") != null && request.getParameter("status").equals("failure")){
PerlParameters perlParam =
(PerlParameters)request.getPortletSession().getAttribute(PerlParameters.PERL_PARAMETER, PortletSession.APPLICATION_SCOPE);
if(perlParam == null){
perlParam = new PerlParameters();
perlParam.setScriptName("failure.cgi");
perlParam.setApplicationName("PerlPortlet");
request.getPortletSession().setAttribute(PerlParameters.PERL_PARAMETER,perlParam, PortletSession.APPLICATION_SCOPE);
}
super.doView(request, response);
}
else if(request.getParameter("status") != null && request.getParameter("status").equals("initial")){
PerlParameters perlParam =
(PerlParameters)request.getPortletSession().getAttribute(PerlParameters.PERL_PARAMETER, PortletSession.APPLICATION_SCOPE);
if(perlParam == null){
perlParam = new PerlParameters();
perlParam.setScriptName("register.cgi");
perlParam.setApplicationName("PerlPortlet");
request.getPortletSession().setAttribute(PerlParameters.PERL_PARAMETER,perlParam, PortletSession.APPLICATION_SCOPE);
}
super.doView(request, response);
}
else {
super.doView(request, response);
}
}
public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException{
// Create request dispatcher
PortletRequestDispatcher dispatcher = this.getPortletContext().getNamedDispatcher("RegisterEmployeeServlet");
try {
if(request.getMethod().equals("POST")){
// Include
dispatcher.include(request, response);
// Set render parameter
response.setRenderParameter("status", "success");
}
else {
response.setRenderParameter("status", "initial");
}
}
catch(Exception ex){
// Set render parameter
response.setRenderParameter("status", "failure");
response.setRenderParameter("exception", ex.getMessage());
}
}
}
portlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<portlet-app xmlns="https://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
version="2.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd">
<portlet>
<display-name>PerlPortlet</display-name>
<portlet-name>PerlPortlet</portlet-name>
<portlet-class>com.journaldev.portlet.PerlPortlet</portlet-class>
<description>Per Portlet</description>
<init-param>
<name>PerlScript</name>
<value>register.cgi</value>
</init-param>
<init-param>
<name>ScriptPath</name>
<value>cgi-bin</value>
</init-param>
<init-param>
<name>Application</name>
<value>PerlPortlet</value>
</init-param>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
</supports>
<portlet-info>
<title>Perl Portlet</title>
<keywords>Perl,Portlet</keywords>
<short-title>Perl Portlet</short-title>
</portlet-info>
</portlet>
</portlet-app>
Here’s detailed explanation for the code listed above:
- Your Perl Portlet should be of type org.apache.portals.bridges.perl.PerlPortlet.
- You have defined your Perl Portlet either by extending PerPortlet or by mentioning it directly inside your Portlet deployment descriptor and with no need for an existing class that does extend.
- doView will be called at each time the Portlet got rendered, as so, it will read the status parameter that determines which Perl view should be delegated for.
- To change the Perl view you should use PerlParameters object that have provided scriptName & applicationName.
- Calling of super.doView() will make sure that the new selected Perl script should be displayed and rendered.
- Make sure you’re set the same applicationName just like that name defined in the Portlet.xml.
- The doView method have defined a default case for which the status parameter might not be not passed or passed with initial value.
- Default view will be handled by calling super.doView() with no additional PerlParamaters. Mainly, you should provide PerlScript & ScriptPath inside your Portlet.xml for such that purpose.
- The ProcessAction have defined the all required code for getting an Employee registered.
- You should note that we’ve distinguished between POST request and GET request in the ProcessAction method due to the Perl Portlet kind. Perl Portlet translates all relative URLs to be Portlet action and so they would call ProcessAction.
- You can extend this effort by extending the using of render parameters that are set in the ProcessAction to be used in the Perl script.
Perl Views
We’ve supposed that we have three different Perl Scripts and they’re:
register.cgi
#!D:Strawberryperlbinperl --
print qq(
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Register Employee</title>
</head>
<body>
<form action="/dummyAction" method="POST">
<table width="100%">
<tr width="60%">
<td>Enter Employee ID:</td>
<td><input name="employeeID" /></td>
</tr>
<tr width="60%">
<td>Enter Employee Name:</td>
<td><input name="employeeName" /></td>
</tr>
<tr width="60%">
<td>Enter Employee Job:</td>
<td><input name="employeeJob" /></td>
</tr>
<tr width="60%">
<td>Enter Employee Salary:</td>
<td><input name="employeeSalary" /></td>
</tr>
<tr width="60%" align="center">
<td colspan="2"><input type="submit" value="Register" /></td>
</tr>
</table>
</form>
</body>
</html>
);
success.cgi
#!D:Strawberryperlbinperl --
print qq(
Register Employee
<table width="100%">
<tbody>
<tr>
<td>Registration has done successfully!</td>
<td><a href="https://www.journaldev.com/pluto/portal/JournalDev">Register Another</a></td>
</tr>
</tbody>
</table>
);
failure.cgi
#!D:Strawberryperlbinperl --
print qq(
Register Employee
<table width="100%">
<tbody>
<tr>
<td>Registration hasn't done successfully!</td>
<td><a href="https://www.journaldev.com/pluto/portal/JournalDev">Register Another</a></td>
</tr>
</tbody>
</table>
);
Here’s detailed explanation for the code listed above:
- We’ve referenced the perl that’s already installed into your machine. You can install Perl into your machine by downloading the Perl software from here.
- Generally, you’re using #! in Perl to reference your local drives from the Perl script.
- We’ve used print function to print out the HTML content.
RegisterEmployeeServlet – Business Delegation
We’ve left the business of employee registration into separate Servlet called RegisterEmployeeServlet. It looks like below:
RegisterEmployeeServlet.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;
import org.apache.log4j.Logger;
import com.journaldev.dao.EmployeeDAO;
import com.journaldev.data.Employee;
public class RegisterEmployeeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
Logger logger = Logger.getLogger(RegisterEmployeeServlet.class);
public RegisterEmployeeServlet() {
super();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// Create employee
Employee employee = new Employee();
// Fill in required data from the request sent
employee.setId(Integer.parseInt(request.getParameter("employeeID")));
employee.setName(request.getParameter("employeeName"));
employee.setJob(request.getParameter("employeeJob"));
employee.setSalary(Integer.parseInt(request.getParameter("employeeSalary")));
try {
// Asking employeeDAO creating the employee against registered database
Employee createdEmployee = EmployeeDAO.getInstance().createEmployee(employee);
// Print out the created employee information
logger.info("Employee Created"+createdEmployee);
} catch (Exception e) {
// Log the exception
logger.error("Employee Creation Failed", e);
// Throw another exception for notifying the Portlet
throw new ServletException(e);
}
}
}
Database Utility
Both of EmployeeDAO & ConnectionUtility classes are used for handling the all database issues.
EmployeeDAO.java
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, employee.getId());
query.setString(2, employee.getName());
query.setString(3, employee.getJob());
query.setInt(4, 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;
}
}
ConnectionUtility.java
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;
}
}
Employee Registration Demo
Before getting started make a demonstration for how can use the Perl script for employee registration, let’s return you back into an Apache Pluto Introduction that will help you get a ready JournalDev Portal page shown.
Now, set your Perl Portlet into your JournalDev Portal page and let’s start the process of Employee registration:
And if you tried to register the same employee with the same ID you’ll likely get the below response.
Summary
Apache Pluto provides you a huge amount of Bridges that could be used for integrating with different languages. The integration with the Perl language is slightly different, in that, you need to install the Perl software and use the enhanced JournalDev Perl Bridge library to get the Perl scripts displayed into your Portlet.
Contribute us by commenting below and find the downloaded source code for your experimental purpose.