Building Bookstore Sample Apps using various Web technologies

Sang Shin, sang.shin@sun.com, Sun Microsystems, www.javapassion.com/j2ee



The goal of this hands-on lab is to exercise various technologies of building BookStore sample application as described below.  You are going to build, run, and modify these sample applications using NetBeans.

Expected duration: 120 minutes (excluding homework)


Software Needed

Before you begin, you need to install the following software on your computer. 


OS platforms you can use


Change Log


Lab Exercises



Exercise 0: Set up the database

In this exercise, you are going to create a new JDBC resource and then create database tables that will be used by the Bookstore sample application.

    1. Add Sun Java System App Server as additional server (Only if you have installed NetBeans and Sun Java System App Server individually)
    2. Start admin console of the Sun Java System Application Server
    3. Create a new JDBC resource
    4. Modify properties of DerbyPool
    5. Start the Derby database (Java DB server)
    6. Create database tables
    7. Verify the BOOKS database table is created

(0.0) Add Sun Java System App Server as additional server


In this step, it is assumed that you have installed NetBeans IDE 5.5 and Sun Java System App Server 9 individually.  If you have installed with Sun Java System Application Server 9 Update 1 bundle (download), this step is not needed.

1. Select Runtime tab.
2. Right click Servers and select Add Server.  (Figure-0.01 below)


Figure-0.01: Add Server

3. Observe that Choose Server pane of the Add Server Instance dialog box appears.  Observe that the Server and the Name fields are set with Sun Java System Application Server.  (Figure-0.02 below)
4. Click Next.


Figure-0.02: Choose Server pane

5. Observe Platform Folder Location pane appears.  Now you have to provide the location where Sun Java System App Server is installed.
6. Click Browse.  (Figure-0.03 below)


Figure-0.03: Platform Folder Location

7. Observe that the Choose Application Server's Install Location pane appears.
8. Browse down to where Sun Java System App Server is installed. (In this example. it is C:\Sun\AppServer9.)
9. Click Choose.  (Figure-0.04 below)


Figure-0.04: Browse down to where Sun Java System App Server is installed

10. Observe now that the Platform Location and Domain fields are set.  (Figure-0.05 below)
11. Click Next.


Figure-0.05: Platform and Domain fields are set

12. Observe that the Domain Admin Login Info pane appears.
13. For the Admin Password field, type in the admin password you chose when you installed Sun Java System App Server.
14. Click Finish. (Figure-0.06 below)


Figure-0.06: Enter Admin password

15. Observe that the Sun Java System Application Server is now added under Servers. (Figure-0.07 below)


Figure-0.07: Sun Java System App Server is now one of the deployment platforms

(0.1) Start admin console of Sun Java System Application Server


1. Right click Sun Java System Application Server 9 and select Start (if it has not been started). (Figure-0.10 below)


Figure-0.10: Start Sun Java System Application Server

2. Right click Sun Java System Application Server 9 and select View Admin Console. (Figure-0.11 below)  The admin console of the Sun Java System App Server can be accessed directly through http://localhost:4848 from your browser (assuming you are using the defaut admin port number 4848).


Figure-0.11: View Admin Console of the Sun Java System App Server

3. Observe that a browser with Sun Java System Application Server Administration Console gets started.
4. For User Name: field, type in admin.
5. For the Password: field, type in adminadmin.
6. Click Log In button.  (Figure-0.12 below)


Figure-0.12: Log in to the admin console

7. Observe that Sun Java System Application Server Admin Console gets displayed.


(0.2) Create a new JDBC resource


1. Expand Resources->JDBC.
2. Double-click JDBC Resources under Resources->JDBC.
3. Observe that existing JDBC Resources are displayed in the right pane of the console.
4. Click New. (Figure-0.13 below)


Figure-0.13: Create a new JDBC Resource

5. For the JNDI Name field, type in jdbc/BookDB.
6. For the Pool Name field, select DerbyTool from the drop-down menu. (Figure-0.14 below)
7. Click OK.


Figure-0.14: Configure new JDBC Resource

8. Observe that jdbc/BookDB is now added.

(0.3) Modify the properties of DerbyPool


1. Expand Connection Pools under Resources->JDBC.
2. Click DerbyPool on the left and scroll down the right pane of the window until you see Properties.
3. Change the Password and User properties to app and app from APP and APP.
4. Change the DatabaseName to sample.
5. Change connectionAttributes to ;create=false (from ;create=true).
6. Click Save.


Figure-0.15: Set the DatabaseName to sample and set the connectionAttributes to create=false


(0.4) Start the Derby database (Java DB Server)


1. From NetBeans, select  Tools and and select Start Java DB Server (if it has not been started already)


Figure-0.30: Start Java DB Server

(0.5) Create database tables


