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.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
entity (Model) that would be created according for employee Table figured above will be:
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 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.
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
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 |
<html xmlns="https://www.w3.org/1999/xhtml" xmlns:ui="https://java.sun.com/jsf/facelets" xmlns:h="https://java.sun.com/jsf/html" xmlns:f="https://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.
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 |
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
1 2 3 4 5 6 7 8 9 10 11 12 |
<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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<!-- 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
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 |
<!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-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
1 2 3 4 5 6 7 8 9 10 11 12 |
<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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<!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-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
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 |
<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>EmployeeRegistration-JSFBridge</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>EmployeeRegistration-JSFBridge</name> <url>https://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.
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, 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; } } |
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://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.
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.
But what’s happened if we’ve tried to register already registered employees.
What’s happened if we register a new employee.
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.