Skip to content
This repository has been archived by the owner on Jul 3, 2023. It is now read-only.

Tutorial: a Java EE Web Profile application with nemo utils, part 3

Vítor E. Silva Souza edited this page Nov 4, 2014 · 5 revisions

In this step we apply a template to our Web Application (WebApp) using a few resources prepared beforehand to work with some of nemo-utils's features.

Configure JSF

We begin by configuring JSF in our project: right-click on it and open its properties. Then, open Project Facets, uncheck JavaServer Faces and click Apply (yes, it seems strange to do this, but keep reading). Then, check JavaServer Faces back again so the Further configuration available... link shows up. Click on it to view the project's JSF configuration. Make sure that:

  • The Type field is set to Library Provided by Target Runtime;
  • The URL Mapping Patterns field lists *.faces, which configures JSF to deal with any URL that ends in .faces.

Click OK, then OK again to go back to the workspace. At this point, your WebContent/WEB-INF/web.xml file should look similar to this:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>AutoTrab</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.faces</url-pattern>
  </servlet-mapping>
</web-app>

Whereas your WebContent/WEB-INF/faces-config.xml file should be similar to this:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config
    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_2.xsd"
    version="2.2">

</faces-config>

Add the template (decorator)

Now that JSF is configured, we add the template. From the Templated website, we obtained a free CSS template called emerald and adapted it to be applied through Facelets. The result is zipped in the file tutorial-part03-resources.zip. Download and unpack this file, then copy the resources folder into the WebContent folder of your project.