1. From NetBeans, select Runtime tab.
2. Expand Databases.
3. Right click jdbc:derby://localhost:1527/sample [app on App] and select Connect. (Figure-0.50 below)


Figure-0.50: Connect to a database

2. If Connect dialog appears, for the password field, type in app. (Figure-0.51 below)


Figure-0.51: Provide database admin user name and password

3. Get books.sql script.


Figure-0.52: Open file


Figure-0.53: Select books.sql

4. Execute books.sql to create database table.


Figure-0.54: Select Execute Command

CREATE TABLE BOOKS
(id VARCHAR(8),
surname VARCHAR(24),
first_name VARCHAR(24),
title VARCHAR(96),
price FLOAT,
onSale SMALLINT,
calendar_year INT,
description VARCHAR(30),
inventory INT);

INSERT INTO BOOKS VALUES('201', 'Duke', '',
 'My Early Years: Growing up on *7',
 30.75, 0, 1995, 'What a cool book.', 20);

INSERT INTO BOOKS VALUES('202', 'Jeeves', '',
 'Web Servers for Fun and Profit', 40.75, 1,
 2000, 'What a cool book.', 20);

INSERT INTO BOOKS VALUES('203', 'Masterson', 'Webster',
 'Web Components for Web Developers',
 27.75, 0, 2000, 'What a cool book.', 20);

INSERT INTO BOOKS VALUES('205', 'Novation', 'Kevin',
 'From Oak to Java: The Revolution of a Language',
 10.75, 1, 1998, 'What a cool book.', 20);

INSERT INTO BOOKS VALUES('206', 'Gosling', 'James',
 'Java Intermediate Bytecodes', 30.95, 1,
 2000, 'What a cool book.', 20);

INSERT INTO BOOKS VALUES('207', 'Thrilled', 'Ben',
 'The Green Project: Programming for Consumer Devices',
 30.00, 1, 1998, 'What a cool book', 20);

INSERT INTO BOOKS VALUES('208', 'Tru', 'Itzal',
 'Duke: A Biography of the Java Evangelist',
 45.00, 0, 2001, 'What a cool book.', 20);
Code-0.55: books.sql


Figure-0.56: SQL Command is created


Figure-0.58: Run SQL

(0.6) Verify the BOOKS database table is created


1. Right click Tables under jdbc:derby://localhost:1527/sample [app on App] and select Refresh.


Figure-0.50: Refresh

2. Observe that BOOKS table is displayed.
3. Right click BOOKS and select View Data.  (Figure-0.51 below)


Figure-0.51: View Data

4. Observe that the rows of the database table BOOKS is displayed. (Figure-0.52 below)


Figure-0.52: Display BOOKS database table


Exercise 1: Open, build and run "bookstore1" sample application

In this exercise, you are going to build and run "bookstore1" sample application, which uses only Servlets. 

  1. Open, build, and run "bookstore1" sample application
  2. Look under the hood of the "bookstore1" sample application
Note: If you still want to build the bookstore1 sample application using ant script, please see the following instruction.


(1.1) Open, build, and run "bookstore1" sample application

0. Start NetBeans IDE (if it has not been started already)
1. Open bookstore1 NetBeans project (that is provided as part of hands-on lab zip file).

2 Build and run bookstore1 project.


<Learning points> If you are wondering how the URL, ./bookstore1/bookstore, gets displayed automatically (instead of index.jsp) when the application is run, it is because the project is configured that way.  If you right click "bookstore1" project and select Properties, and then select Run on the left, you will Relative URL field is set to /bookstore.  By setting the Relative URL field, you are telling NetBeans to use the URL when it starts the browser.   Note that the Relative URL field is NetBeans project configuration not part of Web application. 


Figure-1.12: Running bookstore1 project



Trouble-shooting-1
: If you see the following error condition (Figure-1.13 in the browser and Figure-1.14 in the Sun Java System App server log file), it is likely because the database has not been started.


Figure-1.13: Error condition


Figure-1.14: Error condition

Solution: Start the Derby database server (Java DB Server) by selcting Tools->Java DB Database->Start Java DB Server. Right click  bookstore1 project and select Clean and Build, then Run Project.

2. Click Duke: A Biography of the Java Evangelist or any other book on the page. (Figure-1.13 below)


Figure-1.13: Select a book

3. Select Add to Cart. (Figure-1.14 below)


Figure-1.14: Add to Cart

4. Select Buy Your Books. (Figure-1.15 below)


Figure-1.15: Select Buy Your Books.

5. Click Submit Information.


Figure-1.16: Click Submit Information


(1.2) Look under the hood of the "bookstore1" applicaiton


1. Study event listener class (same as life cycle event handler class)
package listeners;

import database.BookDBAO;
import javax.servlet.*;
import util.Counter;

