Creating of PHP Portlet isn’t an easy mission as no standard specification created for. However, when it comes to make an integration between PHP and Java you may mainly would like to:
- Execute Java code inside a PHP pages. (Using of Java Bridge, To be Discussed Later On).
- Execute a PHP page by a Java-based container (JVM). (Using of Quercus Library).
Actually, this tutorial is intended to cover the second choice as the first one would be discussed later on. Practically, you may find a links inside Apache Pluto site referring for PHP bridge, but unfortunately, it’s considered as obsolete API, thus is no longer available. You won’t be able to locate any of these mentioned libraries neither as a JAR nor as a Maven libraries.
This tutorial will provide you a kind of integration that you may find it very helpful way to leverage a PHP code inside your Portlet application. We’re going to orchestrate the Portlet, Servlet and PHP pages for achieving employee registration process like we did in Developing Portlets with JSPs & Servlets Tutorial.
For executing a PHP pages inside a JVM, we’ve used a Quercus library which is considered as a Java-based implementation for PHP language. It’s already contained for a lot of PHP modules and extensions like PDF, MySQL, JSON, etc.
However, the assumed employee registration example will adhere the MVC concept while it handles the client request by using Standard Portlet and delegate it into the desired view (PHP pages), once the user has activated a registration action, the submitted form should be handled by the business Servlet that’s already created for this purpose and the employee should be registered after then.
A confirmation message should be displayed once the registration operation finished successfully. In case you’ve got an exception, an error message should be displayed contained for the reason of happened error.
Either the operation has been finished successfully or not, the user will be able to navigate again into the registration employee view for another trial.
Employee Table
This section will show you the Employee Table that’s used for retaining the registered employees.
employee.sql
1 2 3 4 5 6 7 8 9 |
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 Model
Accordingly, an Employee object model should be defined for holding the employee’s information that’s going back and forth in the registration process.
Employee.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
package com.journaldev.data; public class Employee { private int id; private String name; private String job; 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; } } |
PHP Views
Similar for the example was provided for JSP, the view should be handled by using a set of PHP pages. Mainly, we have a three different views, employee registration, success confirmation and failure confirmation are the only views you would deal with for handling the employee registration process.
register.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
<?php $actionUrl = "?"; $renderUrl = "?"; foreach($_GET as $key=>$val){ if($key == "actionUrl"){ $actionUrl = $val; } } ?> <html> <body> <form action="<?php echo $actionUrl?>" method="POST"> <table> <tr> <td>Enter ID:</td> <td><input name="employeeID"/></td> </tr> <tr> <td>Enter name:</td> <td><input name="employeeName"/></td> </tr> <tr> <td>Enter job:</td> <td><input name="employeeJob"/></td> </tr> <tr> <td>Enter salary:</td> <td><input name="employeeSalary"/></td> </tr> <tr> <td colspan="2"> <input type="submit" value="Register"/> </td> </tr> </table> </form> </body> </html> |
success.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<?php $renderUrl = "?"; foreach($_GET as $key=>$val){ if($key == "renderUrl"){ $renderUrl = $val; } } ?> <html> <body> <table> <tr> <td> Congratulations, employee registration operation has been finished successfully ! </td> </tr> </table> <a href="https://www.journaldev.com/5095/<?php echo $renderUrl?>">Register Another</a> </body> </html> |
failure.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<?php $renderUrl = "?"; $exception = "?"; foreach($_GET as $key=>$val){ if($key == "renderUrl"){ $renderUrl = $val; } else if($key == "exception"){ $exception = $val; } } ?> <html> <body> <table> <tr> <td> <span style="color: red;"> Unfortunately, employee registration operation hasn't been finished successfully ! </span> </td> </tr> <tr> <td>For cause:<?php echo $exception?></td> </tr> </table> <a href="https://www.journaldev.com/5095/<?php echo $renderUrl?>">Try Again</a> </body> </html> |
Just, want you notice that we have a PHP code snippets in the provided views and these will absolutely be handled by the used JVM (i.e. Apache Pluto).
Portlet Deployment Descriptor
Find below the portlet.xml file that would help your Portlet container recognize your Portlets.
portlet.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<?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>Register Employee</display-name> <portlet-name>RegisterEmployee</portlet-name> <portlet-class>com.journaldev.portlet.RegisterEmployeePortlet </portlet-class> <description>Employee Registration</description> <supports> <mime-type>text/html</mime-type> <portlet-mode>VIEW</portlet-mode> </supports> <portlet-info> <title>Employee Registration</title> <keywords>employee, registration</keywords> <short-title>Employee Registration</short-title> </portlet-info> </portlet> </portlet-app> |
As you’ve mentioned, no additional fragments used as being the developed Portlet is a standard one.
Register Employee Portlet
RegisterEmployeePortlet.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
package com.journaldev.portlet; import java.io.IOException; import javax.portlet.ActionRequest; import javax.portlet.ActionResponse; import javax.portlet.GenericPortlet; import javax.portlet.PortletException; import javax.portlet.PortletRequestDispatcher; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; public class RegisterEmployeePortlet extends GenericPortlet{ public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException { if(request.getParameter("status") == null){ PortletRequestDispatcher dispatcher = this.getPortletContext().getRequestDispatcher("/register/register.php?actionUrl="+ response.createActionURL()); dispatcher.include(request, response); } else { if(request.getParameter("status").equals("success")){ PortletRequestDispatcher dispatcher = this.getPortletContext().getRequestDispatcher("/register/success.php?renderUrl="+ response.createRenderURL()); dispatcher.include(request, response); } else { PortletRequestDispatcher dispatcher = this.getPortletContext().getRequestDispatcher("/register/failure.php?renderUrl="+ response.createRenderURL()+"&exception="+request.getParameter("exception")); dispatcher.include(request, response); } } } public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException{ // Create request dispatcher PortletRequestDispatcher dispatcher = this.getPortletContext().getNamedDispatcher("RegisterEmployeeServlet"); try { // Include dispatcher.include(request, response); // Set render parameter response.setRenderParameter("status", "success"); } catch(Exception ex){ // Set render parameter response.setRenderParameter("status", "failed"); response.setRenderParameter("exception", ex.getMessage()); } } } |
Register Employee Servlet
RegisterEmployeeServlet.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
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); } } } |
Deployment Descriptor & Maven Build File
As we’ve stated earlier, Quercus is used for interpreting the PHP code inside your JVM, thus, below Maven file will be included for the all needed libraries that you need for executing a PHP code inside your JVM.
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
<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>PHPBridge</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>PHPBridge</name> <url>https://maven.apache.org</url> <properties> <deployFolder>D:/Apache Pluto/pluto-2.0.3/webapps</deployFolder> </properties> <repositories> <repository> <id>caucho</id> <name>Caucho</name> <url>https://caucho.com/m2</url> <layout>default</layout> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <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-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3</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>com.caucho</groupId> <artifactId>resin</artifactId> <version>4.0.30</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> |
You should notice that you are provided resin library that would be used for interpreting PHP purpose. Actually, a QuercusServlet will do that and so, you must configure it inside your web deployment descriptor. So we added it inside our deployment descriptor that should look like below:
web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "https://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Employee Registration</display-name> <servlet> <servlet-class>com.journaldev.servlet.RegisterEmployeeServlet</servlet-class> <servlet-name>RegisterEmployeeServlet</servlet-name> </servlet> <servlet-mapping> <servlet-name>RegisterEmployeeServlet</servlet-name> <url-pattern>/registerEmployeeServlet</url-pattern> </servlet-mapping> <taglib> <taglib-uri>https://java.sun.com/portlet</taglib-uri> <taglib-location>/WEB-INF/portlet.tld</taglib-location> </taglib> <servlet> <servlet-name>Quercus Servlet</servlet-name> <servlet-class>com.caucho.quercus.servlet.QuercusServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Quercus Servlet</servlet-name> <url-pattern>*.php</url-pattern> </servlet-mapping> </web-app> |
As you’ve noticed, any request for a PHP resources should trigger the Quercus Servlet to handle the initiated request. This Servlet will read the requested resource and make its interpretation operation to return a pure HTML code for your browser.
EmployeeDAO and ConnectionUtility
For seeking simplicity, we’ve developed EmployeeDAO and ConnectionUtility classes for handling all database operations.
ConnectionUtility.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
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://10.10.90.3:3306/journaldev", properties)); } return connection; } public void setConnection(Connection connection) { this.connection = connection; } } |
EmployeeDAO.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
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; } } |
Employee Registration Demo
Now, it’s time to see what’s the result of code developed above, but before getting into, you should create a Portal page named JournalDev and you must deploy your WAR into your Apache Pluto Portlet container after then. If you’ve not tried that before, it’s important for you to return back into our Apache Pluto Introduction to know how you can achieve these important tasks.
And when you try to register another employee with the same ID, you should face the following error:
Summary
Apache Pluto hasn’t provided you the way in which you can integrate your PHP views with its Portlet container. This tutorial is a good trial from JournalDev to make this possible by orchestrate different parties help you achieving that. Contribute us by commenting below and find downloaded source code.