## Chapter 27

# JavaServer Pages and Servlets

## Chapter Goals

- To implement dynamic web pages with JavaServer Faces (JSF) technology
- To learn the syntactical elements of JavaServer Faces
- To learn about navigation in JSF applications
- To build three-tier web applications

## A Simple JSF Program

- JSF: Java Server Faces
- To develop a JSF application, you need a web server that is integrated with a JSF container
- A JSF page contains HTML and JSF tags
- The user interface of a JSF application is described by a set of JSF pages

## A Simple JSF Program

- Each JSF page has the following structure:

      <html>
         <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
         <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
         <f:view>
            <head>
               <title>Page title</title>
            </head>
            <body>
               <h:form>
                  Page contents
               </h:form>
            </body>
         </f:view>
      </html>

## A Simple JSF Program

- Previous structure has three parts:
  1. `taglib` directives required to locate two JSF libraries
     - Tags from the core library have the prefix `f:` (such as `f:view`)
     - Tags from the HTML library have the prefix `h:` (such as `h:form`)
  2. All JSF tags must be contained inside an `f:view` tag
  3. The `h:form` tag encloses all user interface elements

## Executing the `datetime` Web Application

## File datetime/index.jsp

## The JSF Container Rewrites the Requested Page

## A Simple JSF Program

- Purpose of a JSF page is to generate an HTML page
- Basic process:
  - HTML tags in the page are retained; they are the static part of the page
  - JSF tags are translated into HTML; translation is dynamic, it depends on the state of Java objects
    - The `h:` tags generate HTML
    - The `f:` describe structural information that the `h:` tags use
  - The `taglib` directives are stripped out

## The HTML Code That Is Generated by a JSF Page

## A Simple JSF Program

- The JSF container converts a JSF page to an HTML page, replacing JSF tags with text and HTML
- In the example, the `h:outputText` tag has the value binding `#{dateTime.time}`
- Value bindings link JSF pages with Java objects
- The Java objects are defined in a configuration file
  - Named `faces-config.xml`
  - Placed in the `WEB-INF` subdirectory of the web application's base directory

## File datetime/WEB-INF/faces-config.xml

## A Simple JSF Program

- This file defines an object `dateTime` with type `java.util.Date`
- A new object is constructed with each "request"
- Whenever a browser requests the page,
  - A new `Date` object is constructed, and
  - It is attached to the `dateTime` variable
  - The `Date` constructor constructs an object with the current time
- `#{dateTime.time}` calls `getTime` of `dateTime`
- The `h:outputText` tag converts the result of that method call to text

## Important Design Principle of the JSF Technology

- JSF enables the separation of presentation and business logic
- Presentation logic: the user interface of the web application
- Business logic: the part of the application that is independent of the visual presentation
- JSF pages define the presentation logic
- Java objects define the business logic
- The value bindings tie the two together

## Steps for Deploying a JSF Application

1. Make a subdirectory with the name of your web application in the `webapps` directory of your Tomcat installation

       /usr/local/jakarta-tomcat/webapps/datetime

   or

       c:\Tomcat\webapps\datetime

2. Place the `index.jsp` file into that directory
3. Create a subdirectory `WEB-INF` in your application directory

       /usr/local/jakarta-tomcat/webapps/datetime/WEB-INF

   or

       c:\Tomcat\webapps\datetime\WEB-INF

## Steps for Deploying a JSF Application

1. Place `faces-config.xml` into the `WEB-INF` subdirectory
2. Place your Java classes (if any) inside `WEB-INF/classes`
3. Place the file `web.xml` inside the `WEB-INF` subdirectory
4. Start the web server
5. Point your browser to `http://localhost:8080/datetime/index.faces`

## The Directory Structure of the `datetime` Application

## The Java Studio Creator Tool

## File datetime/WEB-INF/web.xml

## Self Check