// Event handler class for handling application scope events
public final class ContextListener implements ServletContextListener {
    private ServletContext context = null;

    // This method gets called when the application is deployed
    public void contextInitialized(ServletContextEvent event) {
        context = event.getServletContext();

        // Create BookDBAO object and save it as an attribute to
        // ServletContext scope object.
        try {
            BookDBAO bookDB = new BookDBAO();
            context.setAttribute("bookDB", bookDB);
        } catch (Exception ex) {
            System.out.println("Couldn't create bookstore database bean: " +
                ex.getMessage());
        }

        // Save hitCounter and orderCounter attributes in the
        // ServletContext scope object
        Counter counter = new Counter();
        context.setAttribute("hitCounter", counter);
        counter = new Counter();
        context.setAttribute("orderCounter", counter);
    }

    // This method gets called when the application is undeployed
    public void contextDestroyed(ServletContextEvent event) {
        context = event.getServletContext();

        BookDBAO bookDB = (BookDBAO) context.getAttribute("bookDB");

        if (bookDB != null) {
            bookDB.remove();
        }

        context.removeAttribute("bookDB");
        context.removeAttribute("hitCounter");
        context.removeAttribute("orderCounter");
    }
}
Code-1.20: ContextListener.java
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" version="2.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
  <display-name>bookstore1</display-name>
  <filter>
    <filter-name>OrderFilter</filter-name>
    <filter-class>filters.OrderFilter</filter-class>
  </filter>
  <filter>
    <filter-name>HitCounterFilter</filter-name>
    <filter-class>filters.HitCounterFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>OrderFilter</filter-name>
    <servlet-name>ReceiptServlet</servlet-name>
  </filter-mapping>
  <filter-mapping>
    <filter-name>HitCounterFilter</filter-name>
    <servlet-name>BookStoreServlet</servlet-name>
  </filter-mapping>
  <listener>
    <listener-class>listeners.ContextListener</listener-class>
  </listener>
 
 
  ...
</web-app>
Code-1.21: web.xml

2. Study database related classes
package database;

import java.sql.*;
import javax.sql.*;
import javax.naming.*;
import java.util.*;
import exception.*;
import cart.*;

// The instance of BookDBAO gets created when the application
// is deployed. It maintains the Connection object to the
// database. The Connection object is created from DataSource
// object, which is retrieved through JNDI.
// For more information on DataSource, please see
// http://java.sun.com/j2se/1.4.2/docs/api/javax/sql/DataSource.html.
//
// It also maintains list of books in the form of ArrayList.
//

// Study points:
//        - How DataSource object is retrieved through JNDI
//        - How Connection object is obtained through DataSource object

public class BookDBAO {
    private ArrayList books;
    Connection con;
    private boolean conFree = true;

    public BookDBAO() throws Exception {
        try {
            Context initCtx = new InitialContext();
            Context envCtx = (Context) initCtx.lookup("java:comp/env");
            DataSource ds = (DataSource) envCtx.lookup("jdbc/BookDB");
            con = ds.getConnection();
        } catch (Exception ex) {
            throw new Exception("Couldn't open connection to database: " +
                ex.getMessage());
        }
    }

    public void remove() {
        try {
            con.close();
        } catch (SQLException ex) {
            System.out.println(ex.getMessage());
        }
    }

    protected synchronized Connection getConnection() {
        while (conFree == false) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }

        conFree = false;
        notify();

