Your First Cup: An Introduction to the Java EE Platform

Previous
Next

4.4 Modifying the Web Client

To add the correct functionality to the web client, you need to perform the following tasks:

  • Modify the DukesBDay managed bean class

  • Modify the Facelets pages

4.4.1 Modify the DukesBDay Managed Bean Class

DukesBDay is a CDI managed bean that acts as a backing bean. A managed bean is a lightweight container-managed object that supports a set of basic services. A backing bean is a managed bean that provides temporary data storage for the values of the components included on a particular JavaServer Faces page. The JavaServer Faces application instantiates the managed bean and stores it in scope. The section following this one describes more about managed beans and how to configure them.

This section describes how to modify the DukesBDay class.

4.4.1.1 Call the dukes-age Web Service to Retrieve Duke's Current Age

Now modify the getAge method of DukesBDay to call the dukes-age web service using the JAX-RS Client API. This will retrieve Duke's current age, so it can be compared to the user's age.

  1. Expand the Source Packages node, expand the firstcup.web node, then double-click the DukesBDay.java file to open it in the editor window.

  2. Find the getAge method and implement its functionality by copying and pasting the following code in bold:

        public int getAge() {
            try {
                Client client = ClientBuilder.newClient();
                WebTarget target = 
                client.target("http://localhost:8080/dukes-age/webapi/dukesAge");
                String response = target.request().get(String.class);
                age = Integer.parseInt(response);
            } catch (IllegalArgumentException | NullPointerException | 
                     WebApplicationException ex) {
                logger.severe("processing of HTTP response failed");
            } 
            return age;
        }
    
  3. In the editor window, right-click and select Format.

  4. From the File menu, select Save.

4.4.1.2 Get the Age Difference from the DukesBirthdayBean Enterprise Bean

Now modify the processBirthday method to get the difference in age between the user's age and Duke's age from the DukesBirthdayBean EJB, set the absAgeDiff variable to the absolute value of the age difference, and set a result string that will forward the user to the display page.

  1. Find the processBirthday method and implement the functionality by copying and pasting the following code in bold:

        public String processBirthday() {
            this.setAgeDiff(dukesBirthdayBean.getAgeDifference(yourBD));
            logger.log(Level.INFO, "age diff from dukesbday {0}", ageDiff);
            this.setAbsAgeDiff(Math.abs(this.getAgeDiff()));
            logger.log(Level.INFO, "absAgeDiff {0}", absAgeDiff);
        this.setAverageAgeDifference(dukesBirthdayBean.getAverageAgeDifference());
        logger.log(Level.INFO, "averageAgeDifference {0}", averageAgeDifference);
            return "/response.xhtml";
        }
    

    This method calls the getAgeDifference method of DukesBirthdayBean to get the age difference and store it in the ageDiff property, sets the absolute age difference stored in the absAgeDiff property, and sets the average age difference stored in the averageAgeDifference property. It returns the relative URL of the response page to which the user will be forwarded.

  2. In the editor window, right-click and select Format.

  3. From the File menu, select Save.

4.4.2 Creating the Facelets Client

The Facelets client consists of a resource library, a composite component, and two XHTML files.

4.4.2.1 Resource Libraries in firstcup-war

A JavaServer Faces resource library is a collection of user-created components collected in a standard location in a web application. Resource libraries are identified according to a resource identifier, a string that represents a particular resource within a web application. Resources can be packaged either at the root of the web application or on the web application's classpath.

A resource packaged in the web application root must be in a subdirectory of a resources directory at the web application root.

resources/resource-identifier

A resource packaged in the web application classpath must be in a subdirectory of the META-INF/resources directory within a web application.

META-INF/resources/resource-identifier

Resource identifiers are unique strings that conform to the following format:

[locale-prefix/][library-name /][library-version/]resource-name [/resource-version]

Elements of the resource identifier in brackets ([]) are optional. A resource name, identifying a particular resource (a file or a graphic, for example), is required. In firstcup-war, a resource library with the name components is packaged in the web application root, and this library contains one resource, a file called inputDate.xhtml. The resource identifier for this resource is therefore components/inputDate.xhtml, and it is located in the web application root at resources/components/inputDate.xhtml.

4.4.2.2 The inputDate Composite Component

A composite component is a set of user-defined JavaServerFaces and Facelets components located in a resource. In firstcup-war, the inputDate.xhtml resource, located in the components resource library, is a composite component that contains tags for reading in a date the user enters in a form. Composite components consist of an interface definition and an implementation.

The interface definition is specified with the <cc:interface> tag to define which attributes are exposed to pages that use the composite component. Attributes are identified with the <cc:attribute> tag.

The inputDate.xhtml interface definition is as follows. It defines a single attribute, date, that must be specified in pages that use the inputDate composite component.

<cc:interface>
    <cc:attribute name="date" />
</cc:interface>

