Saturday, April 12, 2014

JSF - PrimeFaces Hello World using Jetty and Maven

PrimeFaces is an open source component library for JavaServer Faces (JSF). It provides a collection of mostly visual components (widgets) that can be used by JSF programmers to build the UI for a web application. An overview of these widgets can be found at the PrimeFaces showcase. The following post illustrates a basic example in which we will configure, build and run a Hello World PrimeFaces example using Jetty and Maven.


Tools used:
  • JSF 2.2
  • PrimeFaces 5.1
  • Jetty 8
  • Maven 3

First let's look at the below Maven POM file which contains the needed dependencies for our project. At the bottom of the dependencies list we find the PrimeFaces library. As PrimeFaces is built on top of 'JavaServer Faces' we also need to include the JSF dependencies. JSF is a component based Model–view–controller (MVC) framework which is built on top of the 'Servlet API' so we also need to include the Servlet dependency.

In order to run our example we need a servlet container (the component of a web server that interacts with Java servlets). There are a number of servlet containers implmenetations available, in the below example we will use Jetty which is a non-commercial pure Java-based HTTP (Web) server and Java Servlet container from the Eclipse Foundation. There is a Jetty Maven plugin which allows launching a Jetty instance from command line using Maven which has been configured so that the HTTP listener port is set to '9090' and the context path is set to 's4c'.
<?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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>info.source4code</groupId>
<artifactId>jsf-jetty-primefaces-helloworld</artifactId>
<version>1.0</version>
<packaging>war</packaging>

<name>JSF - PrimeFaces Hello World using Jetty and Maven</name>
<url>http://www.source4code.info/2014/04/jsf-primefaces-hello-world-jetty-maven.html</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.6</java.version>

<junit.version>4.12-beta-2</junit.version>
<servlet.version>3.0.1</servlet.version>
<jsf.version>2.2.8-02</jsf.version>
<primefaces.version>5.1</primefaces.version>

<maven-compiler-plugin.version>3.1</maven-compiler-plugin.version>
<jetty-maven-plugin.version>8.1.14.v20131031</jetty-maven-plugin.version>
</properties>

<dependencies>
<!-- JUnit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet.version}</version>
</dependency>
<!-- JSF -->
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>${jsf.version}</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>${jsf.version}</version>
</dependency>
<!-- PrimeFaces -->
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>${primefaces.version}</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${jetty-maven-plugin.version}</version>
<configuration>
<webAppConfig>
<contextPath>/s4c</contextPath>
</webAppConfig>
<connectors>
<connector
implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
<port>9090</port>
</connector>
</connectors>
</configuration>
</plugin>
</plugins>
</build>
</project>

Next is the HelloWorld class which is a simple POJO (Plain Old Java Object) that will provide data for the PrimeFaces (JSF) components. It contains the getters and setters for first and last name fields as well as a method to show a greeting.

In JSF, a class that can be accessed from a JSF page is called Managed Bean. By annotating the HelloWorld class with the @ManagedBean annotation it becomes a Managed Bean which is accessible and controlled by the JSF framework.
package info.source4code.jsf.primefaces;

import javax.faces.bean.ManagedBean;

@ManagedBean
public class HelloWorld {

private String firstName = "John";
private String lastName = "Doe";

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String showGreeting() {
return "Hello" + " " + firstName + " " + lastName + "!";
}
}

The web page that will be shown is a standard JSF page as defined below. It contains a number of PrimeFaces components which include two <p:inputText> fields, that will be used to enter a first and last name, surrounded by a <p:panel>. There is also a <p:dialog> component that shows a greeting message. The dialog is triggered by a <p:commandButton> that is part of the panel.

In order to use the PrimeFaces components, following namespace needs to be declared: xmlns:p="http://primefaces.org/ui
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">

<h:head>
<title>Hello World</title>
</h:head>

<h:body>
<h:form>

<p:panel header="Hello World">
<h:panelGrid columns="2" cellpadding="4">
<h:outputText value="First Name: " />
<p:inputText value="#{helloWorld.firstName}" />

<h:outputText value="Last Name: " />
<p:inputText value="#{helloWorld.lastName}" />

<p:commandButton value="Submit"
update="display" oncomplete="PF('dlg').show()" />

</h:panelGrid>
</p:panel>

<p:dialog header="Greeting" widgetVar="dlg" modal="true"
resizable="false">
<h:panelGrid id="display" columns="1"
cellpadding="4">
<h:outputText value="#{helloWorld.showGreeting()}" />

</h:panelGrid>
</p:dialog>