        return con;
    }

    protected synchronized void releaseConnection() {
        while (conFree == true) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }

        conFree = true;
        notify();
    }

    // Return the list of books.
    //
    //
    // Study points:
    //        - How PreparedStatement is used for database operations
    //        - How ResultSet object is used for returned values
    //

    public List getBooks() throws BooksNotFoundException {
        books = new ArrayList();

        try {
            String selectStatement = "select * " + "from books";
            getConnection();

            PreparedStatement prepStmt = con.prepareStatement(selectStatement);
            ResultSet rs = prepStmt.executeQuery();

            while (rs.next()) {
                BookDetails bd =
                    new BookDetails(rs.getString(1), rs.getString(2),
                        rs.getString(3), rs.getString(4), rs.getFloat(5),
                        rs.getBoolean(6), rs.getInt(7), rs.getString(8),
                        rs.getInt(9));

                if (rs.getInt(9) > 0) {
                    books.add(bd);
                }
            }

            prepStmt.close();
        } catch (SQLException ex) {
            throw new BooksNotFoundException(ex.getMessage());
        }

        releaseConnection();
        Collections.sort(books);

        return books;
    }

    // Get book details given a book id
    //
    public BookDetails getBookDetails(String bookId)
        throws BookNotFoundException {
        try {
            String selectStatement = "select * " + "from books where id = ? ";
            getConnection();

            PreparedStatement prepStmt = con.prepareStatement(selectStatement);
            prepStmt.setString(1, bookId);

            ResultSet rs = prepStmt.executeQuery();

            if (rs.next()) {
                BookDetails bd =
                    new BookDetails(rs.getString(1), rs.getString(2),
                        rs.getString(3), rs.getString(4), rs.getFloat(5),
                        rs.getBoolean(6), rs.getInt(7), rs.getString(8),
                        rs.getInt(9));
                prepStmt.close();
                releaseConnection();

                return bd;
            } else {
                prepStmt.close();
                releaseConnection();
                throw new BookNotFoundException("Couldn't find book: " +
                    bookId);
            }
        } catch (SQLException ex) {
            releaseConnection();
            throw new BookNotFoundException("Couldn't find book: " + bookId +
                " " + ex.getMessage());
        }
    }

    // Buy books by calling buyBook() method for each book in the
    // shopping cart.
    //
    // Study points:
    //        - How setAutoCommit() method of a Connection object is used
    //        - How Connection object is retrieved and released
    //
    public void buyBooks(ShoppingCart cart) throws OrderException {
        Collection items = cart.getItems();
        Iterator i = items.iterator();

        try {
            getConnection();
            con.setAutoCommit(false);

            while (i.hasNext()) {
                ShoppingCartItem sci = (ShoppingCartItem) i.next();
                BookDetails bd = (BookDetails) sci.getItem();
                String id = bd.getBookId();
                int quantity = sci.getQuantity();
                buyBook(id, quantity);
            }

            con.commit();
            con.setAutoCommit(true);
            releaseConnection();
        } catch (Exception ex) {
            try {
                con.rollback();
                releaseConnection();
                throw new OrderException("Transaction failed: " +
                    ex.getMessage());
            } catch (SQLException sqx) {
                releaseConnection();
                throw new OrderException("Rollback failed: " +
                    sqx.getMessage());
            }
        }
    }

    // Buy a book - basically reducing the quantity of books in the database.
    //
    public void buyBook(String bookId, int quantity) throws OrderException {
        try {
            String selectStatement = "select * " + "from books where id = ? ";
            PreparedStatement prepStmt = con.prepareStatement(selectStatement);
            prepStmt.setString(1, bookId);

            ResultSet rs = prepStmt.executeQuery();

            if (rs.next()) {
                int inventory = rs.getInt(9);
                prepStmt.close();

                if ((inventory - quantity) >= 0) {
                    String updateStatement =
                        "update books set inventory = inventory - ? where id = ?";
                    prepStmt = con.prepareStatement(updateStatement);
                    prepStmt.setInt(1, quantity);
                    prepStmt.setString(2, bookId);
                    prepStmt.executeUpdate();
                    prepStmt.close();
                } else {
                    throw new OrderException("Not enough of " + bookId +
                        " in stock to complete order.");
                }
            }
        } catch (Exception ex) {
            throw new OrderException("Couldn't purchase book: " + bookId +
                ex.getMessage());
        }
    }
}
Code-1.23: BookDBAO.java

3. Study filters
package filters;

import java.io.*;
import java.sql.Timestamp;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import util.Counter;

// Servlet filter class for updating hitcounter
public final class HitCounterFilter implements Filter {
    private FilterConfig filterConfig = null;

    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    public void destroy() {
        this.filterConfig = null;
    }

    // This method gets called everythime BookStoreServlet gets accessed.
    // See filter mapping of the web.xml file.
    public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException {
        if (filterConfig == null) {
            return;
        }

        HttpServletRequest hr = (HttpServletRequest) request;
        HttpSession session = hr.getSession();
        ResourceBundle messages =
            (ResourceBundle) session.getAttribute("messages");

        if (messages == null) {
            Locale locale = request.getLocale();
            messages = ResourceBundle.getBundle("messages.BookstoreMessages",
                    locale);
            session.setAttribute("messages", messages);
        }

        StringWriter sw = new StringWriter();
        PrintWriter writer = new PrintWriter(sw);

        Counter counter =
            (Counter) filterConfig.getServletContext()
                                  .getAttribute("hitCounter");
        writer.println();
        writer.println(
            "=======================================================");
        writer.println("The number of hits is: " + counter.incCounter());
        writer.println(
            "=======================================================");

        // Log the resulting string
        writer.flush();
        System.out.println(sw.getBuffer().toString());

        PrintWriter out = response.getWriter();
        CharResponseWrapper wrapper =
            new CharResponseWrapper((HttpServletResponse) response);

        // Pass the request to the next filter in the chain.
        chain.doFilter(request, wrapper);

        CharArrayWriter caw = new CharArrayWriter();
        caw.write(wrapper.toString().substring(0,
                wrapper.toString().indexOf("</body>") - 1));
        caw.write("<p>\n<center>" + messages.getString("Visitor") +
            "<font color='red'>" + counter.getCounter() + "</font></center>");
        caw.write("\n</body></html>");
        response.setContentLength(caw.toString()
                                     .getBytes().length);
        out.write(caw.toString());
        out.close();
    }

