Showing posts with label Managed Bean. Show all posts
Showing posts with label Managed Bean. Show all posts

Saturday, April 18, 2020

JSF 2.3 tutorial with Eclipse, Maven, WildFly and H2

Introduction

In this tutorial you will learn how to set up a JSF (Jakarta Faces) 2.3 development environment with the Eclipse IDE, the Maven dependency management system, the WildFly application server, and the H2 database from scratch.

Noted should be this tutorial was originally written by me for the “From Zero to Hello World” chapter of the book The Definitive Guide to JSF in Java EE 8, published at May 30, 2018. But as technology changes quickly, that chapter is currently slightly outdated. This tutorial is basically a rewrite of that chapter conform the current state of technology. Moreover, it covered Payara application server only while we’d like to use WildFly application server instead (whose JEE8 version wasn’t yet available at time of writing of the book, around Q4 of 2017).

Back to top

Installing Java SE JDK

You probably already know that Java SE is available as a JRE for end users and as a JDK for software developers. Eclipse itself does not strictly require a JDK as it has its own compiler. JSF being a software library does not require a JDK to run either. WildFly, however, does require a JDK to run, primarily in order to be able to compile JSP files, even though JSP has been deprecated as JSF view technology since JSF 2.0.

Therefore, you need to make sure that you already have a JDK installed as per Oracle’s instructions. The current Java SE version is 14, but as Jakarta EE 8 was designed for Java SE 8, you could get away with a minimum version of Java SE 8. Installation instructions depend on the platform being used (Windows, Linux, or macOS). You can find detailed Java SE 14 JDK installation instructions here.

The most important parts are that the PATH environment variable covers the /bin folder containing the Java executables (e.g., /path/to/jdk/bin), and that the JAVA_HOME environment variable is set to the JDK root folder (e.g., /path/to/jdk). This is not strictly required by JSF, but Eclipse and WildFly need this. Eclipse will need the PATH in order to find the Java executables. WildFly will need the JAVA_HOME in order to find the JDK tools.

Back to top

What About Jakarta EE?

First a small bit of history: “Java EE” has been renamed to “Jakarta EE” in February 2018, and the first Jakarta EE release, the Jakarta EE 8, became available in September 2019. So, anything related to “Java EE” is currently outdated. This includes the currently still available “Java EE SDK” download from Oracle.com. You should ignore that.

JSF itself is part of Jakarta EE. Jakarta EE is basically an abstract specification of which the so-­called application servers represent the concrete implementations. Examples of those application servers are Eclipse Glassfish, JBoss EAP, JEUS, Open Liberty, Payara Server, Primeton Appserver and WildFly. You can find them all at the Jakarta EE Compatible Products page. It are exactly those application servers that actually provide among others JSF, EL (Expression Language), JSTL (Jakarta Server Tag Library), CDI (Contexts and Dependency Injection), EJB (Enterprise JavaBeans), JPA (Java Persistence API), Servlet, WebSocket, and JSON-P APIs out of the box.

There also exist so-called servlet containers which provide basically only the Servlet, JASPIC, JSP, EL, and WebSocket APIs out of the box, such as Tomcat and Jetty. Therefore, it would require some work to manually install and configure among others JSF, JSTL, CDI, EJB, JPA and/or JSON-P on such a servlet container. It is not even trivial in the case of EJB as it basically requires modifying the servlet container’s internals. That is, by the way, exactly why TomEE exists. It’s a Java EE application server built on top of the barebones Tomcat servlet container engine. Note that TomEE is at the time of writing still not Jakarta EE compatible, so it’s not listed in the Jakarta EE Compatible Products page.

Back to top

Installing WildFly

WildFly is an open source Jakarta EE application server from Red Hat. You can download it from wildfly.org. Make sure you choose the “Jakarta EE Full & Web Distribution" download and not, for example, the “WildFly Preview EE 9 Distribution” or “Servlet-Only Distribution”. Here’s a direct link to the ZIP file: 18.0.1.Final.

Installing is basically a matter of unzipping the downloaded file and putting it somewhere in your home folder. We’ll leave it there until we have Eclipse up and running, so that we can then integrate WildFly in Eclipse and let Eclipse manage the WildFly application server.

Back to top

Installing Eclipse

Eclipse is an open source IDE written in Java. You can download it from eclipse.org. It is basically like notepad but then with thousands if not millions of extra features, such as automatically compiling class files, building a WAR (Web Application Archive) file with them, and deploying it to an application server without the need to manually fiddle around with javac in a command console.

Eclipse is available in a lot of flavors, even for C/C++ and PHP. As we’re going to develop with Jakarta EE, we need the one saying “Eclipse IDE for Enterprise Java developers”, importantingly the one with “Enterprise” in its name. The one without it doesn’t contain the mandatory plug-ins for developing Jakarta EE web applications. Here’s a direct link to the main download page of currently available latest version: 2020-03. In the section “Download Links” you can find platform-specific versions (Windows, Linux, or macOS).

Also here, installing is basically a matter of unzipping the downloaded file and putting it somewhere in your home folder.

In Windows and Linux you’ll find the eclipse.ini configuration file in the unzipped folder. In Mac OS this configuration file is located in Eclipse.app/Contents/Eclipse. Open this file for editing. We want to increase the allocated memory for Eclipse. At the bottom of eclipse.ini, you’ll find the following lines:

-Xms256m
-Xmx2048m

This sets, respectively, the initial and maximum memory size pool which Eclipse may use. This is a bit too low when you want to develop a bit decent Jakarta EE application. Let’s at least double both the values:

-Xms512m
-Xmx4g

Watch out that you don’t declare more than the available physical memory in the Xmx setting. When the actual memory usage exceeds the available physical memory, it will continue into virtual memory, usually in a swap file on disk. This will greatly decrease performance and result in major hiccups and slowdowns.

Now you can start Eclipse by executing the eclipse executable in the unzipped folder. You will be asked to select a directory as workspace. This is the directory where Eclipse will save all workspace projects and metadata.

After that, Eclipse will show a welcome screen. This is not interesting for now. You can click the Workbench button on the right top to close the welcome screen. Untick if necessary “Always show Welcome at start up” on the bottom right. After that, you will enter the workbench. By default, it looks like this:

Back to top

Configuring Eclipse

Before we can start writing code, we would like to fine-tune Eclipse a bit so that we don’t eventually end up in trouble or with annoyances. Eclipse has an enormous amount of settings, and some of its default values should not have been the default values. You can verify and configure the settings via Window ➤ Preferences.

  • General ➤ Workspace ➤ Text file encoding must be set to UTF-­8. Particularly in Windows this might otherwise default to the proprietary encoding CP-1252 which supports only 255 different characters and does not support any characters beyond the Latin range. When reading and saving Unicode files with CP-1252, you risk seeing unintelligible sequences of characters. This is also called “Mojibake”. For more background information on character encodings, see my old but still very relevant blog article Unicode - How to get the characters right?
  • General ➤ Workspace ➤ New text file line delimiter must be set to Unix. It works just fine on Windows as well. This will particularly keep version control systems happy. Otherwise, developers pulling code on different operating systems might face confusing conflicts or diffs caused by different line endings.
  • General ➤ Editors ➤ Text editors ➤ Spelling should preferably be disabled. This will save you from a potentially big annoyance, because it unnecessarily also spellchecks technical entries in XML configuration files such as faces-config.xml and web.xml for nothing, causing confusing warnings in those files such as “*.xhtml is not correctly spelled”.
  • Java ➤ Installed JREs must be set to the JDK, not to the JRE. This setting will normally also be used to execute the integrated application server which usually requires the JDK.
  • Java ➤ Compiler ➤ Compiler compliance level must be set to at least 1.8. This is the minimum required Java version for Jakarta EE 8. You can of course also pick a higher version. For example 11 will work just fine. We’ll use that version in the remainder of this tutorial. It’s also going to be the minimum required Java version of the upcoming Jakarta EE 9.
Back to top

Integrating New Server in Eclipse

We need to familarize Eclipse with any installed application server so that Eclipse can seamlessly link its Jakarta EE API libraries in the project’s build path (read: the compile time classpath of the project). This is mandatory in order to be able to import classes from the Jakarta EE API in your project. You know, the application server itself represents the concrete implementation of the abstract Jakarta EE API.

