Dave’s Dust Collectors ReadMe

Version 1.0

Contents

1.0 Introduction

2.0 Installing and Executing Dave’s Dust Collectors

3.0 How to Use the Dust Collectors Web Site

4.0 About the DustCollectors Database

5.0 Particulars About the Application

            5.1 About Data Validation

            5.2 About the Inventory

            5.3 Submitting an Order

            5.4 User Interface Items

 

6.0 Conclusion

 

1.0 Introduction

Welcome to Dave’s Dust Collectors. This is my first attempt at creating an online shopping web site, using Java servlets. The inspiration for Dave’s Dust Collectors came out of a desire to create the same shopping experience one finds at many web sites today, where small JPEGs of the items for sale are presented, which can be added to a shopping cart with the click of a button. Since I needed pictures of things to sell, I decided to take a few digital photos of stuff lying around my house. Yes, all of the products that are for sale at Dave’s Dust Collectors are things that I actually own. If you are not familiar with the term dust collector, it refers to any item you may find in your home that does not do much, other than sit on a shelf and collect dust.

The Dust Collectors web site was created using servlets along with a few static html pages. I decided not to use Java Server Pages for the web site not because I think that using servlets provides a better solution, but rather because I am new to writing online applications, I wanted to get a better feel for how servlets work before moving on to jsp and other newer architectures. Needless to say, it did not take me long to appreciate why JSPs were invented. Besides understanding the maintenance difficulties that servlets produce, I also found that, in an effort to reduce redundant code, the html content for a given page of the Dust Collectors web site became scattered among several classes, making it difficult to remember which classes collaborated to create the web page. That experience sent me scrambling to the internet to look for solid design patterns for e-commerce sites using servlets. Many solutions suggested using JSP to create pages rather than servlets.

 

2.0 Installing and Executing Dave’s Dust Collectors

These instructions make a few assumptions about the environment you plan on running this web site under.

1)      You are going to run Dust Collectors using Jakarta Tomcat version 5.5.4.

2)      Tomcat has been configured to run under a J2SE 5 JRE.

3)      The Oracle driver, classes12.zip, has been copied to your $CATALINA_HOME/common/lib directory and has been renamed to classes12.jar.

There may be other ways to get Dust Collectors to work and it may work under different servlet containers, but this is easiest way to run the web site and it is also the only configuration that it has been tested under. The Dust Collectors web site will definitely need to run under the J2SE 5 JRE, as it makes a method call within the BigDecimal class that did not exist under JRE 1.4. Also, as I will talk about later, Dust Collectors makes use of Tomcat’s Database connection pooling, so Tomcat needs to be able access Oracle’s database driver. The easiest way to accomplish this is by copying the classes12.zip file to the common/lib directory of your Tomcat installation and renaming it to classes12.jar.

If the Tomcat server is running, shut it down. Download the DustCollectors.zip file to a temporary director. Using WinZip, extract the contents of DustCollectors.zip to the following Tomcat directory:

$CATALINA_HOME\webapps

Be sure that the ‘Use folder names’ option is selected in WinZip during the extract. If done correctly, your directory structure should look something like:

 

Now start the Tomcat server.

 

3.0 How to Use the Dust Collectors Web Site

Open up a web browser and, in the browser’s address field, type

http://ipaddress:8080/DustCollectors/index.html

where ipaddress is the ip address of the machine that is running the Tomcat server. If you are running the browser on the same machine as the Tomcat server, you may optionally type,

http://localhost:8080/DustCollectors/index.html

in the browser’s address field. Press the Enter key and after a few seconds you should see the Dust Collectors log in page shown below.

 

Since you are a new customer, click the Register here link. Or, if you wish, you can log in with the following authorized user id and password:

User ID: annek

Password: java4me

Assuming you decided to click Register here, you should see a form that looks like this.

Fill out your name, user id (make one up) and password (make one up) and then click on Submit. If not all fields were filled in, the registration page will be presented again. If, by some remote chance, the user id already exists in the database, the registration page will be presented again with a message such as,

            That user id is already being used. Please choose another user id.

At this point you should know if the Dust Collectors web site is successful in accessing the database. If there is an error, make sure that the installation instructions given in section 2.0 were followed correctly. If all goes well you will be presented with the log in page again. Enter the user id and password you registered with and click Log in to begin shopping.

Once your user id and password have been validated, you will see a page with the Dust Collector goodies that are for sale along with a personalized message welcoming you to the site.

 

If you see an item that you want to purchase, you can add it to your shopping cart by clicking the add to cart button next to the item. If  you want to purchase more than one of the item, enter the quantity desired in the same row before you click the add to cart button. The Dust Collectors program does check to see if a valid integer was entered for quantity. Once you have selected an item, the web site will display your shopping cart so far, personalized with your name on it.

 