    public String toString() {
        if (filterConfig == null) {
            return ("HitCounterFilter()");
        }

        StringBuffer sb = new StringBuffer("HitCounterFilter(");
        sb.append(filterConfig);
        sb.append(")");

        return (sb.toString());
    }
}
Code-1.24: HitCounterFilter.java
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" version="2.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
  <display-name>bookstore1</display-name>
  <filter>
    <filter-name>OrderFilter</filter-name>
    <filter-class>filters.OrderFilter</filter-class>
  </filter>
  <filter>
    <filter-name>HitCounterFilter</filter-name>
    <filter-class>filters.HitCounterFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>OrderFilter</filter-name>
    <servlet-name>ReceiptServlet</servlet-name>
  </filter-mapping>
  <filter-mapping>
    <filter-name>HitCounterFilter</filter-name>
    <servlet-name>BookStoreServlet</servlet-name>
  </filter-mapping>
  <listener>
    <listener-class>listeners.ContextListener</listener-class>
  </listener>
  <servlet>
    <display-name>ShowCartServlet</display-name>
    <servlet-name>ShowCartServlet</servlet-name>
    <servlet-class>servlets.ShowCartServlet</servlet-class>
  </servlet>
  <servlet>
    <display-name>CatalogServlet</display-name>
    <servlet-name>CatalogServlet</servlet-name>
    <servlet-class>servlets.CatalogServlet</servlet-class>
  </servlet>
  <servlet>
    <display-name>BookStoreServlet</display-name>
    <servlet-name>BookStoreServlet</servlet-name>
    <servlet-class>servlets.BookStoreServlet</servlet-class>
  </servlet>
  <servlet>
    <display-name>CashierServlet</display-name>
    <servlet-name>CashierServlet</servlet-name>
    <servlet-class>servlets.CashierServlet</servlet-class>
  </servlet>
  <servlet>
    <display-name>BannerServlet</display-name>
    <servlet-name>BannerServlet</servlet-name>
    <servlet-class>servlets.BannerServlet</servlet-class>
  </servlet>
  <servlet>
    <display-name>BookDetailsServlet</display-name>
    <servlet-name>BookDetailsServlet</servlet-name>
    <servlet-class>servlets.BookDetailsServlet</servlet-class>
  </servlet>
  <servlet>
    <display-name>ReceiptServlet</display-name>
    <servlet-name>ReceiptServlet</servlet-name>
    <servlet-class>servlets.ReceiptServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>ShowCartServlet</servlet-name>
    <url-pattern>/bookshowcart</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>CatalogServlet</servlet-name>
    <url-pattern>/bookcatalog</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>BookStoreServlet</servlet-name>
    <url-pattern>/bookstore</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>CashierServlet</servlet-name>
    <url-pattern>/bookcashier</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>BannerServlet</servlet-name>
    <url-pattern>/banner</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>BookDetailsServlet</servlet-name>
    <url-pattern>/bookdetails</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>ReceiptServlet</servlet-name>
    <url-pattern>/bookreceipt</url-pattern>
  </servlet-mapping>
  <error-page>
    <exception-type>exception.BookNotFoundException</exception-type>
    <location>/errorpage.html</location>
  </error-page>
  <error-page>
    <exception-type>javax.servlet.UnavailableException</exception-type>
    <location>/errorpage.html</location>
  </error-page>
  <error-page>
    <exception-type>exception.BooksNotFoundException</exception-type>
    <location>/errorpage.html</location>
  </error-page>
  <jsp-config/>
  <resource-ref>
    <res-ref-name>jdbc/BookDB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
  </resource-ref>
</web-app>
Code-1.25: web.xml

4. Studt the servlets
package servlets;

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import database.*;
import exception.*;


/**
 * An HTTP Servlet that overrides the service method to return a
 * simple web page.
 */
public class BookStoreServlet extends HttpServlet {
    private BookDBAO bookDB;

    public void init() throws ServletException {
        bookDB = (BookDBAO) getServletContext()
                                .getAttribute("bookDB");

        if (bookDB == null) {
            throw new UnavailableException("Couldn't get database.");
        }
    }