In order to integrate a new application server in Eclipse, first check the bottom section of the workbench with several tabs representing several Views (you can add new ones via Window ➤ Show View). Click the Servers tab to open the servers view.

Click the link which literally says “No servers are available. Click this link to create a new server...”. It’ll show the New Server wizard, displaying a list of available server types. From the list, select Red Hat JBoss Middleware ➤ JBoss AS, WildFly, & EAP Server Tools.

After clicking Next, it will download the plug-in in the backgroud and request you to accept the license agreement before installing the plug-in. This plug-in is mandatory in order to manage any JBoss server from inside the workbench. This will allow you to add and remove Eclipse projects to the deployments folder of the server, as well as starting and stopping the server, and running the server in debug mode.

Let it finish downloading and installing the plug-in in the background. Confirm any possible warning of “unsigned software”. This is okay. Finally it will request you to restart Eclipse. Take action accordingly.

Once returned into the workspace, click the same link in the Servers view again. You’ll now see a JBoss Community ➤ WildFly 18 option. Noted should be that WildFly 19 was just recently available at the time of writing, but the JBoss plug-in is not yet updated for it. If it is available for you, of course pick it instead.

Advance to the next step. Just leave this screen default.

Advance to the next step. Here, you should point the Home Directory field to the folder of the WildFly installation, there where you have unzipped it after downloading. And, you should adjust the Execution Environment to the desired JDK version. Pick JavaSE-11.

Complete the remainder of the New Server wizard with default settings. You don’t need to edit any other fields. The newly added server will now appear in the Servers view.

Back to top

Creating New Project in Eclipse

We’re now ready to create a new project for our JSF application in Eclipse. This can be done via the left section of the workbench which by default shows only one tab representing the Project Explorer view (also here, you can add new views via Window ➤ Show View). By default, when there are no projects in your workspace, then it shows a list of options to create a new project. These options are also available via File ➤ New.

Eclipse, being an IDE for many different project tasks, offers a bewildering amount of different project types from which to choose. For a Jakarta EE-based application which is going to be deployed as a simple WAR file, there are basically two project types that we could choose from: Dynamic Web Project or Maven Project.

The difference is that the first is an Eclipse native project that really only works on Eclipse, while the latter is a universal type of project that can be built by any IDE, as well as easily on the command line and by various CI servers such as Travis and Jenkins. For this reason, the Maven project type is really the only viable choice.

In the next step, make sure that the option Create a simple project (skip archetype selection) is checked.

This will let us start with a really empty Maven project so that we can configure and populate it ourselves. Of course, you could also choose from an archetype, which is basically a template project with several already prepared files and configurations. But we don’t need any for now.

In the next step, we can specify our own Maven coordinates of the project. The Maven coordinates consist of, among others, Group Id, Artifact Id, and Version, also known as GAV in the Maven world. The Group Id usually matches the root package name you’re going to use, such as com.example. The Artifact Id usually represents the project name you’re going to use. For simplicity, we’ll use project. The Version can be kept default at 0.0.1-SNAPSHOT. Finally the Packaging must be set to war (Web Application Archive). This will during the build procude a WAR file instead of a JAR file.

Now click Finish. You don’t need to edit any other fields. Once you’ve finished the wizard, you’ll get to see the project structure in the Project Explorer view.

Unfortunately, the Eclipse-generated pom.xml, which is the main indicator of the project being a Maven project and containing its configuration, is less than ideal. It’s not current any more, even when generated by the latest Eclipse, the 2020-03 (released at March 2020).

You can already see that by the pom.xml file being marked with an alarming red cross and an error message in the Markers view. Any project that has at least one such red cross cannot be built and won’t be deployable.

The error message literally says “web.xml is missing and <failOnMissingWebXml> is set to true.” In other words, Maven somehow thinks that it’s still a pre-Java EE 6 project, when this was indeed disallowed. In order to solve this problem and to catch up the Eclipse-generated pom.xml with the current standards, we need to open pom.xml for editing and adjust it to look exactly like follows:

<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>com.example</groupId>
    <artifactId>project</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <failOnMissingWebXml>false</failOnMissingWebXml>
    </properties>

    <dependencies>
        <dependency>
            <groupId>jakarta.platform</groupId>
            <artifactId>jakarta.jakartaee-api</artifactId>
            <version>8.0.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>

Once you save this file, Eclipse will automatically sort it out by itself and clear out the alarming red cross. Now that looks much better.

We’ll briefly go through the most important settings here.

  • Packaging war — indicates the project is a “web” project, and that the project’s contents will be assembled into a WAR (Web Application Archive) file.
  • Encoding UTF-8 — sets the encoding that the source files are in and with which the (reporting) output files should be generated. This makes the build repeatable, as it otherwise would default to the system default encoding.
  • Compiler 11 — sets the version of Java SE used in the .java source files as well as the byte code output in the .class files. Without setting this, Maven defaults to the oldest version possible, and sometimes even a lower version than that.
  • failOnMissingWebXml false — older versions of Java EE required the /WEB-INF/web.xml file to be physically present in the WAR project. Even though this has not been required any more since Java EE 6, which was released in 2009, Maven still checks for this file to be present. Setting this to false prevents this unnecessary check.
  • Dependency jakarta.platform:jakarta.jakartaee-api:8.0.0:provided — this declares a dependency on the Jakarta EE 8 API, and makes sure all the Jakarta EE types like FacesServlet, @Named and @Entity are known to the compiler. This dependency is set to provided since those types are in our case already provided by the target runtime, which is WildFly 18, a Jakarta EE 8 compatible application server. This dependency will then only be used to compile the source code against, and the associated JAR files won’t be included in the generated WAR file. You need to make absolutely sure that any compile time dependency which is already provided by the target runtime is set to provided; otherwise it will eventually end up in the generated WAR file and you may run into class loading trouble wherein duplicate different versioned libraries are conflicting with each other. In case you’re actually not targeting a full-fledged Jakarta EE server but a barebones servlet container, such as Tomcat, then you would need to adjust the dependencies as instructed in the installation instructions of Mojarra, one of the available JSF implementations and actually the one used under the covers of WildFly.

Now, in Eclipse’s Markers view, there are two warnings left which say “The compiler compliance specified is 1.5 but a JRE 14 is used” and “Build path specifies execution environment J2SE-1.5. There are no JREs installed in the workspace that are strictly compatible with this environment”. Well, this basically means that Eclipse recognizes this Maven project as a Java SE 1.5-only project while we don’t actually have Java SE 5 installed, and in spite of the compiler version in pom.xml being set to 11. This is an Eclipse+Maven quirk. Eclipse clearly knows how to find the configured compiler version in pom.xml, but unfortunately refuses to automatically adjust its project settings based on that.

In order to tell Eclipse that this is really a Java SE 11 targeted project, we need to right-click the project in Project Explorer view and choose Properties. In the Project Facets section you should change the version of the “Java” entry from 1.5 to 11 (or whatever compiler version specified in pom.xml).

While at it, we also need to update the Servlet API version and add the JSF and JPA facets. The Servlet API is represented by the “Dynamic Web Module” entry. This needs to be set to version 4.0, which matches Jakarta EE 8. Further the “JavaServer Faces” and “JPA” entries need to be selected.

As you can see in the yellow warning bar, Eclipse requires further configuration. This concerns the newly selected JSF and JPA facets. Click the link. We get to see the Modify Faceted Project wizard.

The first step of the Modify Faceted Project wizard allows us to configure the JPA facet. We need to make sure that Eclipse is being instructed that the JPA implementation is already provided by the target runtime and thus Eclipse doesn’t need to include any libraries. This can be achieved by choosing the “Disable Library Configuration” option in the JPA implementation field.

As we’re going to use the WildFly-provided Hibernate as the actual JPA implementation, which supports automatically discovering of @Entity annotated classes, we’d like to instruct Eclipse to do the same. So, choose the “Discover annotated classes automatically” option in the Persistent class management field. Otherwise Eclipse would automatically add entities to the persistence.xml file when going through the entity code generation wizards, or it would show warnings when we manually create one and don’t add it to the persistence.xml.