The implementation of the composite component is specified with the <cc:implementation> tag. The tags within the <cc:implementation> are the actual component tags that will be added to pages that use the composite component. They can be any HTML render kit, JavaServer Faces, or Facelets tags. The #{cc.attrs.attribute-name} expression is used to get the value of the specified attribute from the page or component that is using the composite component.

The implementation of the inputDate composite component is as follows. An HTML input text component will store the entered text into the date attribute, accessed by the #{cc.attrs.date} expression. A JavaServer Faces convertDateTime component will convert the entered text to a date with the form of MM/dd/yyyy (04/13/2014, for example).

<cc:implementation>
    <h:inputText id="getdate" value="#{cc.attrs.date}">
        <f:convertDateTime pattern="MM/dd/yyyy" />
    </h:inputText>
    <p/>
    <h:message for="getdate" style="color:red" />
</cc:implementation>

If there's an error with the input of the inputText component, the form submission is unsuccessful, and a warning message is displayed. The message output is specified by the <h:message> tag, which is connected to the inputText component that has the id getdate.

4.4.2.3 Implement the inputDate Composite Component

Modify the inputDate composite component in the components resource library.

  1. Expand Web Pages, then resources, then components, and open inputDate.xhtml.

  2. Add the composite component interface definition between the opening and closing <cc:interface> tags in inputDate.xhtml:

        <cc:interface>
            <cc:attribute name="date" />
        </cc:interface>
    
  3. Add the composite component implementation between the opening and closing cc:implementation tags:

        <cc:implementation>
            <h:inputText id="getdate" value="#{cc.attrs.date}">
                <f:convertDateTime pattern="MM/dd/yyyy" />
            </h:inputText>
            <p/>
            <h:message for="getdate" style="color:red" />
        </cc:implementation>
    
  4. In the editor window, right-click and select Format.

  5. From the File menu, select Save.

4.4.2.4 The Facelets Web Interface

The firstcup-war web application interface has two XHTML files. The greeting.xhtml file displays Duke's current age and the form where the user can enter a birthday. The response.xhtml file displays the age difference between the user and Duke.

The greeting.xhtml file contains several pieces of the firstcup-war application detailed previously. It uses the localized strings contained in WebMessages.properties and WebMessages_es.properties. It uses the DukesBDay managed bean to call both the DukesAgeResource JAX-RS web service and the DukesBirthdayBean enterprise bean. It uses the inputDate composite component to create the input for the user to enter a birthday.

Here's the content of the greeting.xhtml file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
      PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:fc="http://xmlns.jcp.org/jsf/composite/components">
    <h:head>
        <title>Firstcup Greeting Page</title>
    </h:head>
    <h:body>
        <h:form>
            <h2>
                <h:outputText value="#{bundle.Welcome}"/>
            </h2>
            <h:outputText value="#{bundle.DukeIs} "/>
            <h:outputText value="#{dukesBDay.age} #{bundle.YearsOldToday}"/>
            <p/>
            <h:outputText value="#{bundle.Instructions}"/>
            <p/>
            <h:outputText value="#{bundle.YourBD} "/>
            <fc:inputDate id="userBirthday" date="#{dukesBDay.yourBD}" />
            <p/>
            <h:commandButton value="#{bundle.Submit}"
                             action="#{dukesBDay.processBirthday}"/>
        </h:form>

    </h:body>
</html>

The greeting.xhtml file uses the HTML RenderKit and the components resource library tag libraries. The components tag library has a prefix of fc, and is used to specify the inputDate composite component in the form below. The <fc:inputDate id="userBirthday" date="#{dukesBDay.yourBD}" /> tag has the required date attribute, and it stores the value in the yourBD property in the DukesBDay managed bean by using the EL expression #{dukesBDay.yourBD}.

The localized strings are referenced by the EL expressions #{bundle.property-name}. For example, the <h:outputText value="#{bundle.Welcome}"/> tag will display the following string in English locales:

Hi. I'm Duke. Let's find out who's older -- you or I.

The <h:commandButton> tag creates a Submit button and specifies that a successful submission should render the response.xhtml file by setting the action attribute to #{dukesBDay.processBirthday}. The processBirthday method returns the value "/response.xhtml". The action attribute is used to define navigation rules for forms in Facelets pages.

The response.xhtml file displays the age difference between the user and Duke and the average age difference of all users so far. Different strings are displayed based on whether the user is the same age, younger, or older than Duke. The text can be displayed or not based on the conditions specified by the rendered attribute of the <h:outputText> tag. The conditions used in the rendered attribute are Expression Language (EL) alternatives to the Java programming language conditional operators to allow XML parsing of the XHTML file.

Table 4-1 Conditional Operator EL Language Alternatives

Logical Condition Java Programming Language Conditional Operator EL Alternative

AND

&&


&&


EQUALS

==


==


LESS THAN

<


lt

GREATER THAN

>

gt