    public void destroy() {
        bookDB = null;
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

        // Get HttpSession scope object and retrieve ResourceBundle object.
        HttpSession session = request.getSession();
        ResourceBundle messages =
            (ResourceBundle) session.getAttribute("messages");

        // Use the browser's locale.
        if (messages == null) {
            Locale locale = request.getLocale();
            messages = ResourceBundle.getBundle("messages.BookstoreMessages",
                    locale);
            session.setAttribute("messages", messages);
        }

        // set content-type header before accessing the Writer
        response.setContentType("text/html");
        response.setBufferSize(8192);

        PrintWriter out = response.getWriter();

        // then write the data of the response
        out.println("<html>" + "<head><title>Duke's Bookstore</title></head>");

        // Get the dispatcher; it gets the banner to the user
        RequestDispatcher dispatcher =
            getServletContext()
                .getRequestDispatcher("/banner");

        if (dispatcher != null) {
            dispatcher.include(request, response);
        }

        // Get book detail of the book 203 and display.
        // Study how encodeURL() method is used for URL encoding.
        try {
            BookDetails bd = bookDB.getBookDetails("203");

            //Left cell -- the "book of choice"
            out.println("<b>" + messages.getString("What") + "</b>" + "<p>" +
                "<blockquote>" + "<em><a href=\"" +
                response.encodeURL(request.getContextPath() +
                    "/bookdetails?bookId=203") + "\">" + bd.getTitle() +
                "</a></em>" + messages.getString("Talk") + "</blockquote>");

            //Right cell -- various navigation options
            out.println("<p><a href=\"" +
                response.encodeURL(request.getContextPath() + "/bookcatalog") +
                "\"><b>" + messages.getString("Start") + "</b></a></font><br>" +
                "<br> &nbsp;" + "<br> &nbsp;" + "<br> &nbsp;" + "</body>" +
                "</html>");
        } catch (BookNotFoundException ex) {
            response.resetBuffer();
            throw new ServletException(ex);
        }

        out.close();
    }

    public String getServletInfo() {
        return "The BookStore servlet returns the main web page " +
        "for Duke's Bookstore.";
    }
}
Code-1.27: BookStoreServlet.java

Summary

In this exercise,  you have built and run "bookstore1" sample application.  You have looked into how an event listener is written and configured.  You also have seen two filters.  You studied how servlets are used to write bookstore1 sample application.

                                                                                                                        return to the top



Exercise 2: Build and run "bookstore2" sample application

In this exercise, you are going to build and run "bookstore2" sample application, which uses only JSP pages. 


(2.1) Build and run "bookstore2" sample application


1. Open bookstore2 NetBeans project (that is provided as part of hands-on lab zip file). 

2 Build and run bookstore2 project.


(2.2) Look under the hood of the "bookstore2" sample application


1. Study web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" version="2.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
  <display-name>bookstore2</display-name>
  <context-param>
    <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
    <param-value>messages.BookstoreMessages</param-value>
  </context-param>
  <listener>
    <listener-class>listeners.ContextListener</listener-class>
  </listener>
  <servlet>
    <display-name>Dispatcher</display-name>
    <servlet-name>Dispatcher</servlet-name>
    <servlet-class>dispatcher.Dispatcher</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>Dispatcher</servlet-name>
    <url-pattern>/bookstore</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>Dispatcher</servlet-name>
    <url-pattern>/bookdetails</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>Dispatcher</servlet-name>
    <url-pattern>/bookcatalog</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>Dispatcher</servlet-name>
    <url-pattern>/bookshowcart</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>Dispatcher</servlet-name>
    <url-pattern>/bookcashier</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>Dispatcher</servlet-name>
    <url-pattern>/bookreceipt</url-pattern>
  </servlet-mapping>
  <jsp-config>
    <jsp-property-group>
      <display-name>bookstore2</display-name>
      <url-pattern>*.jsp</url-pattern>
      <el-ignored>false</el-ignored>
      <scripting-invalid>false</scripting-invalid>
      <is-xml>false</is-xml>
      <include-prelude>/template/prelude.jspf</include-prelude>
      <include-coda>/template/coda.jspf</include-coda>
    </jsp-property-group>
  </jsp-config>
  <resource-ref>
    <res-ref-name>jdbc/BookDB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
  </resource-ref>
</web-app>
Code-2.20: web.xml of the bookstore2 sample application

2. Study Dispatcher.java
package dispatcher;

import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
import cart.ShoppingCart;
import database.*;
import exception.*;


public class Dispatcher extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) {
        String bookId = null;
        String clear = null;
        BookDetails book = null;
        BookDBAO bookDBAO =
            (BookDBAO) getServletContext()
                           .getAttribute("bookDBAO");
        HttpSession session = request.getSession();

        // Retrieve ServletPath from the request object.
        String selectedScreen = request.getServletPath();
        ShoppingCart cart = (ShoppingCart) session.getAttribute("cart");