1. What steps are required to add the image of a clock to the `datetime` application? (The clock doesn't have to show the correct time.)
2. Does a Swing program automatically separate presentation and business logic?

## Answers

1. Place an image file, say `clock.gif`, into the `datetime` directory, and add a tag `<img src="clock.gif"/>` to the `index.jsp` file.
2. No–it is possible (and sadly common) for programmers to place the business logic into the frame and component classes of the user interface.

## JavaBeans Components

- Software component:
  - Encapsulates functionality
  - Can be plugged into a software system without programming
  - For example, the `dateTime` object
- Unlike some programming languages, Java does have explicit support for components
- In Java, use a programming convention to implement components
  - A JavaBean is a Java class that follows this convention
- A JavaBean exposes properties–values of the component that can be accessed without programming

## JavaBeans Components

- JavaBean requirements:
  1. Must have a public constructor with no parameters
  2. Must have methods for accessing the component properties that follow the get/set naming convention

## JavaBeans Components

- For example, to get or set the time of a `Date` object,
  must use `getTime` and `setTime`
- For a property with name propertyName and type `Type`,

      public Type getPropertyName()
      public void setPropertyName(Type newValue)

- Exception: the accessor of a `boolean` property can use an is prefix

      public boolean isShopping()

## JavaBeans Components

- The name of a property starts with a lowercase letter
- The corresponding methods have an uppercase letter (`isShopping`)
- Exception: property names can be all capitals (e.g. `ID` or `URL`)
  - `getID` or `setURL`
- Read-only property: has only a get method
- Write-only property: has only a set method
- A JavaBean can have additional methods, but they are not connected with properties

## JavaBeans Components

- Many programmers follow the additional convention that the name of a bean class should end in `Bean`

      public class UserBean
      {
         // Required default constructor
         public UserBean() { . . . }

         // creditCard property
         public String getCreditCard() { . . . }
         public void setCreditCard(String newValue) { . . . }

         // shopping property
         public boolean isShopping() { . . . }
         public void setShopping(boolean newValue) { . . . }

         // Other methods
         . . .
         // Instance fields
         . . .
      }

## JavaBeans Components

- This bean has two properties: `creditCard` and `shopping`
- Do not make any assumptions about the internal representation of properties
  - May have an instance field for every property:

        private String creditCard;
        private boolean shopping;

  - May store the credit card state in a database
    - get and set methods would contain database operations
  - May compute the property value:

        public boolean isShopping() { return shoppingCart != null; }

## JavaBeans Components

- To use a bean in a JSF page, define it in `faces-config.xml`

      <managed-bean>
         <managed-bean-name>user</managed-bean-name>
         <managed-bean-class>bigjava.UserBean</managed-bean-class>
         <managed-bean-scope>session</managed-bean-scope>
      </managed-bean>

- Called a managed bean because the JSF container manages its lifetime
- Session scope: the bean is available for multiple requests by the same browser
- Application scope: the bean stays alive for the entire web application
  - It is shared among different users

## JavaBeans Components

- Access the bean properties in value bindings

      <h:outputText value="#{user.creditCard}"/>

- Specify the name of the property, not the name of the get or set methods
  - `<h:inputText value="#{user.creditCard}"/>` first calls `getCreditCard`
  - When the user submits the form, the `setCreditCard` is called to store the edited property value

## JavaBeans Components: An Example

- We want to display the current time, not the number of milliseconds since January 1, 1970
- Default time computation uses the time zone at the server location → not very useful
- We will prompt for the city in which the user is located,
  and display the time in the user's time zone

## JavaBeans Components: An Example

- Java library contains a `TimeZone` class
  - A time zone is identified by a string such as "America/Los_Angeles" or "Asia/Tokyo"
  - `getAvailableIDs` returns a string array containing all IDs:

        String[] ids = TimeZone.getAvailableIDs();

  - `getTimeZone` returns a `TimeZone` object for a given ID string:

        String id = "America/Los_Angeles";
        TimeZone zone = TimeZone.getTimeZone(id);

## JavaBeans Components: An Example

- Use a `DateFormat` object to get a time string:

      DateFormat timeFormatter = DateFormat.getTimeInstance();
      timeFormatter.setTimeZone(zone);
      Date now = new Date();
      // Suppose the server is in New York, and it's noon there
      System.out.println(timeFormatter.format(now));
      // Prints 9:00:00 AM

## JavaBeans Components: An Example

- Interaction with user:
  - The user will simply enter the city name
  - The time zone bean will replace the spaces in the name with underscores
  - Then, check if that string appears at the end of one of the valid time zone IDs

## The timezone Application

## File timezone/WEB-INF/classes/bigjava/TimeZoneBean.java

## File timezone/WEB-INF/faces-config.xml

## File timezone/index.jsp

## The Directory Structure of the `timezone` Application

## Self Check

1. Is the `Random` class a Java bean?
2. What work does the `setCity` method of the `TimeZoneBean` do besides setting the city instance field?
3. When you start the `timezone` application for the first time, why does the input field contain the string "Los Angeles"?

## Answers

1. Technically, yes. It has a default constructor. However, it has no methods whose name start with get or set, so it exposes no properties.
2. It sets the zone instance field to match the time zone of the city.
3. When the zone bean was constructed, its city property was set to "Los Angeles". When the input field is rendered, its default value is the current value of the city property.

## Session State and Cookies

## JSF Components

- Each component has a value attribute to connect the component value with a bean property

      <h:inputSecret value="#{user.password}"/>

- `h:inputTextArea` has attributes to specify the rows and columns

      <h:inputTextArea value="#{user.comment}" rows="10" cols="40"/>

- Radio button and checkbox groups allow you to specify horizontal or vertical layout:

      <h:selectOneRadio value="#{burger.topping}" layout="lineDirection">

## JSF Components: Button Groups and Menus

- Require two properties:
  - the collection of possible choices
  - the actual choice
- The value attribute specifies the actual choice to be displayed
- The collection of possible choices is defined by a nested `f:selectItems` tag

      <h:selectOneRadio value="#{creditCard.expirationMonth}"
            layout="pageDirection">
         <f:selectItems value="#{creditCard.monthChoices}"/>
      </h:selectOneRadio>

- `monthChoices` must have a type that can describe a list of choices
  - For example, `Map`
  - The keys of the map are the labels
  - The corresponding map values are the label values

## Example: Using a `Map` to Describe a List of Choices

- To create the list of choices:

      public class CreditCardBean
      {
         . . .
         public Map<String, Integer> getMonthChoices()
         {
            Map<String, Integer> choices = new LinkedHashMap<String, Integer>();
            choices.put("January", 1);
            choices.put("February", 2);
            . . .
            return choices;
         }
      }

- The type of the value property of the component must match the type of the map value
  - For example, `creditCard.expirationMonth` must be an integer
- If multiple selections are allowed, the type of the value property must be a list or array of matching types

## Common JSF Components

Component | JSF Tag | Common Attributes | Example
--- | --- | --- | ---
Text Field | `h:inputText` | `value` | ``
Password Field | `h:inputSecret` | `value` | ``
Text Area | `h:inputTextArea` | `value rows cols` | ``
Radio Button Group | `h:selectOneRadio h:selectManyRadio` | `value layout` | ``
Checkbox | `h:selectOneCheckbox` | `value` | ``
Checkbox Group | `h:selectManyCheckbox` | `value layout` | ``
Menu | `h:selectOneMenu h:selectManyMenu` | `value` | ``
Image | `h:graphicImage` | `value` | ``
Submit Button | `h:commandButton` | `value action` | ``

## Self Check

1. Which JSF components can be used to give a user a choice between "AM/PM" and "military" time?
2. How would you supply a set of choices for a credit card expiration year to a `h:selectOneMenu` component?

## Answers

1. `h:selectOneRadio`, `h:selectOneMenu`, or `h:selectOneCheckbox`
2. You would need a bean with a property such as the following:

       public Map<String, Integer> getYearChoices()
       {
          Map<String, Integer> choices = new TreeMap<String, Integer>();
          choices.put("2003", 2003);
          choices.put("2004", 2004);
          . . .
          return choices;
       }

   Then supply a tag `<f:selectItems value="#{creditCard.yearChoices}"/>`.

## Navigation Between Pages

- Consider an enhancement of our `timezone` program
- We start with a page that prompts the user to enter the name of a city
- When the user clicks "Submit" a new page appears
- Next page is either the page with the time display or an error page if no time zone is available
- The JSF container needs to determine which page to show next

## Navigating Between Pages

## Navigation Between Pages

- Each button has an outcome, a string used to look up the next page
- Generally, next page may depend on the result of some computation
- We need different outcomes depending on the city entered
- Specify a method binding as the action attribute:

      <h:commandButton value="Submit" action="#{zone.addCity}"/>

- A method binding consists of the name of a bean and the name of a method

## Navigation Between Pages

- When the form is submitted, the JSF engine calls `zone.addCity()`

      public class TimeZoneBean
      {
         . . .
         public String addCity()
         {
            if (zone == null) return "unavailable";
            // Add the city
            . . .
            return "available";
         }
      }

- If next page doesn't depend on a computation, you set the action attribute of the button to a fixed outcome string

      <h:commandButton value="Back" action="back"/>

## Navigation Between Pages

- `faces-config.xml` contains a navigation rule that maps outcome strings to pages:

      <faces-config>
         <navigation-rule>
            <navigation-case>
               <from-outcome>available</from-outcome>
               <to-view-id>/next.jsp</to-view-id>
            </navigation-case>
            <navigation-case>
               <from-outcome>unavailable</from-outcome>
               <to-view-id>/error.jsp</to-view-id>
            </navigation-case>
            <navigation-case>
               <from-outcome>back</from-outcome>
               <to-view-id>/index.jsp</to-view-id>
            </navigation-case>
         </navigation-rule>
         . . .
      </faces-config>

- Current page is redisplayed when
  - The button has no action attribute, or
  - The action outcome is not listed in the navigation rules

## Self Check

1. What tag would you need to add to `error.jsp` so that the user can click on a button labeled "Help" and see `help.jsp`? What other changes do you need to make to the web application?
2. Which page would be displayed if the `addCity` method returned `null`?

## Answers

1. Add the tag `<h:commandButton value="Help" action="help"/>` to `error.jsp`, and add a navigation rule to `faces-config.xml`:

       <navigation-case>
          <from-outcome>help</from-outcome>
          <to-view-id>/help.jsp</to-view-id>
       </navigation-case>

2. The current page would be redisplayed.

## A Three-Tier Application

- A three-tier application has separate tiers for presentation, business logic, and data storage
  - The presentation tier: the web browser
  - The "business logic" tier: the JSF container, the JSF pages, and the JavaBeans
  - The storage tier: the database

## Three-Tier Architecture

## Two-Tier Client-Server Architecture

## A Three-Tier Application

- If business logic changes
  - In a two-tier application, new client program must be distributed over all desktops
  - In a three-tier application, server code is updated, while presentation tier remains unchanged
    - Simpler to manage

## A Three-Tier Application

- We will have a single database table, `CityZone`, with city and time zone names
- If the `TimeZoneBean` can't find the city among the standard time zone IDs, it makes a query:

      SELECT Zone FROM CityZone WHERE City = the requested city

- If there is a matching entry in the database, that time zone is returned

## File multizone/misc/CityZone.sql

## The `CityZone` Table

## A Three-Tier Application

- To query the database, the bean needs a `Connection` object
- With Tomcat, specify the database configuration in `conf/server.xml`
  - Locate the element

        <Host name="localhost" . . . >

  - Immediately after, add the configuration information found on the next slide
  - You need to place the JDBC driver file into `common/lib`
  - Restart server after changing the configuration file

## A Three-Tier Application

    <DefaultContext>
       <Resource name="jdbc/mydb" auth="Container" type="javax.sql.DataSource"/>
       <ResourceParams name="jdbc/mydb">
          <parameter>
             <name>factory</name>
             <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
          </parameter>
          <parameter>
             <name>driverClassName</name>
             <value>driver class</value>
          </parameter>
          <parameter>
             <name>url</name>
             <value>database URL</value>
          </parameter>
          <parameter>
             <name>username</name>
             <value>database user name</value>
          </parameter>
          <parameter>
             <name>password</name>
             <value>database user password</value>
          </parameter>
       </ResourceParams>
    </DefaultContext>

## A Three-Tier Application

- To obtain a database connection, first look up the data source that was configured in the JSF container:

      InitialContext ctx = new InitialContext();
      DataSource source = (DataSource) ctx.lookup("java:comp/env/jdbc/mydb");
      Connection conn = source.getConnection();
      try
      {
         Use the connection
      }
      finally
      {
         conn.close();
      }

- JSF containers such as Tomcat manage a pool of database connections
  - Pooling avoids the overhead of creating new database connections
  - Pooling is completely automatic

## A Three-Tier Application

- Enhanced `TimeZoneBean` so that it manages a list of cities
- Can add cities to the list and remove a selected city

## The Directory Structure of the `multizone` Application

## File multizone/index.jsp

## File multizone/next.jsp

## File multizone/error.jsp

## File multizone/WEB-INF/classes/bigjava/TimeZoneBean.java

## File multizone/WEB-INF/faces-config.xml

## Self Check

1. Why don't we just keep a database connection as an instance field in the `TimeZoneBean`?
2. Why does the `removeCity` method of the `TimeZoneBean` return null or "back", depending on the size of the cities field?

## Answers

1. Then the database connection would be kept open for the entire session.
2. As long as there are cities, the `next.jsp` page is redisplayed. If all cities are removed, it is pointless to display the `next.jsp` page, so the application navigates to the `index.jsp` page.