At this point you may keep shopping by clicking the Continue shopping link. At any time you can view your shopping cart by selecting the Show Cart link. Also, after each addition to your shopping cart, your shopping cart will be displayed. If there are any items you decide to remove from your cart, click on the remove item next to the item you wish to delete. If you wish to change the quantity of an item, remove the item from your cart and add the item again with the desired quantity. When you are ready to purchase the Dust Collector(s) you have selected, click on the Checkout link. At this point you should see a form showing your cart and a grand total. You will also see some fields for entering your credit card information and a shipping address. You need to fill out all of the fields on the form or the web site will present you with the form again along with an error message explaining the problem.

When all of your customer information has been filled in, click the submit button. After a few seconds you will be presented with your order. It will have an order number on it and the location of where the items will be shipped.

 

At this point you may continue shopping by clicking the Continue shopping link or, if you are finished, you may click the Log out link, whereupon you will be brought back to the Login page.

 

4.0 About the DustCollectors Database

I came to an understanding, through reading the Tomcat documentation, that most servlet containers (at least those that follow the J2EE specification) now provide database connection pooling on behalf of the web applications that run within them. Rather than write my own connection pool class, I decided to try and make use of the connection pooling that Tomcat provides for the Dust Collectors web site. What this amounted to was providing an additional xml file, called context.xml which specifies the data source and driver information to Tomcat within a Resource element. My entry looks like this:

<Resource name="jdbc/DustCollectorsDB"

                 auth="Container"

                 type="javax.sql.DataSource"

                 driverClassName="oracle.jdbc.driver.OracleDriver"

                 url="jdbc:oracle:thin:…etc."

                 username="*****" password="*****" maxActive="4" maxIdle="2"

                 maxWait="-1"/>

 

Then, within the web.xml file, I create a reference to the name of the database resource so that it is available to my application, like  this:

 

            <resource-ref>

                        <description>Resource ref to DustCollectors db factory</description>

                        <res-ref-name>jdbc/DustCollectorsDB</res-ref-name>

                        <res-type>javax.sql.DataSource</res-type>

                        <res-auth>Container</res-auth>

            </resource-ref>

 

Finally, this is what I used in my source code to get a connection from the connection pool.

     

Context initCtx = new InitialContext();

Context envCtx = (Context) initCtx.lookup("java:comp/env");

DataSource ds = (DataSource)envCtx.lookup("jdbc/DustCollectorsDB");

Connection conn = ds.getConnection();

 

The source code above is very similar to the documentation Tomcat provides on how to set up connection pooling. The connection that ds.getConnection() produces is actually a connection that already exists within the pool. Tomcat will loan out the connection until I call conn.close(), at which point the connection is not actually closed, but rather returned to the pool and made available to other objects in the Dust Collectors application. Per the context.xml entry, I configured Tomcat to create a pool to always have two connections available for the application and, if needed, Tomcat can make more connection up to a maximum of 4. My understanding is that the context.xml file is server specific for Tomcat, but the web.xml file and my source code should port to other J2EE compliant servlet containers.

 

The name of the database for Dust Collectors is referred to as, not surprisingly, the DustCollectors database. I created two tables for the database: one called the RegisteredUsers table and one called the Inventory table. The RegisteredUsers table contains the names and passwords of all the users registered with the Dust Collectors web site. The Inventory table contains a list of the products available for sale, including the price, quantity in stock, product code and the name of the file that contains the image of the product.

 

All of the database transactions are handled through a class called DustCollectorsDbManager. Four database interactions are possible through the methods in DustCollectorsDbManager. They are:

 

 

Each method that interacts with the database begins and ends with a pair of calls to private methods which retrieve and return a connection to the connection pool. Those methods are called dbInit and dbClose.

 

5.0 Particulars About the Application

5.1 About Data Validation

For fields filled out by the user, Dust Collectors does attempt to do some data validation. In all cases, the application validates that the fields are not empty and that a quantity entered is in fact an integer. Beyond that, however, Dust Collectors does not validate the length of request data or whether the data is valid (such as a valid zip code or credit card number). It occurred to that, to be user friendly, the servlet would have to produce a wide range of messages for the user, one for each validation check. I could have used Javascript to get around this problem, but I have read that even if Javascript validation is used, the same validation should be performed on the server for security and safety reasons. Again, JSP seems like a better solution.

 

There a few other data validation no-nos that Dust Collectors does that I am well aware of. The two biggest are trimming white space and checking for invalid sql characters in the registration forms. A more robust application would probably check for those things. So please, show a little mercy and don’t register a user with the name Peter O’Toole.

 

5.2 About the Inventory