        // If cart attribute is not present in the HttpSession scope object,
        // create one and save it.
        if (cart == null) {
            cart = new ShoppingCart();
            session.setAttribute("cart", cart);
        }

        // Based on the ServletPath, extract request parameters
        if (selectedScreen.equals("/bookcatalog")) {
            bookId = request.getParameter("Add");

            if (!bookId.equals("")) {
                try {
                    book = bookDBAO.getBookDetails(bookId);
                    cart.add(bookId, book);
                } catch (BookNotFoundException ex) {
                    // not possible
                }
            }
        } else if (selectedScreen.equals("/bookshowcart")) {
            bookId = request.getParameter("Remove");

            if (bookId != null) {
                cart.remove(bookId);
            }

            clear = request.getParameter("Clear");

            if ((clear != null) && clear.equals("clear")) {
                cart.clear();
            }
        } else if (selectedScreen.equals("/bookreceipt")) {
            // Update the inventory
            try {
                bookDBAO.buyBooks(cart);
            } catch (OrderException ex) {
                selectedScreen = "/bookordererror";
            }
        }

        // Determine the destination jsp for forwarding
        String screen = selectedScreen + ".jsp";

        // Perform the forwarding
        try {
            request.getRequestDispatcher(screen)
                   .forward(request, response);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) {
        String screen = request.getServletPath() + ".jsp";

        try {
            request.getRequestDispatcher(screen)
                   .forward(request, response);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
Code-2.21: Dispatcher.java

3. Study JSP pages
<%-- Display localized string of "What" --%>
<p><b><fmt:message key="What"/></b></p>

<%-- Create bookDB attribute in a page scope --%>
<jsp:useBean id="bookDB" class="database.BookDB" scope="page" >
    <jsp:setProperty name="bookDB" property="database" value="${bookDBAO}" />
</jsp:useBean>

<%-- Set the bookId property of the bookDB bean with value of "203" --%>
<jsp:setProperty name="bookDB" property="bookId" value="203" />

<p>
<%-- Retrieve the result of /bookdetails --%>
<c:url var="url" value="/bookdetails" />
<blockquote><p><em><a href="${url}?bookId=203">${bookDB.bookDetails.title}</a></em>,
    <c:url var="url" value="/bookcatalog" />
<fmt:message key="Talk"/></blockquote>
<p><b><a href="${url}?Add="><fmt:message key="Start"/></a></b>
Code-2.22: bookstore.jsp
<jsp:useBean id="bookDB" class="database.BookDB" scope="page" >
  <jsp:setProperty name="bookDB" property="database" value="${bookDBAO}" />
</jsp:useBean>

<c:if test="${!empty param.bookId}">
  <c:set var="bid" value="${param.bookId}"/>
  <jsp:setProperty name="bookDB" property="bookId" value="${bid}" />
  <c:set var="book" value="${bookDB.bookDetails}" />
      <h2>${book.title}</h2>
      &nbsp;<fmt:message key="By"/> <em>${book.firstName}&nbsp;${book.surname}</em>&nbsp;&nbsp;
      (${book.year})<br> &nbsp; <br>
      <h4><fmt:message key="Critics"/></h4>
      <blockquote>${book.description}</blockquote>
      <h4><fmt:message key="ItemPrice"/>: <fmt:formatNumber value="${book.price}" type="currency"/></h4>
    <c:url var="url" value="/bookcatalog" >
      <c:param name="Add" value="${bid}" />
    </c:url>
    <p><strong><a href="${url}"><fmt:message key="CartAdd"/></a>&nbsp; &nbsp; &nbsp;
</c:if>


<c:url var="url" value="/bookcatalog" >
  <c:param name="Add" value="" />
</c:url>
<a href="${url}"><fmt:message key="ContinueShopping"/></a></p></strong>
Code-2.23: bookdetails.jsp

Summary


In this exercise, you have built and studies bookstore2 sample application, which is mainly built with JSP files.

                                                                                                                        return to the top


Exercise 3: Building "bookstore3" sample application


In this exercise, you are going to build and run "bookstore3" sample application, which uses JSP pages and custom tags that are created using tag files. 


(3.1) Build and run "bookstore3" sample application


0. Start NetBeans IDE and select Project tab.
1. Open bookstore3 NetBeans project. 

2 Build and run bookstore3 project.


Figure-3.10: bookcatalog

(3.2) Look under the hood of the "bookstore3" sample application


1. Expand tags under bookstore3->Web Pages->WEB-INF.
2. Observe that there are two tag files - catalog.tag and shipDate.tag.


Figure-3.20: Tag files

3.  Double click catalog.tag under bookstore3->Web Pages->WEB-INF->tags to open it in the sourc editor. 

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>

<%@ attribute name="bookDB" required="true" type="database.BookDB" %>
<%@ attribute name="color" required="true" %>

<%@ attribute name="normalPrice" fragment="true" %>
<%@ attribute name="onSale" fragment="true" %>
<%@ variable name-given="price" %>
<%@ variable name-given="salePrice" %>

<center>
<table summary="layout">
<c:forEach var="book" begin="0" items="${bookDB.books}">
  <tr>
  <c:set var="bookId" value="${book.bookId}" />
  <td bgcolor="${color}">
      <c:url var="url" value="/bookdetails" >
        <c:param name="bookId" value="${bookId}" />
      </c:url>
      <a href="${url}"><strong>${book.title}&nbsp;</strong></a></td>
  <td bgcolor="${color}" rowspan=2>
   

  <c:set var="salePrice" value="${book.price * .85}" />
  <c:set var="price" value="${book.price}" />

    <c:choose>
      <c:when test="${book.onSale}" >
        <jsp:invoke fragment="onSale" />
      </c:when>
      <c:otherwise>
        <jsp:invoke fragment="normalPrice" />
      </c:otherwise>
    </c:choose>
   
  &nbsp;</td>

  <td bgcolor="${color}" rowspan=2>
  <c:url var="url" value="/bookcatalog" >
    <c:param name="Add" value="${bookId}" />
  </c:url>
  <p><strong><a href="${url}">&nbsp;<fmt:message key="CartAdd"/>&nbsp;</a></td></tr>

  <tr>
  <td bgcolor="#ffffff">
  &nbsp;&nbsp;<fmt:message key="By"/> <em>${book.firstName}&nbsp;${book.surname}</em></td></tr>
</c:forEach>

</table>
</center>
Code-3.21: catalog.tag

Now let's find out where the catalog tag is used.  You can perform Edit->Find in Projects with :catalog to find out which files use the catalog tag.  You will find that catalog tag is used in bookcatalog.jsp.

4. Double click bookcatalog.jsp under bookstore3->Web Pages.  Study how the <sc:catalog ..> tags are used. (Code-3.22 below)

<%@ taglib prefix="sc" tagdir="/WEB-INF/tags" %>

<jsp:useBean id="bookDB" class="database.BookDB" scope="page" >
  <jsp:setProperty name="bookDB" property="database" value="${bookDBAO}" />
</jsp:useBean>


<c:if test="${!empty param.Add}">
  <c:set var="bid" value="${param.Add}"/>
  <jsp:setProperty name="bookDB" property="bookId" value="${bid}" />
  <c:set var="addedBook" value="${bookDB.bookDetails}" />
    <p><h3><font color="red" size="+2">
    <fmt:message key="CartAdded1"/> <em>${addedBook.title}</em> <fmt:message key="CartAdded2"/></font></h3>
</c:if>

<c:if test="${sessionScope.cart.numberOfItems > 0}">    
  <c:url var="url" value="/bookshowcart" >
    <c:param name="Clear" value="0" />
    <c:param name="Remove" value="0" />
  </c:url>
<p><strong><a href="${url}"><fmt:message key="CartCheck"/></a>&nbsp;&nbsp;&nbsp;
    <c:url var="url" value="/bookcashier" />
    <a href="${url}"><fmt:message key="Buy"/></a></p></strong>
</c:if>

<br>&nbsp;
<br>&nbsp;
<h3><fmt:message key="Choose"/></h3>



<sc:catalog bookDB ="${bookDB}" color="#cccccc">
  <jsp:attribute name="normalPrice">
    <fmt:formatNumber value="${price}" type="currency"/>
  </jsp:attribute>
  <jsp:attribute name="onSale">
    <strike><fmt:formatNumber value="${price}" type="currency"/></strike><br/>
    <font color="red"><fmt:formatNumber value="${salePrice}" type="currency"/></font>
  </jsp:attribute>
</sc:catalog>
Code-3.22: bookcatalog.jsp

5. Study how shipDate.tag is used.

Summary


In this exercise, you have built and studies bookstore3 sample application, which is mainly built with JSP files and custom tags.

                                                                                                                        return to the top


Exercise 4: Building "bookstore4" sample application


In this exercise, you are going to build and run "bookstore4" sample application, which uses JSP pages and JSTL in native format. 


(4.1) Build and run "bookstore4" sample application


0. Start NetBeans IDE and select Project tab.
1. Open bookstore4 NetBeans project. 

2 Build and run bookstore4 project.


(4.2) Look under the hood of the "bookstore4" sample application


<to be provided>

Summary


In this exercise, you have built and studies bookstore2 sample application, which is mainly built with JSP files JSTL in native format.

                                                                                                                        return to the top




Homework Exercise (for people who are taking Sang Shin's "Java EE Programming online course")


There is no homework exercise for this hands-on lab.

                                                                                                                     return to the top