Note that configuring a database connection (for Eclipse’s built-in data explorer) is not necessary for now as we’re going to use an embedded database.

In the next step of the Modify Faceted Project wizard, we can configure the JSF capabilities. Also here, we need to make sure that Eclipse is being instructed that the JSF implementation is already provided by the target runtime and thus Eclipse doesn’t need to include any libraries. This can be achieved by choosing the “Disable Library Configuration” option in the JSF Implementation Library field.

Further, we need to rename the servlet name of the FacesServlet to match the fictive instance variable name: facesServlet. Last but not least, we absolutely need to change the URL mapping pattern from the jurassic /faces/* to the modern *.xhtml.

Actually, the entire registration of the FacesServlet in web.xml is since JSF 2.2 not strictly necessary any more; you could even uncheck the Configure JSF servlet in deployment descriptor option and rely on the default auto-registered mappings of /faces/*, *.faces, *.jsf and *.xhtml. However, as this allows endusers and even searchbots to open the very same JSF page by different URLs, and thus causes confusion among endusers and duplicate content penalties among searchbots, we’d better restrict to only one explicitly configured URL pattern of *.xhtml. For more background information on JSF URL patterns, see also this Stack Overflow post.

Now, finish and apply all the wizards and dialogs.

Unfortunately, the JPA plug-in of the current Eclipse version only puts the generated persistence.xml in the wrong place. It’s basically not being aware of the “Dynamic Web Project” (WAR) project facet being enabled and Eclipse’s JPA plug-in blindly puts it in the src/main/java/META-INF folder as if it were a JAR project. This is wrong. You need to manually move it into src/main/resources/META-INF folder conform the rules of a WAR project. The workbench must now look like as follows:

Back to top

Adjusting Deployment Descriptors

We only need to verify and adjust all the deployment descriptors to catch up to the Servlet, JSF, JPA, and CDI versions actually used by the target runtime. This is normally done by editing the root element of the deployment descriptor XML file to set the desired version attribute along with version-specific XML schema definitions (XSDs).

You can find all Jakarta EE 8 XSDs at http://xmlns.jcp.org/xml/ns/javaee, which is an actual web page which currently redirects to some landing page at Oracle.com. This may change in the future given that Jakarta EE 8 is currently in the process of being transferred from Oracle to Eclipse, and moreover the javaee part may in the future even be renamed. At this landing page, click the “Java EE 8 Schema Resources” link to see a list of the correct XSD versions. Yes, the Java EE 8 XSDs are still appplicable to Jakarta EE 8.

You can open the deployment descriptor XML file for editing by double-clicking it in the Project Explorer and then selecting the Source tab in the editor. The correct root element declarations for Jakarta EE 8 compatible deployment descriptors are thus as follows:

1. src/main/webapp/WEB-INF/web.xml for Servlet 4.0:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="4.0"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
        http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
>
    <!-- Servlet configuration here. -->
</web-app>

Make sure that the FacesServlet as we created in the Modify Faceted Project wizard is indeed there and that it’s indeed mapped on an URL pattern of *.xhtml.

Unfortunately, the currently available Eclipse version might annoyingly freeze for ~15 seconds during saving the web.xml file when its xsi:schemalocation references XSD file of version 4.0. This is caused by Eclipse Bug 534776. There is so far no clear work around yet. You could only remove the xsi:schemalocation attribute to avoid this from happening. The disadvantage of removing this is that the contents of the web.xml file cannot anymore be autocompleted during typing, nor be validated by Eclipse, and thus e.g. typos may slip through.

2. src/main/webapp/WEB-INF/faces-config.xml for JSF 2.3:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="2.3"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
        http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_3.xsd"
>
    <!-- JSF configuration here. -->
</faces-config>

As of now it’s indeed empty.

3. src/main/resources/META-INF/persistence.xml for JPA 2.2:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2"
    xmlns="http://xmlns.jcp.org/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
        http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
>
    <!-- JPA configuration here. -->
</persistence>

As of it indeed only contains the default persistence unit. We’ll reconfigure it later on.

4. src/main/webapp/WEB-INF/beans.xml for CDI 2.0:

For sake of completeness we need to manually create one more deployment descriptor file, the one for CDI 2.0. This isn’t automatically generated as it’s not required. CDI is by default always enabled in any Jakarta EE 8 compatible web application. It’s even mandatory for the functioning of JSF. Among others the new <f:websocket> relies fully on CDI for tracking the opened web sockets.

Right-click the WEB-INF folder of the project and choose New ➤ File. Give it the name beans.xml. Populate the new file as follows:

<?xml version="1.0" encoding="UTF-8"?>
<beans version="2.0" bean-discovery-mode="annotated"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
        http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
>
    <!-- CDI configuration here. -->
</beans>

Note that the bean-discovery-mode is set to annotated. This is the default value. The other value is all. This is slightly more intrusive and expensive as it will consider any Java class as a potential CDI bean.

Back to top

Configuring JSF

JSF has a lot of settings available which can be configured via <context-param> entries in web.xml. You can find an overview of them in this Stack Overflow post.

The default configuration is okay to start with, but there’s one peculiar setting which we really want to set right from the beginning on. It’s the setting which instructs JSF whether to interpret empty string submitted values as null. Elaborate background information can be found in my another blog article The empty String madness.

This can be done by adding the following section to top of the web.xml:

<context-param>
    <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
    <param-value>true</param-value>
</context-param>

Back to top

Creating the Backing Bean Class

With the project now correctly configured we can finally start with developing the actual MVC application. The Controller part of MVC is already configured as FacesServlet in web.xml. The Model part of MVC is what we’re going to create now. It’s basically just a simple Java class which is by JSF convention called a Backing Bean since it “backs” a View.

Right-click the src/main/java folder of the project and choose New ➤ Class. The New Java Class wizard will now appear. In this wizard, set the Package to com.example.project.view, set the Name to Bean. The rest of the fields can be kept default or empty.

The class editor will now open with the newly created backing bean class. We’ll modify it to add CDI @Named and @RequestScoped annotations on the class, so that it becomes a CDI managed bean. And we need to add two properties, input and output, and accompany the input property with a getter and setter pair, the output property with only a getter, so that these can be referenced from the view. Finally we’ll add a submit() action method which prepares the output property based on the input property, so that this can be invoked from the view.

As a hint, in Eclipse after entering the properties, you can right-­click anywhere in the class editor and choose Source ➤ Generate Getters and Setters to have the IDE to generate them.

In its entirety, the edited backing bean class should look as follows:

package com.example.project.view;

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named @RequestScoped
public class Bean {

    private String input;
    private String output;

    public void submit() {
        output = "Hello World! You have typed: " + input;
    }

    public String getInput() {
        return input;
    }

    public void setInput(String input) {
        this.input = input;
    }

    public String getOutput() {
        return output;
    }
}

We’ll briefly go through the annotations that are used here.

  • @Named — gives the bean a name, which is primarily used to reference it via EL in the view. Without any attributes this name defaults to the simple class name with the first letter in lowercase, thus “bean” here. It will be available by #{bean} in EL. This can be used in JSF pages.
  • @RequestScoped — gives the bean a scope, which means that the same instance of the bean is used throughout the given lifespan. In the case of @RequestScoped that lifespan is the duration of an HTTP request. When the scope ends, then the bean is automatically destroyed. There are more scopes available, such as @ViewScoped, @SessionScoped and @ApplicationScoped. You can read more about scopes in this Stack Overflow post.
Back to top

Creating the Facelets File

Next, we’ll create the View part of MVC. It’s basically just a XHTML file which is by JSF interpreted as a Facelets file or just “Facelet”. When the FacesServlet is invoked with an URL matching the path of this Facelets file, then JSF will ultimately parse it and generate the HTML markup that is sent to the browser as a response to the request. With help of EL, it can reference a bean property and invoke a bean action.

Right-click the webapp folder of the project and choose New ➤ File. Give it the name test.xhtml.

The HTML editor will now open with the newly created Facelets file. It’s initially empty. Fill it with the following content:

<!DOCTYPE html>
<html lang="en"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
>
    <h:head>
        <title>Hello World</title>
    </h:head>
    <h:body>
        <h1>Hello World</h1>
        <h:form>
            <h:outputLabel for="input" value="Input" />
            <h:inputText id="input" value="#{bean.input}" />
            <h:commandButton value="Submit" action="#{bean.submit}">
                <f:ajax execute="@form" render=":output" />
            </h:commandButton>
        </h:form>
        <h:outputText id="output" value="#{bean.output}" />
    </h:body>
</html>

We’ll briefly go through the JSF-specific XHTML tags that are used here.

  • <h:head> — generates the HTML <head> element. It gives JSF the opportunity to automatically include any necessary JavaScript files, such as the one containing the necessary logic for <f:ajax>.
  • <h:body> — generates the HTML <body> element. You can also use a plain HTML <body> in this specific Facelet example, but then it doesn’t give any other JSF tag the opportunity to automatically include any necessary JavaScript in the end of the HTML <body>.
  • <h:form> — generates the HTML <form> element. JSF will automatically include the so-called view state in a hidden input field within the form.
  • <h:outputLabel> — generates the HTML <label> element. You can also use a plain HTML <label> in this specific Facelet, but then you’d have to manually take care of figuring out the actual ID of the target input element.
  • <h:inputText> — generates the HTML <input type="text"> element. JSF will automatically get and set the value in the bean property specified in the value attribute.
  • <h:commandButton> — generates the HTML <input type="submit"> element. JSF will automatically invoke the bean method specified in the action attribute.
  • <f:ajax> — generates the necessary JavaScript code to enable Ajax behavior of the tag it is being nested in, in this case thus the <h:commandButton>. You can also do as good without it, but then the form submit won’t be performed asynchronously. The execute attribute of @form indicates that the entire <h:form> where it is sitting in must be processed on submit, and the render attribute of :output indicates that the tag identified by id="output" must be automatically updated on complete of the Ajax submit. For more background information on the syntax of the execute and render attributes, see this Stack Overflow post.
  • <h:outputText> — generates the HTML <span> element. This is the one being updated on completion of the Ajax submit. It will merely print the bean property specified in the value attribute.

Those JSF-specific XHTML tags are also called “JSF components”. Note that you can also perfectly embed plain vanilla HTML in a Facelets file. JSF components should only be used when the functionality requires so, or is more easily achievable with them.

Noted should be that a HTML5 doctype is indeed explicitly being used “in spite of” that it’s a XHTML file. HTML5 is these days the standard for web pages. For more background information on this, see this Stack Overflow post.

Back to top

Deploying the Project

In the Servers view, right-click the WildFly server entry and choose Add and Remove. It will show the Add and Remove wizard which gives you the opportunity to add and remove WAR projects to the server. Do so for our newly created project and finish the wizard.

Now start the WildFly server. You can do so by selecting it and then clicking the green arrow icon whose tool tip says “Start the server”. You can, of course, also use the bug icon whose tooltip says “Start the server in debug mode”. The Console view will briefly show the server startup log. Wait until the server starts up and has, in the Servers view, gained the status Started.

Now, open a tab in your favorite web browser and enter the web address http://localhost:8080/project-0.0.1-SNAPSHOT/test.xhtml in order to open the newly created JSF page. Play a bit around with it.

Coming back to the URL, the “localhost:8080” part is by convention the default domain of any Jakarta EE server which is running in development mode. The same address is also used by, among others, Payara and TomEE. The “/project-0.0.1-SNAPSHOT” part is by default the filename of the Maven-generated WAR file. In case of WildFly, you can find it in its /standalone/deployments folder. This part is in Servlet terms called the “context path” and obtainable by HttpServletRequest#getContextPath() and in JSF delegated by ExternalContext#getRequestContextPath().

If you have hard time in figuring out the actually used context path, then you can usually find it in the server logs. The exact logger line is however dependent on the server being used. In case of WildFly, it’ll be the line identified by WFLYUT0021. Open the Console view, press Ctrl+F and search for WFLYUT0021. It’ll show the following line:

INFO  [org.wildfly.extension.undertow] (ServerService Thread Pool -- 42) WFLYUT0021: Registered web context: '/project-0.0.1-SNAPSHOT' for server 'default-server'

The context path part can also be set to “/”. The deployed web application will then end up in the domain root. How to do that depends on the server being used. In case of WildFly, you’ll need to create the JBoss-specific jboss-web.xml as follows:

src/main/webapp/WEB-INF/jboss-web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss-web PUBLIC
    "-//JBoss//DTD JBOSS 5.0//EN"
    "http://www.jboss.org/j2ee/dtd/jboss-web_5_0.dtd"
>
<jboss-web>
    <context-root>/</context-root>
</jboss-web>

Now it will be deployed to the domain root and after restarting the server you can access the JSF page by http://localhost:8080/test.xhtml.

We can even get a step further by making test.xhtml the default landing file so that this also doesn’t need to be specified in the URL. This can be achieved by adding the following entry to the bottom of web.xml:

<welcome-file-list>
    <welcome-file>test.xhtml</welcome-file>
</welcome-file-list>

This will basically instruct the server to use the specified file within the folder as default resource when any folder is requested. So, if for example / folder is requested, then it’ll search for a /test.xhtml and serve it. Or if for example /foo folder is requested, then it’ll search for a /foo/test.xhtml and serve it. Etcetera. Now, save the web.xml and restart the server.

Coming back to the web browser, you’ll notice that the JSF page is now also accessible by merely http://localhost:8080.

Back to top

Installing H2

H2 is an in-memory SQL database. It’s an embedded database useful for quickly modeling and testing JPA entities, certainly in combination with autogenerated SQL tables based on JPA entities. Adding H2 to your web application project is a matter of adding the following dependency to the <dependencies> section of the pom.xml file:

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.200</version>
</dependency>

That’s basically it. Its JDBC (Java Database Connecivity) driver is also provided by this dependency.

Back to top

Configuring DataSource

In order to be able to interact with any SQL database, we need to configure a so-called data source in the web application project. This can be done by adding the following section to the web.xml:

<data-source>
    <name>java:global/DataSourceName</name>
    <class-name>org.h2.jdbcx.JdbcDataSource</class-name>
    <url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1</url>
</data-source>

It basically creates a connection pooled data source in the server itself. The data source <name> represents the JNDI (Java Naming and Directory Interface) name. The “java:global/” part is mandatory. The DataSourceName is free to your choice. It’s the one that ultimately needs to be registered in persistence.xml later on. The <class-name> represents the fully qualified name of the javax.sql.DataSource implementation of the JDBC driver being used. The <url> represents the JDBC driver-­specific URL format. The syntax is dependent on the JDBC driver being used. Usually the syntax can be found in the JDBC driver specific documentation. For an in-­memory H2 database with a database name of “test,” that’s thus jdbc:h2:mem:test. The H2-specific DB_CLOSE_DELAY=-1 path parameter basically instructs its JDBC driver not to automatically shut down the database when it hasn’t been accessed for some time, even though the application server is still running.

After configuring the data source, a concrete instance of the javax.sql.DataSource can now be injected in any servlet container managed artifact such as a plain vanilla servlet or filter as follows:

@Resource
private DataSource dataSource;

You could get a SQL connection from it via DataSource#getConnection() for the plain old JDBC work. However, as we’re going to use pure Jakarta EE, it’s better to use Jakarta EE’s own JPA for this instead.

Back to top

Configuring JPA

In order to familiarize JPA with the newly added data source, we need to add a new persistence unit to the persistence.xml which uses the data source as a JTA data source.

<persistence-unit name="PersistenceUnitName" transaction-type="JTA">
    <jta-data-source>java:global/DataSourceName</jta-data-source>
    <properties>
        <property
            name="javax.persistence.schema-generation.database.action"
            value="drop-and-create" />
    </properties>
</persistence-unit>

You see, the data source is identified by its JNDI name which we confgured earlier in web.xml.

You’ll also notice a JPA-­specific javax.persistence.schema-generation.database.action property with a value of “drop-and-create” which basically means that the web application should automatically drop and create all SQL tables based on JPA entities. This is, of course, only useful for prototyping purposes, as we’re basically doing in this tutorial. For real-world applications, you’d better pick either “create” or “none” (which is the default).

The transaction type being set to “JTA” basically means that the application server should automatically manage database transactions. This way every method invocation on an EJB from its client (usually, a JSF backing bean) transparently starts a new transaction and when the EJB method returns to the client (usually, the calling backing bean), the transaction is automatically committed and flushed. And, any runtime exception from an EJB method automatically rolls back the transaction. For more information on usefulness of this, see also this Stack Overflow post.

Back to top

Creating the JPA Entity

Now we’re going to create a JPA entity. Basically, it’s a JavaBean class which represents a single record of a database table. Each bean property is mapped to a particular column of the database table. Normally, JPA entities are modeled against existing database tables. But, as you’ve read in the previous section, “Configuring JPA”, about the persistence.xml, it’s also possible to do it the other way round: database tables are generated based on JPA entities. This is not recommended for production applications, but it’s useful for prototyping as we’re basically doing in this tutorial.

Right-click the src/main/java folder of the project and choose New ➤ JPA Entity. In the wizard, set the Java package to com.example.project.model and set the Class name to Message. The rest of the fields can be kept default or empty.

Modify the new entity class as follows:

package com.example.project.model;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.validation.constraints.NotNull;

@Entity
public class Message implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false) @Lob
    private @NotNull String text;

    // Add/generate getters and setters.
}

As a reminder, you can let Eclipse generate getters and setters by right-clicking anywhere in the class editor and choosing Source ➤ Generate Getters and Setters.

We’ll briefly go through the annotations that are used here.

  • @Entity — marks the bean as a JPA entity, so that the JPA implementation will automatically collect database-related metadata based on all its properties.
  • @Id @GeneratedValue(strategy=IDENTITY) — marks a property to be mapped to a SQL database column of “IDENTITY” type. In MySQL terms, that’s the equivalent of “AUTO_INCREMENT”. In PostgreSQL terms, that’s the equivalent of “BIGSERIAL”.
  • @Column — marks a property to be mapped to a regular SQL database column. The actual SQL database column type depends on the Java type being used. In case of a Java String, without the additional @Lob annotation, that’s by default a VARCHAR(255) whose length can be manipulated by ­ @Column(length=n). With the @Lob annotation present, however, the SQL database column type becomes by default TEXT.
  • @Lob — marks a String property to be mapped to a SQL database column of type TEXT instead of a limited VARCHAR.
  • @NotNull — this is actually not part of JPA but of “Bean Validation”. To the point, it ensures that the bean property is being validated never to be null when submitting a JSF form and when persisting the JPA entity. Also note that this basically replicates the @Column(nullable=false), but that’s only because JPA doesn’t consider any Bean Validation annotations as valid database metadata in order to generate appropriate SQL tables.
Back to top

Creating the EJB Service

Next, we need to create an EJB in order to be able to save an instance of the aforementioned JPA entity in the database, and to obtain a list of them from the database. Right-click the src/main/java folder of the project and choose New ➤ Class. In the wizard, set the Package to com.example.project.service and set the Name to MessageService. The rest of the fields can be kept default or empty.

Modify the new service class as follows:

package com.example.project.service;

import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import com.example.project.model.Message;

@Stateless
public class MessageService {

    @PersistenceContext
    private EntityManager entityManager;

    public void create(Message message) {
        entityManager.persist(message);
    }

    public List<Message> list() {
        return entityManager
            .createQuery("FROM Message m", Message.class)
            .getResultList();
    }
}

That’s basically it. Let’s briefly go through the annotations.

  • @Stateless — marks the bean as a stateless EJB service, so that the application server knows whether it should pool them and when to start and stop database transactions. The alternative annotations are @Stateful and @Singleton. Note that a @Stateless does not mean that the container will make sure that the class itself is stateless. You as developer are still responsible to ensure that the class doesn’t contain any shared and mutable instance variables. Otherwise, you’d better mark it as either @Stateful or @Singleton, depending on its purpose. See also this Stack Overflow post.
  • @PersistenceContext — basically injects the JPA entity manager from the persistence unit as configured in the project’s persistence.xml. The entity manager is, in turn, responsible for mapping all JPA entities against a SQL database. It will, under the covers, do all the hard JDBC work.
Back to top

Adjusting the Backing Bean and Facelet

Now we’re going to adjust the earlier created backing bean in order to save the messages in the database and display all of them in a table.

package com.example.project.view;

import java.util.List;

import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;

import com.example.project.model.Message;
import com.example.project.service.MessageService;

@Named @RequestScoped
public class Bean {

    private Message message = new Message();
    private List<Message> messages;

    @Inject
    private MessageService messageService;

    @PostConstruct
    public void init() {
        messages = messageService.list();
    }
    
    public void submit() {
        messageService.create(message);
        messages.add(message);
        message = new Message();
    }
    
    public Message getMessage() {
        return message;
    }
    
    public List<Message> getMessages() {
        return messages;
    }
}

Note that you don’t need setters for the message and messages properties. We’re going to use the getters and setters of the Message entity itself.

Finally, adjust the <h:body> of test.xhtml Facelet as follows:

<h1>Hello World</h1>
<h:form>
    <h:outputLabel for="input" value="Input" />
    <h:inputText id="input" value="#{bean.message.text}" />
    <h:message id="input_m" for="input" />
    <h:commandButton value="Submit" action="#{bean.submit}">
        <f:ajax execute="@form" render="input input_m :table" />
    </h:commandButton>
</h:form>
<h:dataTable id="table" value="#{bean.messages}" var="message">
    <h:column>#{message.id}</h:column>
    <h:column>#{message.text}</h:column>
</h:dataTable>

Now, restart the server, reload the page in your favorite web browser and create some messages.

As a reminder, the in-memory H2 database will be emptied when you restart the server. If you want to “avoid” this, simply switch to a real database, such as PostgreSQL or MySQL.

That's it! Hopefully it's helpful to get started with JSF 2.3 in Jakarta EE. If you want to explore further, advance to my Stack Overflow answers. You can find a collection of "most valuable" answers at https://jsf.zeef.com/bauke.scholtz. If you already have a moderate knowledge on web application development in general, and want to greatly expand your JSF knowledge, then consider picking the book The Definitive Guide to JSF in Java EE 8. Apart from the “From Zero to Hello World” chapter, the rest of the book is still very up to date these days.

Back to top

Copyright - None of this article may be taken over without explicit authorisation.

(C) April 2020, BalusC

Monday, January 31, 2011

JSF 2.0 tutorial with Eclipse and Glassfish

WARNING - OUTDATED CONTENT!

There is a newer JSF 2.3 tutorial out with Eclipse / Maven / WildFly / H2.

Introduction

In this tutorial you will learn how to setup a JSF 2.0 (Mojarra) playground with Eclipse 3.6 SR1 (Helios) and Oracle Application Server v3 (Glassfish).

There are also another IDE's available next to Eclipse, e.g. Oracle Netbeans, IntelliJ IDEA, etcetera. The choice for Eclipse is made because it's highly configureable, customizeable, has lots of helpful wizards and .. it's free! True, it may eat memory and it may sometimes crash. Just make sure that your environment has enough RAM memory for Java EE development. I recommend at least 2GB of free RAM of which 1GB is reserved to Eclipse. Also at least a dual/quad core CPU around 2GHz is recommended to be able to work fluently. Also make sure that you install trusted Eclipse plugins the right and clean way, because the well-known Eclipse-instability is almost always caused by bad plugins.

There are also another application servers available next to Oracle Glassfish, e.g. JBoss Application Server, Apache Tomcat, etcetera. The choice for Glassfish is made because it ships as being a full fledged Java EE 6 application server already with JSF builtin and offers builtin support for lot of other handy Java EE aspects like JPA for database connectivity, EJB for business services, JSR303 for bean validation, CDI for dependency injection, etcetera. Also, in combination with the current Eclipse plugin, it allows for extremely fast development. Not only Glassfish starts up relatively quick, but it is able to hotdeploy code changes in a subsecond. It's certainly an improvement as compared to its predecesor, Glassfish v2. In the 3-year old JSF 1.2 tutorial, Apache Tomcat was been used. One of the reasons to prefer Tomcat over Glassfish v2 was the lack of a good Eclipse plugin for Glassfish back then in 2008.

Back to top

Preparing

Create a working directory where you install and store all related files. In this tutorial we'll use C:\Java as working directory. If you want to store it somewhere else, then you'll have to replace every occurence of "C:\Java" throughout the tutorial by the desired directory.

Back to top

Download and install Java SE 6 JDK

The Java SE 6 JDK contains both the runtime (JRE, java.exe) and the compiler (JDK, javac.exe) for the standard Java API.

You can skip this part if you already have downloaded/installed Java SE 6 JDK.

  1. Surf to the Java SE 6 download page.
  2. You'll see four big buttons next to each other, press the leftmost one, which says just 'Java'.
  3. Accept the License Agreement and choose the right file for your platform. For Windows x64 for example you will get the file jdk-6u23-windows-x64.exe (naming may differ per version), save it to disk.
  4. Install the JDK and JRE in C:\Java\jdk1.6.0_23 and C:\Java\jre1.6.0_23 respectively (or in their default paths, if you want).
Back to top

Download and install Java EE 6 Web Profile SDK

The Java EE 6 covers the enterprise Java API. This is basically an abstract API for which Glassfish is one of the concrete implementations. Actually, Glassfish is the reference implementation. The Java EE 6 Web Profile is a specified part of the huge Java EE 6 API which includes the minimum necessary API's required for Java web development: the Servlet 3.0 API, JSF 2.0 API, JPA 2.0 API and EJB 3.1 Lite. Note that Apache Tomcat 7.0 only includes Servlet 3.0 API.

You can also consider to pick the standard (full) profile. It's only too heavy-weight since it contains API components which are (possibly) not of your interest like EJB (full), JAX-WS, JAXB, JMS, JACC, JAX-RPC, JAXR, etcetera. It causes Glassfish to start slower as compared to the lightweight web profile, sometimes very noticeably slower. The web profile starts in only a few seconds. You can find an overview of differences halfway the download page of the Glassfish development site.

You can skip this part if you already have downloaded/installed Glassfish, even though you did it by their development site.

  1. Surf to the Java EE 6 download page.
  2. You'll see four big buttons next to each other, press the rightmost one, which says 'Java EE 6 Web Profile SDK'.
  3. Choose Platform/Language, accept the License Agreement and press the Continue button.
  4. In the section 'Available Files', click at the link below 'Java EE 6 Web Profile SDK Update 1', you will get the file java_ee_sdk-6u1-web-windows.exe (naming may differ per version), save it to disk.
  5. Install Glassfish in C:\Java\glassfishv3 and walk through the remnant of the wizard. Just with default settings is fine. You may possibly get a firewall warning whenever you go to the next step after setting the ports (the installer is just testing them). Just let the firewall allow access. Don't forget to remember the admin username and password for the case that you've changed them!


Note that you may possibly get the error 'This application needs version 1.6 or higher of the Java 2 Runtime Environment.' when executing the installer. In this case, your best bet is to try reinstalling the JRE (not the JDK!) which you can download from java.com. In the latest Java 1.6 releases, there's apparently a little difference in how the JDK/JRE installers configures the necessary registry keys and DLL's in Windows. Just reinstall JRE from java.com in the same folder. During auto-uninstalling the original JRE, you'll possibly get warnings that msvcr71.dll is missing, just ignore it and go ahead (it's may namely be exactly that file which was broken in the original JRE install!).

Back to top

Download and install Eclipse Helios 3.6 SR1

The Eclipse IDE is available in several tastes. As we're going to develop Java EE web applications, we need the Java EE variant. It contains among others the invaluable WTP (Web Tools Platform) which eases the development of Java EE web applications. The currently latest version is Eclipse Helios 3.6 SR1.

  1. Surf to the Eclipse download page.
  2. Click at the Eclipse IDE for Java EE Developers link.
  3. On the right hand menu, pick the platform version.
  4. Click the default mirror or pick a mirror and you will get the file eclipse-jee-helios-SR1-win32-x86_64.zip (naming may differ per version), save it to disk.
  5. Extract the zip and move the child directory \eclipse to C:\Java\eclipse.
Back to top

Run and configure Eclipse

After starting Eclipse for the first time, we would like to finetune Eclipse a bit so that we don't after all end in trouble and/or annoyances. Eclipse has enormously a lot of settings of which some default values should after all not have been the default values. Here I'll describe only the most useful/important ones.

  1. Run C:\Java\eclipse\eclipse.exe. You will be asked to select a workspace. Point it to C:\Java\workspace.
  2. On the welcome screen, click at the icon with the curved arrow at the right top: Go to the workbench.
  3. In the top menu, go to Window » Preferences. This is the preferences dialogue.
  4. You want world domination, so enter 'encoding' in the 'type filter text' input field on the left top. On every section, change the encoding from default (often cp1252 or ISO 8859-1) to UTF-8.
  5. In the Preferences dialogue, clear if necessary first the entered filter text, then go to General » Editors » Text Editors » Spelling and disable it. Really. It will save you from a big annoyment, because it also unnecessarily spellchecks XML documents like web.xml, faces-config.xml and on.
  6. In the Preferences dialogue, go to Web » JavaServer Faces Tools » Validation and in the section Type Assignment Problems set Method expression signature incompatibility to Warning or Ignore if you want to allow JSF action methods return void. I also recommend to set the Unary operation number (and boolean) coercion problems in the section Type Coercion Problems to Warning or Ignore, because it would unnecessarily give an error when you're using for example UIComponent#getValue() -which has Object type outcome- in EL but you treated it as number or boolean.
  7. In the Preferences dialogue, go to Web » HTML Files » Editor » Templates and click New. Enter name New Facelet Page, select context New HTML, enter description Creates a new Facelet page, copypaste the following snippet in the pattern field and click OK:
    <!DOCTYPE html>
    <html lang="en"
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:f="http://java.sun.com/jsf/core"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:ui="http://java.sun.com/jsf/facelets">
        <h:head>
            <title>Insert title here</title>
        </h:head>
        <h:body>
            ${cursor}
        </h:body>
    </html>
    
  8. Here are some more screenshots of how I configured some other preferences (Text Editors, HTML Editor and Errors/Warnings), you may find it useful as well (indent using spaces, set line width and print margin, finetune errors/warnings, etc):
  9. Click OK to close the Preferences dialogue.
Back to top

Integrate Glassfish in Eclipse

We need to familarize Eclipse with any installed application servers so that Eclipse can seamlessly link their libraries in the build path (read: the compiletime classpath) of the project. This is mandatory in order to be able to import classes from the Java EE API in your project (you know, the applications server is namely the concrete Java EE implementation).

  1. At the bottom box click at the Servers tab to open the servers view. Rightclick at the box and choose New » Server. In the wizard, click the link 'Download additional server adapters'. Wait until it has finished gathering all available adapters. Finally choose 'Oracle Glassfish Server Tools' from the list and click Next. Accept the license terms and click Finish. In the end you need to restart Eclipse, do it.
  2. After restarting and going to workbench, open the servers view once again to add a new server. In the wizard, select GlassFish » GlassFish Server Open Source Edition 3 (Java EE 6) and click Next. In the next page, click at Browse, point to C:\Java\glassfishv3\glassfish and click Next. In the next page, change if necessary the admin ID (username) and password, which is the same as the ones specified during Glassfish installation. Finally click Finish. Now Glassfish is integrated in Eclipse.
  3. Doubleclick the Glassfish server entry in the Servers tab, you'll get the server configuration. You can there if necessary change the admin name/password and configure the degree of publishing (hotdeploying). You may possibly get a firewall warning when you open the server configuration for the first time, just let it allow access. Glassfish is able to publish extremely fast on just a Ctrl+S. In the Publishing section, set Automatically publish when resources change and set the interval to 0.
  4. Rightclick the Glassfish server entry in the Servers tab and choose Start. You can also start it by clicking at the green arrow at the toolbar of the box. Again, you may possibly get a firewall warning here as well, just let it allow access (this should be the last time now ;) ). Once it is started, go to http://localhost:8080 (where 8080 is the HTTP port as in Glassfish config). You should get the default Glassfish home page. Also checkout the admin console on http://localhost:4848 (where 4848 is the admin port as in Glassfish config).

    If you get a timeout or kind of an unknown host error message, then doublecheck it is started properly and you're using the right port number. In Eclipse you can find the Glassfish logs at the Console tab of the bottom dialogue box (you can doubleclick the tab to maximize it and bring it back). Glassfish actually shows two consoles, one of the JVM and one of the server.log logfile. The last one is of your interest. Click the blue monitor icon on the right top to switch between consoles.
  5. You can stop the server by rightclicking at the Glassfish server entry in the Servers tab and choose Stop. You can also stop it by clicking at the red square at the toolbar of the box.
Back to top

Prepare JSF web project in Eclipse

Now we can finally create a JSF web project in Eclipse.

  1. At the left box open the Project Explorer tab if not already opened. Rightclick at the box and choose New » Dynamic Web Project. In the wizard, give it the Project name Playground, verify if Target Runtime is set to 'GlassFish Server Open Source Edition 3 (Java EE 6)' and Dynamic Web Module version is set to '3.0' (this is actually the Servlet API version). Under Configuration select 'JavaServer Faces v2.0 project' and click Next.
  2. In the next page, you can configure the source folder and build folder (there where compiled classes will end up in). Just keep it default and click Next.
  3. In the next page, you may change the module settings to your taste. Personally I like to have URL's always in lowercase, so I change the default Context Root from Playground to playground. Also, check the checkbox Generate web.xml deployment descriptor to have Eclipse auto-generate the web.xml. Click Next.
  4. In the next page, you need to define JSF Capabilities. At JSF Implementation Library, select 'Disable Library Configuration'. Glassfish already ships with JSF 2.0 builtin, so we don't need to specify anything. At URL Mapping Patterns, select the default /faces/* and click Remove to remove it. Prefix patterns end up to be less maintainable. Better use postfix patterns like *.jsf or even *.xhtml (unless you have XHTML files which you'd like not to have JSF's FacesServlet to kick in). We'll pick *.xhtml here, a major advantage is that this is an easy way to avoid that the enduser can see the JSF source code whenever s/he (accidently) opens the page with *.xhtml in the URL while the FacesServlet is mapped on *.jsf.

    Click Add... to add a new pattern with the value *.xhtml. Finally click Finish.
  5. After creation of the web project, you should get a directory structure similar to the screenshot below.
  6. Due to a combination of constraints in the HTTP/HTML/EL specifications, empty HTML input fields are by default treated as empty String. The average (Java) web developer usually dislikes this (so do I). We can instruct JSF to interpret them as null. Open WebContent/WEB-INF/web.xml file, click if necessary the Source tab at the bottom of the editor, and add the following context parameter:
    <context-param>
        <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
        <param-value>true</param-value>
    </context-param>
    
    If necessary hit Ctrl+Shift+F to format the xml file nicely.
  7. Save and close the file.
Back to top

Create JSF hello world in Eclipse - The model

As a hello world project, we'll create a simple ajax-flavored form which treats the use case of "Register User". We first need to create a data model. That's a class which represents a real world entitiy, in this case the User. It holds all the information about the user. It should be written as a Javabean. A Javabean is a class which holds properties as private fields which are exposed by public getters and setters.

  1. Open the newly created Playground project, rightclick at Java Resources folder and choose New » Class. In the wizard, enter the package name com.example, enter the class name User, keep the other fields default and click Finish. The package and the class will be created and the editor box will show the class source.
  2. Let the class implement Serializable. This is not mandatory per se, but this is useful in order to let the HTTP session survive server restarts. Also, as we're going to use a JSF view scoped bean, which will be stored in the component tree (the `UIViewRoot`) in the HTTP session, the view scoped bean itself and all of its properties should be Serializable as well.
    package com.example;
    
    import java.io.Serializable;
    
    public class User implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
    }
    Note that when you add implements Serializable, Eclipse will show a warning that the class needs to have a serialVersionUID field. You can if necessary just let Eclipse include it with a default or autogenerated ID. Click the yellow bullet on the left hand side and choose it.
  3. Add five fields to the class (note that Date is to be imported as java.util.Date, not as java.sql.Date):
    
        private Long id;
        private String username;
        private String password;
        private String email;
        private Date birthdate;
     
    
  4. Let Eclipse auto-generate the necessary getters and setters. Rightclick somewhere in blank space of the source code inside the source editor, choose Source » Generate Getters and Setters, or hit Alt+Shift+S, then R. In the wizard, click Select All and then untick the serialVersionUID one, if necessary choose the insertion point (I like to have getters and setters at the whole bottom of the class, thus Last member) and the sorting (it defaults to getter/setter pairs, which is okay) and then click at OK. If necessary, hit Ctrl+Shift+F to format the code again so that methods get separated by a blank line. You can configure formatting preferences in Window » Preferences » Java » Code Style » Formatter.
  5. Save the class by choosing File » Save in the top menu or by pressing Ctrl+S.

Create JSF hello world in Eclipse - The controller

The backing bean is in turn the glue between the view (the JSF page) and the data model (the entity). The backing bean is linked to the view and all properties of the model are by the backing bean exposed in the view. The backing bean can contain action methods which are linked in the view. The backing bean is basically a mini-controller at its own (in the bigger picture of JSF, the FacesServlet is actually the real web MVC controller).

  1. Rightclick at com.example package and choose New » Class. In the wizard, enter the class name Register, keep the other fields default (if you rightclicked on the package to create a new class, the package name should already be com.example) and click Finish. The class will be created and the editor box will show the class source.
  2. First let the class implement Serializable. Then add a new line above the class declaration, enter @ManagedBean, press Ctrl+Space and ensure that you choose the javax.faces one to import. Do the same for @ViewScoped annotation as well. Note that we can also use @RequestScoped here as well since the bean doesn't do any significantly expensive operations during the construction such as obtaining some data from a database, but if it did and you declared it @RequestScoped, then the bean will be constructed and thus the DB will be hit on every ajax request, keep this in mind!
    package com.example;
    
    import java.io.Serializable;
    
    import javax.faces.bean.ManagedBean;
    import javax.faces.bean.ViewScoped;
    
    @ManagedBean
    @ViewScoped
    public class Register implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
    }
  3. Add a property for the User model, along with a getter and (optionally) a setter, add a @PostConstruct method with which initializes a new User and finally add an action method which just adds a success message (in real world, we would save the newly registered user in the DB as well, but that's beyond the scope of this tutorial):
    
        private User user;
    
        @PostConstruct
        public void init() {
            user = new User();
        }
        
        public void submit() {
            FacesMessage message = new FacesMessage("Registration succesful!");
            FacesContext.getCurrentInstance().addMessage(null, message);
        }
        
        public User getUser() {
            return user;
        }
    
    
  4. Save the class.
Back to top

Create JSF hello world in Eclipse - The view

blah

  1. Rightclick at WebContent folder and choose New » XHTML page. In the wizard, enter the File name register, click Next (the .xhtml extension will be appended automatically anyway), select the template New Facelet Page (which we have definied in the preferences) and click Finish.

  2. Change the <title> to Register user and add the following ajax-flavored form to the body of the view:
    <h:form>
        <h:panelGrid columns="3">
            <h:outputLabel for="username">Username</h:outputLabel>
            <h:inputText id="username" value="#{register.user.username}" required="true">
                <f:ajax event="blur" render="usernameMessage" />
            </h:inputText>
            <h:message id="usernameMessage" for="username" />
    
            <h:outputLabel for="password">Password</h:outputLabel>
            <h:inputSecret id="password" value="#{register.user.password}" required="true" redisplay="true">
                <f:ajax event="blur" render="passwordMessage" />
            </h:inputSecret>
            <h:message id="passwordMessage" for="password" />
    
            <h:outputLabel for="email">Email</h:outputLabel>
            <h:inputText id="email" value="#{register.user.email}" required="true">
                <f:ajax event="blur" render="emailMessage" />
            </h:inputText>
            <h:message id="emailMessage" for="email" />
    
            <h:outputLabel for="birthdate">Birthdate (yyyy-MM-dd)</h:outputLabel>
            <h:inputText id="birthdate" value="#{register.user.birthdate}">
                <f:convertDateTime pattern="yyyy-MM-dd" />
                <f:ajax event="blur" render="birthdateMessage" />
            </h:inputText>
            <h:message id="birthdateMessage" for="birthdate" />
    
            <h:panelGroup />
            <h:commandButton value="Register" action="#{register.submit}">
                <f:ajax execute="@form" render="@form" />
            </h:commandButton>
            <h:messages globalOnly="true" layout="table" />
        </h:panelGrid>
    </h:form>
    You see, it creates a form with a 3-column table (however, a tableless form with a flood of CSS would semantically have been more correct, but that's beyond the scope of this tutorial, we teach JSF, not CSS). The 1st column contains the labels for input fields, the 2nd column contains the input fields and the submit button, the 3rd column contains the messages. The <f:ajax> tags in the input fields will submit (and validate!) only the current field and trigger a re-render of the associated message field when the JavaScript/HTML DOM blur event is triggered (when the field loses focus, i.e. when you tab out the field or click somewhere else on the page). The <f:ajax> tag in the command button will do a pure ajax submit instead of a normal submit. The globalOnly="true" in the messages field will only display messages whose client ID is null (as we've created in the managed bean's submit() method).
  3. Save the view.
Back to top

Run JSF web project in Glassfish

Now it's time to deploy the project to Glassfish and run it!

  1. Rightclick the Glassfish server entry in the Servers tab and choose Add and Remove Projects. In the wizard, select the Playground project under Available Projects and click Add to add it to Configured Projects. Click Finish.
  2. Rightclick the Glassfish server entry in the Servers tab and choose Start. You can also start it by clicking at the green arrow at the toolbar of the box. Glassfish is started successfully if the server.log in the Console tab (click the blue monitor icon on the right top to switch between consoles if necessary) displays at least the following line:
    INFO: Playground was successfully deployed in 3,770 milliseconds.
    
    Note that it may take longer or shorter, depending on whether the server has already started for the first time before or not.
  3. Once it is started, go to http://localhost:8080/playground/register.xhtml in your favourite webbrowser. Note that the .xhtml extension must match the URL pattern of the FacesServlet mapping as we have definied in step 4 of chapter Prepare JSF web project in Eclipse. Such a request URL will then trigger the FacesServlet and it will create the FacesContext and do all the JSF works.

    If you get a timeout or kind of an unknown host error message, then doublecheck if Glassfish is started properly and if the port is correct. If you get an internal server error, then an exception was been thrown and is available in the server log. Also try to interpret and understand the exception message and the trace, if necessary with help of Google, and then fix the code accordingly.
  4. Play around it in your browser! Tab through the fields, enter values, remove values, press the submit button, etcetera. You'll note that it's running smoothly thanks to all the new JSF 2.0 ajax works.
Back to top

Extra! Finetuning validation

You'll probably have noticed that the default validation error messages are scary and you would probably also like to add a bit more strong password and email validation. Now, you can finetune the validation messages in several ways.

  1. Those j_idt6:username, j_idt6:password, etc are actually client ID's of the input elements (that is, the generated id of the HTML input element which you can see when you do rightclick and View Source of the opened page in the webbrowser). The j_idt6 part (which can differ) is controllable by giving the <h:form> a fixed id.
    <h:form id="form">
    
    Edit it accordingly in the register.xhtml, save it and refresh the page (no server restart is required! Glassfish hotdeploys extremely fast, you don't need to wait for anything, just refresh the page in browser). Trigger the validation and you'll see form:username, form:password, etc instead.
  2. That's already less scary. However, we can make the labels more human friendly by defining them in the label attribute of the input components.
    <h:inputText id="username" label="Username" ... >
    ...
    <h:inputSecret id="password" label="Password" ... >
    ...
    <h:inputText id="email" label="Email" ... >
    ...
    <h:inputText id="birthdate" label="Birthdate" ... >
    Edit accordingly, save source, refresh page in browser, play around it. No pain!
  3. Better, but still too "mechanic". However, there's a way to replace the entire default required and conversion message in the view side by defining them as requiredMessage and converterMessage accordingly.
    <h:inputText id="username" requiredMessage="Please enter username" ... >
    ...
    <h:inputSecret id="password" requiredMessage="Please enter password" ... >
    ...
    <h:inputText id="email" requiredMessage="Please enter email" ... >
    ...
    <h:inputText id="birthdate" converterMessage="Please enter date in yyyy-MM-dd format" ... >
    Rinse and repeat.

    There are other ways as well, for example defining them as <message-bundle> in the faces-config.xml, but that's beyond the scope of this tutorial.
  4. We can also do the validation straight in the model instead of the view. This can be more useful if the model is a JPA entity. Glassfish ships with builtin bean validation (also known as JSR 303) which is anticipated seamlessly by JSF 2.0. It ships with several validation constraint annotations such as @NotNull.

    First remove the required and requiredMessage attributes from the three input fields username, password and email. Then add the @NotNull annotation on exactly those properties of the model (note that this only works when you've added the javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL context parameter as described in step 6 of chapter Prepare JSF web project in Eclipse, otherwise you need the Hibernate validation specific @NotEmpty annotation instead!).
    
        private Long id;
        @NotNull
        private String username;
        @NotNull
        private String password;
        @NotNull
        private String email;
        private Date birthdate;
    
    
    Save and refresh browser (no, still no server restart needed here as well!)
  5. Again, the messages are too generic: "may not be null". We can however customize them straight in the model by the message field of the annotation.
    
        private Long id;
        @NotNull(message = "Please enter username")
        private String username;
        @NotNull(message = "Please enter password")
        private String password;
        @NotNull(message = "Please enter email")
        private String email;
        private Date birthdate;
    
    
    Save, refresh, play.

    Now we're back at the same state as with view-level validation finetuning.

    Which one you should be using in your projects really depends on the requirements. For example, if you want to be able to run this on a random Tomcat machine or non-Java EE 6-container (JSF 2.0 is by itself backwards compatible with Java EE 5 / Servlet 2.5), then forget bean validation.
  6. We can even use regex to validate the strengthness of the password and correctness of the email. For this the JSR 303 @Pattern annotation is useful. We want the password to be at least 8 chars in length, contain at least one digit, at least one lowercase alphabet letter and at least one uppercase alphabet letter. We also want the email to be syntactically valid with regard to the @ and the .. We shouldn't care about the actual characters in the email address.
    
        private Long id;
        @NotNull(message = "Please enter username")
        private String username;
        @NotNull(message = "Please enter password")
        @Pattern(regexp = ".*(?=.{8,})(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).*", message = "Password is not strong enough")
        private String password;
        @NotNull(message = "Please enter email")
        @Pattern(regexp = "([^.@]+)(\\.[^.@]+)*@([^.@]+\\.)+([^.@]+)", message = "Email is not in valid format")
        private String email;
        private Date birthdate;
    
    
    Rinse and repeat.
Back to top

And now?

Play with it! Head if necessary to Communication in JSF 2.0 article to learn about some tips and tricks.

Here are the most important JSF 2.0 related links to be bookmarked and read thoroughly:

  • JSF 2.0 specification (pick the 1st download link), it explains why JSF is there, how it works and what it all provides.
  • JSF 2.0 API documentation, it contains detailed javadocs of the JSF API classes, it explains where the classes are for, how to use them and what all fields/methods do.
  • JSF 2.0 tag documentation, it shows which JSF tags are all available, what they all do and which attributes they supports.
  • Java EE 6 tutorial, chapter 4 and on contains Sun's Oracle's own JSF 2.0 tutorial.
  • If you want to get a book, I highly recommend the JSF 2.0: The Complete Reference, one of its authors, Ed Burns, is the lead of the JSF specification. If you want to get a step further with Glassfish, then Java EE 6 platform with GlassFish 3 is also an excellent choice.
  • Another excellent online resource is the Mkyong.com JSF 2.0 Tutorials. It contains lot of high quality JSF 2.0 examples (although there are unfortunately a bit too much advertisements, it's sometimes demotivating). There are other sites as well, but please don't even take a look at Roseindia.net.

Finally you can check the Favorites section at the right column of this blog site for more interesting links (of which the majority of the older ones are still targeted on JSF 1.2, the future articles will cover JSF 2.0 anyway).

Back to top

Copyright - None of this article may be taken over without explicit authorisation.

(C) January 2011, BalusC