When I first created the Inventory table for the Dust Collectors application, I really wanted to store the product JPEGs right in the table itself. That way the Dust Collector products could change without changing the application code, since it would just require a database update. Alas, storing images in an Oracle table was more involved than I assumed and I am not that well versed in Oracle at the moment. I had to settle for storing the image file names in the Inventory table and keeping the image files themselves with the application.

 

The inventory itself, once it is retrieved from the database, is stored as an object in session. The first time the user logs on and the products are displayed is the only time that the inventory is retrieved from the database for that session. Every time the user clicks the Continue shopping link from that point on, the inventory is displayed by retrieving it from the session object instead of the database.

 

5.3 Submitting an Order

An order is submitted when a customer fills out the credit card and shipping information and clicks on the Submit button. When that happens, the ProcessOrderSevlet loops through each item in the customer’s shopping cart and decreases the products stock in inventory by the quantity the customer ordered. While the Dust Collectors application does manage the inventory, it does not check a user’s order to see if there is enough of the item in stock. After enough customers, the quantity amounts in inventory will fall below zero. I left this check out for the same reason I left a lot of the edit checks out. It would have required yet another custom message sent back to the user. At some point I felt the project did enough.

 

Of course there was one thing I just couldn’t help fiddling with. When a user submits a form but does not fill in one of the fields, the usual thing is to send him back to the form and inform him that he is missing the required data. I am not sure how web sites do it today, but nowadays you usually get your form back with the fields you did fill in still on the form. By using an user information bean as a parameter to the method that creates the form, I could present the form to the user with the fields already filled in if they were being sent back. In html you can set the initial value for the text fields. For the credit card drop-down lists, however, this approach looked like it was going to be too ugly so the form does not preserve the user’s drop-down selections.

 

Finally, note that the ProcessOrderServlet makes up an order number for each order that is successfully processed. This accomplished by a static class variable called orderCounter, which is basically an integer counter. Because the counter is shared by all threads that are running, the update to the counter is done within a synchronized block.

 

        synchronized(this) {

          orderNumber = ++orderCounter;

        }

 

As long as the Dust Collectors web site stays running, all customers should get a unique order number when they click Submit. However, because the last order number is not saved off to a data store during shutdown, the counter will start over whenever Dust Collectors is re-started.

 

5.4 User Interface Items

For outputting the data stored within a typical session (i.e. inventory data, shopping cart items, customer information) I attempted to bring some sanity to my design by creating an interface called a BeanPresenter. The idea behind a BeanPresenter is to avoid locking the Dust Collectors web site into displaying data in a specific format that is not easy to change. A Dust Collector servlet can create and call upon whichever bean presenter it chooses to display a bean’s data. For example, right now in the application, the inventory data is displayed as an html table. But if that needed to change to a bulleted list, a new class which implements the BeanPresenter interface could be created to present the inventory as a bulleted list. The servlet just needs to call on the new class to change the way the data is displayed. The figure below shows the basic object model of how the beans and presenters interact. This relationship may not be that obvious while studying the Class Relationship Diagrams, since I didn’t provide one big picture with all of the classes on it (it got too complicated). In retrospect, the abstract class called DustCollectorBean would have been better off as an interface called presentable, but the concept remains the same.

 

 

 

The other thing I’d like to mention under User Interface Items is that the standard ‘Submit’ button available for a form is sometimes not the best choice for a web page. Originally, I used the standard ‘Submit’ buttons for the ‘add to cart’ and ‘remove item’ buttons. Not only did they look awkward, but within a table they didn’t seem to respond to the ‘align’ attribute so I could not make them look centered. I decided to create images for my ‘add to cart’ and ‘remove item’ buttons, but this was after some investigating of how other web sites got around doing forms without the ‘Submit’ button.

 

6.0 Conclusion

For my first web application, I had quite a bit of fun doing this project. I have to conclude, however, that the process of creating a web site using servlets left me with quite a few unanswered questions. Most of these questions centered around how best (from a design perspective) to deal with the user interaction that goes on with a typical e-commerce web site. What is the best way to deal with validating input and the myriad of responses back to the user that can come as a result of errors, bad data, out of stock items etc? Is it  good idea, as I did in Dust Collectors, to create a servlet for each web page, as the user progresses through the purchase process? What is a good way to handle a user that selected the ‘back’ button on her browser and then submits her order again? I found a lot of information on writing servlets, but not much information on how to deal with the particular issues found with web programming.

 

I’d also mention that learning how to use Tomcat and making use of the connection pooling was quite rewarding (especially since it worked). The one mistake I made over and over again was that every time I created a new servlet, I always forgot to list it in my web.xml file. This would lead to a ‘servlet not found’ error and that would always fool me into thinking it was a problem with my code. Now when I see that error, I know exactly what the problem is: web.xml!