Here's the content of the response.xhtml file.

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html">
    <h:head>
        <title>Response Page</title>
    </h:head>
    <h:body>
        <h:form>
            <h:outputText value="#{bundle.YouAre} "/>
            <h:outputText value="#{bundle.SameAge}"
                          rendered="#{dukesBDay.ageDiff == 0}"/>
            <h:outputText value="#{dukesBDay.absAgeDiff}"
                          rendered="#{dukesBDay.ageDiff lt 0}"/>
            <h:outputText value=" #{bundle.Year} "
                          rendered="#{dukesBDay.ageDiff == -1}"/>
            <h:outputText value=" #{bundle.Years} "
                          rendered="#{dukesBDay.ageDiff lt -1}"/>
            <h:outputText value="#{bundle.Younger}"
                          rendered="#{dukesBDay.ageDiff lt 0}"/>
            <h:outputText value="#{dukesBDay.absAgeDiff}"
                          rendered="#{dukesBDay.ageDiff gt 0}"/>
            <h:outputText value=" #{bundle.Year} "
                          rendered="#{dukesBDay.ageDiff == 1}"/>
            <h:outputText value=" #{bundle.Years} "
                          rendered="#{dukesBDay.ageDiff gt 1}"/>
            <h:outputText value="#{bundle.Older}"
                          rendered="#{dukesBDay.ageDiff gt 0}"/>
            <p/>
            <h:outputText 
                value="#{bundle.AverageAge} #{dukesBDay.averageAgeDifference}."/>
            <p/>
            <h:commandButton id="back" value="#{bundle.Back}" action="greeting"/>
        </h:form>
    </h:body>
</html>

For example, the #{bundle.SameAge} string is displayed if the user and Duke have the same birthday, as specified by the condition #{dukesBDay.ageDiff == 0} in the rendered attribute. That is, the following string is displayed when the ageDiff property of DukesBDay equals 0:

You are the same age as Duke!

The form also contains a <h:commandButton> tag that creates a Back button, which directs the user back to the greeting.xhtml page, as specified in the action attribute.

4.4.2.5 Add the Form to greeting.xhtml

Add the form that provides the user interface for displaying Duke's age and specifying the user's birthday.

  1. In the Projects tab, double-click greeting.xhtml in the firstcup-war project and, in the editor window, replace the text between the <h:form> and </h:form> tags with the following:

        <h2>
            <h:outputText value="#{bundle.Welcome}"/>
        </h2>
        <h:outputText value="#{bundle.DukeIs} "/>
        <h:outputText value="#{dukesBDay.age} #{bundle.YearsOldToday}"/>
        <p/>
        <h:outputText value="#{bundle.Instructions}"/>
        <p/>
        <h:outputText value="#{bundle.YourBD} "/>
        <fc:inputDate id="userBirthday" date="#{dukesBDay.yourBD}" />
        <p/>
        <h:commandButton value="#{bundle.Submit}" 
                         action="#{dukesBDay.processBirthday}"/>
    
  2. In the editor window, right-click and select Format.

  3. From the File menu, select Save.

4.4.2.6 Add the Form to response.html

Add a form that displays the age difference between Duke and the user, displays the average age difference of all users, and allows the user to navigate back to greeting.xhtml.

  1. In the Projects tab, double-click response.xhtml in the firstcup-war project and, in the editor window, replace the text between the <h:form> and </h:form> tags with the following:

        <h:outputText value="#{bundle.YouAre} "/>
        <h:outputText value="#{bundle.SameAge}"
                      rendered="#{dukesBDay.ageDiff == 0}"/>
        <h:outputText value="#{dukesBDay.absAgeDiff}"
                      rendered="#{DukesBDay.ageDiff lt 0}"/>
        <h:outputText value=" #{bundle.Year} "
                      rendered="#{dukesBDay.ageDiff == -1}"/>
        <h:outputText value=" #{bundle.Years} "
                      rendered="#{dukesBDay.ageDiff lt -1}"/>
        <h:outputText value="#{bundle.Younger}"
                      rendered="#{dukesBDay.ageDiff lt 0}"/>
        <h:outputText value="#{dukesBDay.absAgeDiff}"
                      rendered="#{dukesBDay.ageDiff gt 0}"/>
        <h:outputText value=" #{bundle.Year} "
                      rendered="#{dukesBDay.ageDiff == 1}"/>
        <h:outputText value=" #{bundle.Years} "
                      rendered="#{dukesBDay.ageDiff gt 1}"/>
        <h:outputText value="#{bundle.Older}" 
                      rendered="#{dukesBDay.ageDiff gt 0}"/>
        <p/>
        <h:outputText 
            value="#{bundle.AverageAge} #{dukesBDay.averageAgeDifference}." />
        <p/>
        <h:commandButton id="back" value="#{bundle.Back}" action="greeting"/>
    
  2. In the editor window, right-click and select Format.

  3. From the File menu, select Save.

Previous
Next