</h:form>
</h:body>
</html>

Java web applications use a deployment descriptor file to determine how URLs map to servlets and other information. This file is named 'web.xml', and resides in the application's WAR under the 'WEB-INF' directory. The below 'web.xml' contains the definition of the FacesServlet servlet class that will be used to manage the request processing lifecycle of our web page which contains JSF components. The page is mapped to the servlet by defining a mapping for all files ending with '.xhtml'.
Note that MyFaces and Mojarra register a servlet context listener for the startup configuration via the TLD file of the JSF core taglib. Jetty 8 uses the Glassfish JSP implementation which requires the TLD files to be on the classpath of the container which is not the case if the application is started via the Jetty Maven Plugin. In order to fix this the easiest solution is to simply add the config listener to the web.xml. For more information check this blog post.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">

<display-name>PrimeFaces HelloWorld Example</display-name>

<!-- Define the JSF listener class when using the Jetty Maven Plugin
with Jetty8 -->
<listener>
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>

<!-- File(s) appended to a request for a URL that is not mapped to a
web component -->
<welcome-file-list>
<welcome-file>helloworld.xhtml</welcome-file>
</welcome-file-list>

<!-- Define the JSF servlet (manages the request processing lifecycle
forJavaServer) -->
<servlet>
<servlet-name>faces</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<!-- Map following files to the JSF servlet -->
<servlet-mapping>
<servlet-name>faces</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
</web-app>

In order to run the above example open a command prompt and execute following Maven command:
mvn jetty:run

Maven will download the needed dependencies, compile the code and start a Jetty instance on which the web application will be deployed. The result should be the following Jetty startup trace ending with: 'Started Jetty Server'.
[INFO] --- jetty-maven-plugin:8.1.14.v20131031:run (default-cli) @ jsf-primefaces-helloworld ---
[INFO] Configuring Jetty for project: JSF - PrimeFaces HelloWorld example using Jetty
[INFO] webAppSourceDirectory not set. Defaulting to D:\source4code\code\jsf-primefaces-helloworld\src\main\webapp
[INFO] Reload Mechanic: automatic
[INFO] Classes = D:\source4code\code\jsf-primefaces-helloworld\target\classes
[INFO] Context path = /s4c
[INFO] Tmp directory = D:\source4code\code\jsf-primefaces-helloworld\target\tmp
[INFO] Web defaults = org/eclipse/jetty/webapp/webdefault.xml
[INFO] Web overrides = none
[INFO] web.xml file = file:/D:/source4code/code/jsf-primefaces-helloworld/src/main/webapp/WEB-INF/web.xml
[INFO] Webapp directory = D:\source4code\code\jsf-primefaces-helloworld\src\main\webapp
2014-07-05 13:52:33.306:INFO:oejs.Server:jetty-8.1.14.v20131031
2014-07-05 13:52:33.794:INFO:oejpw.PlusConfiguration:No Transaction manager found - if your webapp requires one, please configure one.
5-jul-2014 13:52:35 com.sun.faces.config.ConfigureListener contextInitialized
INFO: Initializing Mojarra 2.2.7 ( 20140610-1547 https://svn.java.net/svn/mojarra~svn/tags/2.2.7@13362) for context '/s4c'
5-jul-2014 13:52:35 com.sun.faces.spi.InjectionProviderFactory createInstance
INFO: JSF1048: PostConstruct/PreDestroy annotations present. ManagedBeans methods marked with these annotations will have said annotations processed.
5-jul-2014 13:52:36 org.primefaces.webapp.PostConstructApplicationEventListener processEvent
INFO: Running on PrimeFaces 5.0
2014-07-05 13:52:36.358:WARN:oejsh.RequestLogHandler:!RequestLog
2014-07-05 13:52:36.378:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:9090
[INFO] Started Jetty Server

Open a web browser and enter following URL: http://localhost:9090/s4c/. The result should be that below page is displayed:


Enter a first and last name and press the Submit button. A pop-up dialog will be shown with a greeting message.



github icon
If you would like to run the above code sample you can download the full source code and their corresponding JUnit test cases here.

This concludes the PrimeFaces Hello World example. If you found this post helpful or have any questions or remarks, please leave a comment.

3 comments:

  1. Nice script! i really enjoyed to read this. A lot of informative stuff. Thanks

    ReplyDelete
  2. Thanks a lot very much for the high quality and results-oriented help. I won’t think twice to endorse your blog post to anybody who wants and needs support about this area.
    Azure Training in Chennai

    ReplyDelete