Here's the general structure of the resources folder:

  • scripts: client-side scripts (i.e., JavaScript);
  • templates: Facelets templates that can be applied to your WebApp (you can add more than one if you'd like to give users the option of switching, for example);
  • templates/default/icons: icons of the default template, used with JSF buttons, menus and such;
  • templates/default/images: images of the default template;
  • templates/default/stylesheets: CSS style sheets of the default template;
  • templates/default/decorator.xhtml: the main template file, with the decoration applied to all pages;
  • templates/default/form*.xhtml: form and form field decorations, mini-templates done in Facelets to reuse code that is useful in HTML forms (e.g., validation).

Of course, many of these files should be customized to each specific application. We will do just the minimal amount of customization by opening the file templates/default/decorator.xhtml and replacing occurrences of NemoUtils with AutoTrab so our layout shows the proper name of the application.

Also, while you have the decorator.xhtml file open in Eclipse, look for the <ui:insert /> tags present in this document. There is one in line 20 that defines an insertion point for title and another in line 73 that defines an insertion point for body. These are the two sections of the web page, to be defined at the last part of this step of the tutorial.

Internationalization (i18n)

Next, we create a couple of resource bundles with externalized strings that allows us to, later on, internationalize our application by providing copies of them in other languages. First, expand the Java Resources item of your project and right-click src. Choose New > Package and create a package called br.ufes.inf.nemo.autotrab.

Then, right-click the package you just created, select New > Other... and choose File from the General folder. Click Next and call it messages.properties. Then, add the following contents to the file:

##
## Global resource bundle for NemoUtils. 
## Language: default (English)
##

# For the nemo-utils default decorator:
text.ajax.loading = Loading data, please wait...
text.ajax.loading.alt = Loading...
text.ajax.error = There has been an error communicating with the server.
text.ajax.error.alt = Error!
text.ajax.complete = Last communication with the server successful.
text.ajax.complete.alt = OK!

# Generic messages for CRUD web pages:
crud.button.add = Add
crud.button.filter = Filter listing
crud.button.cancelFilter = Cancel filter
crud.button.create = New
crud.button.retrieve = View
crud.button.update = Modify
crud.button.delete = Delete
crud.button.cancelDeletion = Cancel
crud.button.confirmDeletion = Confirm deletion
crud.button.cancel = Cancel
crud.button.save = Save
crud.button.back = Back
crud.help.hotkeys.filterFocus = focus the filter field
crud.help.hotkeys.clearFilter = clear current filter
crud.help.hotkeys.create = open the form for a new entry
crud.help.hotkeys.retrieve = open the details of the selected item
crud.help.hotkeys.update = open the form for modifying the selected item
crud.help.hotkeys.delete = add the selected item to the trash bin for deletion
crud.help.hotkeys.cancelDeletion = cancel deletion and restore the items in the trash bin
crud.help.hotkeys.confirmDeletion = confirm the deletion of the items in the trash bin
crud.help.hotkeys.focusFirstField = focus the first form field
crud.help.hotkeys.backToList = go back to the listing
crud.help.hotkeys.save = save changes and go back to the listing
crud.help.hotkeys.cancel = cancel the operation and go back
crud.help.hotkeys.back = go back
crud.hotkey.filterFocus = f
crud.hotkey.clearFilter = l
crud.hotkey.create = n
crud.hotkey.retrieve = c
crud.hotkey.update = a
crud.hotkey.delete = e
crud.hotkey.cancelDeletion = esc
crud.hotkey.confirmDeletion = s
crud.hotkey.focusFirstField = f
crud.hotkey.backToList = esc
crud.hotkey.save = ctrl+return
crud.hotkey.cancel = esc
crud.hotkey.back = esc
crud.text.filter = Filter
crud.text.filterInfo = Filtering {0}: {1}
crud.text.trashHeader = Items to delete:

# Default formats:
format.date.java=dd/MM/yyyy
format.date.primefaces=99/99/9999
format.date.label=dd/mm/aaaa
format.datetime.java=dd/MM/yyyy HH:mm:ss
format.taxCode.primefaces=999.999.999-99
format.taxCode.label=\#\#\#.\#\#\#.\#\#\#-\#\#
format.zipCode.primefaces=99999-999
format.zipCode.label=\#\#\#\#\#-\#\#\#

# Regular expressions and validator messages.
regex.email=([^.@]+)(\\.[^.@]+)*@([^.@]+\\.)+([^.@]+)
regex.confirmationCode=[\\w\\-]\{36\}
regex.email.message = This is not a valid email address.
regex.confirmationCode.message = This confirmation code given is not valid.

This file contains messages that are used by nemo-utils, particularly by its mini CRUD framework (which is demonstrated in the next step of this tutorial). You can, however, replace NemoUtils with AutoTrab in the comments at the top of the file.

Now, repeat the above procedure to create another file, called faces.properties, which contains JSF standard messages:

# Standard localized error and informational messages from the JSF 2.0 specification
javax.faces.component.UIInput.CONVERSION = {0}: Conversion error occurred
javax.faces.component.UIInput.REQUIRED = {0}: Validation Error: Value is required
javax.faces.component.UIInput.UPDATE = {0}: An error occurred when processing your submitted information
javax.faces.component.UISelectOne.INVALID = {0}: Validation Error: Value is not valid
javax.faces.component.UISelectMany.INVALID = {0}: Validation Error: Value is not valid
javax.faces.converter.BigDecimalConverter.DECIMAL = {2}: ''{0}'' must be a signed decimal number.
javax.faces.converter.BigDecimalConverter.DECIMAL_detail = {2}: ''{0}'' must be a signed decimal number consisting of zero or more digits, that may be followed by a decimal point and fraction. Example: {1}
javax.faces.converter.BigIntegerConverter.BIGINTEGER = {2}: ''{0}'' must be a number consisting of one or more digits.
javax.faces.converter.BigIntegerConverter.BIGINTEGER_detail = {2}: ''{0}'' must be a number consisting of one or more digits. Example: {1}
javax.faces.converter.BooleanConverter.BOOLEAN = {1}: ''{0}'' must be 'true' or 'false'.
javax.faces.converter.BooleanConverter.BOOLEAN_detail = {1}: ''{0}'' must be 'true' or 'false'. Any value other than 'true' will evaluate to 'false'.
javax.faces.converter.ByteConverter.BYTE = {2}: ''{0}'' must be a number between 0 and 255.
javax.faces.converter.ByteConverter.BYTE_detail = {2}: ''{0}'' must be a number between 0 and 255. Example: {1}
javax.faces.converter.CharacterConverter.CHARACTER = {1}: ''{0}'' must be a valid character.
javax.faces.converter.CharacterConverter.CHARACTER_detail = {1}: ''{0}'' must be a valid ASCII character.
javax.faces.converter.DateTimeConverter.DATE = {2}: ''{0}'' could not be understood as a date.
javax.faces.converter.DateTimeConverter.DATE_detail = {2}: ''{0}'' could not be understood as a date. Example: {1}
javax.faces.converter.DateTimeConverter.TIME = {2}: ''{0}'' could not be understood as a time.
javax.faces.converter.DateTimeConverter.TIME_detail = {2}: ''{0}'' could not be understood as a time. Example: {1}
javax.faces.converter.DateTimeConverter.DATETIME = {2}: ''{0}'' could not be understood as a date and time.
javax.faces.converter.DateTimeConverter.DATETIME_detail = {2}: ''{0}'' could not be understood as a date and time. Example: {1}
javax.faces.converter.DateTimeConverter.PATTERN_TYPE = {1}: A 'pattern' or 'type' attribute must be specified to convert the value ''{0}''.
javax.faces.converter.DoubleConverter.DOUBLE = {2}: ''{0}'' must be a number consisting of one or more digits.
javax.faces.converter.DoubleConverter.DOUBLE_detail = {2}: ''{0}'' must be a number between 4.9E-324 and 1.7976931348623157E308 Example: {1}
javax.faces.converter.EnumConverter.ENUM = {2}: ''{0}'' must be convertible to an enum.
javax.faces.converter.EnumConverter.ENUM_detail = {2}: ''{0}'' must be convertible to an enum from the enum that contains the constant ''{1}''.
javax.faces.converter.EnumConverter.ENUM_NO_CLASS = {1}: ''{0}'' must be convertible to an enum from the enum, but no enum class provided.
javax.faces.converter.EnumConverter.ENUM_NO_CLASS_detail = {1}: ''{0}'' must be convertible to an enum from the enum, but no enum class provided.
javax.faces.converter.FloatConverter.FLOAT = {2}: ''{0}'' must be a number consisting of one or more digits.
javax.faces.converter.FloatConverter.FLOAT_detail = {2}: ''{0}'' must be a number between 1.4E-45 and 3.4028235E38 Example: {1}
javax.faces.converter.IntegerConverter.INTEGER = {2}: ''{0}'' must be a number consisting of one or more digits.
javax.faces.converter.IntegerConverter.INTEGER_detail = {2}: ''{0}'' must be a number between -2147483648 and 2147483647 Example: {1}
javax.faces.converter.LongConverter.LONG = {2}: ''{0}'' must be a number consisting of one or more digits.
javax.faces.converter.LongConverter.LONG_detail = {2}: ''{0}'' must be a number between -9223372036854775808 to 9223372036854775807 Example: {1}
javax.faces.converter.NumberConverter.CURRENCY = {2}: ''{0}'' could not be understood as a currency value.
javax.faces.converter.NumberConverter.CURRENCY_detail = {2}: ''{0}'' could not be understood as a currency value. Example: {1}
javax.faces.converter.NumberConverter.PERCENT = {2}: ''{0}'' could not be understood as a percentage.
javax.faces.converter.NumberConverter.PERCENT_detail = {2}: ''{0}'' could not be understood as a percentage. Example: {1}
javax.faces.converter.NumberConverter.NUMBER = {2}: ''{0}'' is not a number.
javax.faces.converter.NumberConverter.NUMBER_detail = {2}: ''{0}'' is not a number. Example: {1}
javax.faces.converter.NumberConverter.PATTERN = {2}: ''{0}'' is not a number pattern.
javax.faces.converter.NumberConverter.PATTERN_detail = {2}: ''{0}'' is not a number pattern. Example: {1}
javax.faces.converter.ShortConverter.SHORT = {2}: ''{0}'' must be a number consisting of one or more digits.
javax.faces.converter.ShortConverter.SHORT_detail = {2}: ''{0}'' must be a number between -32768 and 32767 Example: {1}
javax.faces.converter.STRING = {1}: Could not convert ''{0}'' to a string.
javax.faces.validator.BeanValidator.MESSAGE = {0}
javax.faces.validator.DoubleRangeValidator.MAXIMUM = {1}: Validation Error: Value is greater than allowable maximum of ''{0}''
javax.faces.validator.DoubleRangeValidator.MINIMUM = {1}: Validation Error: Value is less than allowable minimum of ''{0}''
javax.faces.validator.DoubleRangeValidator.NOT_IN_RANGE = {2}: Validation Error: Specified attribute is not between the expected values of {0} and {1}.
javax.faces.validator.DoubleRangeValidator.TYPE = {0}: Validation Error: Value is not of the correct type
javax.faces.validator.LengthValidator.MAXIMUM = {1}: Validation Error: Value is greater than allowable maximum of ''{0}''
javax.faces.validator.LengthValidator.MINIMUM = {1}: Validation Error: Value is less than allowable minimum of ''{0}''
javax.faces.validator.LongRangeValidator.MAXIMUM = {1}: Validation Error: Value is greater than allowable maximum of ''{0}''
javax.faces.validator.LongRangeValidator.MINIMUM = {1}: Validation Error Value is less than allowable minimum of ''{0}''
javax.faces.validator.LongRangeValidator.NOT_IN_RANGE = {2}: Validation Error: Specified attribute is not between the expected values of {0} and {1}.
javax.faces.validator.LongRangeValidator.TYPE = {0}: Validation Error: Value is not of the correct type

This file is useful in case you want to customize some of these standard messages or if you want to translate them as part of your application's i18n effort.

Last, but not least, we need to configure JSF to make this bundle available for the web pages through EL (Expression Language). To do this, open WebContent/WEB-INF/faces-config.xml, switch to the Source tab and add the following contents under the <faces-config> tag:

<application>
	<!-- Defines the resource bundle that contains the standard JSF messages (overriding the ones provided). -->
	<message-bundle>br.ufes.inf.nemo.autotrab.faces</message-bundle>

	<!-- Loads resource bundles for i18n messages and assigns names to them. -->
	<resource-bundle>
		<base-name>br.ufes.inf.nemo.autotrab.messages</base-name>
		<var>msgs</var>
	</resource-bundle>

	<!-- Defines the default locale. -->
	<locale-config>
		<default-locale>en-US</default-locale>
	</locale-config>
</application>

The above changes will tell JSF to use our faces.properties file as the default JSF messages; plus, make the contents of the messages.properties file available under the #{msgs['key']} EL name; and, finally, set U.S. English as the default locale for the application. You can change that configuration (and provide the appropiate bundles) if you'd like your system to be provided in other language by default.

Create the JSF page and test it

To finalize this step, let's create the starting page of the application in JSF. First of all, open the index.html file created in the previous step of the tutorial and replace its entire contents with the following:

<html>
<head><meta http-equiv="refresh" content="0;url=index.faces"></head>
</html>

This will tell the browser to immediately (0 milliseconds) request the URL http://localhost:8080/AutoTrab/index.faces which, as we know, would direct the control to JSF to open the page index.xhtml. Thus, create that file under WebContent (right-click > New > File) with the following contents:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
                xmlns:ui="http://java.sun.com/jsf/facelets"
                xmlns:f="http://java.sun.com/jsf/core"
                xmlns:h="http://java.sun.com/jsf/html"
                xmlns:p="http://primefaces.org/ui"
                template="/resources/templates/default/decorator.xhtml">

	<ui:define name="title"><h:outputText value="#{msgs['title.home']}" /></ui:define>

	<ui:define name="body">
		<h1><h:outputText value="#{msgs['title.home']}" /></h1>
		
		<p>Work in progress...</p>
	</ui:define>
</ui:composition>

The file is a Facelets composition that points to the decorator.xhtml file we created at the beginning of this step. It defines contents for the two sections of the web page: title and body, which match the insertion points defined in the Facelets decorator file, as previously mentioned.

Both sections refer to the EL name #{msgs['title.home']} which, as explained earlier, refers to the key title.home in the messages.properties message bundle. Open this bundle and add the key (and its value) at the end of the file:

# Global messages for AutoTrab
title.home = AutoTrab

That's it. Save everything, redeploy the application and open http://localhost:8080/AutoTrab/ in your browser. The result should be something like the image below:

Starting page of the AutoTrab application as a result of step 3 of the tutorial.

Next: implement a basic CRUD feature