Listing 16.2 shows a complete example using JDBC and JTA from a servlet deployed on the WebLogic Platform. The BookStoreServlet provides the user interface for a Web-based application to search for and order books. This example focuses on using JDBC with JTA. Refer to Chapter 19 "Servlets and JavaServer Pages ”Best Practices" for more information on servlets. The init() method in the BookStoreServlet connects to the WebLogic JNDI naming service. The JNDI connection is used to lookup the DataSource for the relational database. The service() method is invoked when the HTML form that is handled by this servlet is submitted. The first step in the service() method is to lookup the JTA UserTransaction in the WebLogic naming service. All further processing is performed within a transaction which is either committed, if all completes successfully, or rolled back, if an error occurs. The following actions are performed within the transaction:
The BookStoreServlet checks the inventory for the number of available copies of the book and the customer's balance to verify that the balance is greater than the price of the book. If the book is out of stock or the customer's balance is less than the price of the book, throw an exception which will roll back the transaction. These checks are performed in queryBook() and queryCustomer() respectively. This example was created using Together ControlCenter version 6.0. The class diagram was created using the Class By Pattern tool and choosing the Servlet pattern. For the pattern properties, we chose Implement Method init() and Implement Method service(). Together they generate the class diagram and template source code. The remainder of the application was manually edited within the Java source code. Figure 16.4. The class diagram of the BookStore servlet shows the attributes and methods for the class.
Listing 16.2 Template Source Code for the BookStore Servlet Generated by Together ControlCenter 6.0/* Generated by Together */ import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import javax.naming.Context; import javax.naming.InitialContext; import javax.sql.DataSource; import java.sql.Connection; import java.sql.Statement; import javax.transaction.UserTransaction; public class BookStoreServlet extends HttpServlet { // constants private static final String DATASOURCE_NAME = "datasource-demopool"; private void parseForm( HttpServletRequest req ) { Enumeration fields = req.getParameterNames(); while( fields.hasMoreElements() ) { String field = (String)fields.nextElement(); if( field.equals( "name" ) ) name = req.getParameter( field ); else if( field.equals( "title" ) ) title = req.getParameter( field ); } } public void init(ServletConfig config)throws ServletException{ super.init(config); // //Write your code here // name = null; title = null; try { // create a connection to the WebLogic JNDI Naming Service ctx = new InitialContext(); // locate a DataSource in the Naming Service ds = (DataSource)m_ctx.lookup( DATASOURCE_NAME ); } catch( Exception x ) { System.err.println( "Error in init(): " + x ); } } public String getServletInfo(){ return "Servlet description"; } public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // //Write your code here // Connection con = null; UserTransaction tx = null; try { PrintWriter out = res.getWriter(); // print the HTML header out.println( "<html>" ); out.println( "<head><title>Book Store Servlet</title></head>" ); out.println( "<body>" ); out.println( "<h1>Book Store Servlet</h1>" ); // locate a UserTransaction in the Naming service tx = (UserTransaction)ctx.lookup( "javax.transaction.UserTransaction" ); // start a transaction tx.start(); // get a JDBC Connection from the DataSource con = ds.getConnection(); // create a Statement Statement st = con.createStatement(); // get customer name and book name from the HTML form parseForm( req ); // search database for requested data queryBook( con ); queryCustomer( con ); // update the database con.setAutoCommit( false ); // disable auto-commit st.executeUpdate( "UPDATE books SET copies = " + ( copies - 1 ) + " WHERE title = " + title ); st.close(); st = con.createStatement(); st.executeUpdate( "UPDATE customers SET balance = " + ( balance - price ) + " WHERE customer_name = " + name ); st.close(); st = con.createStatement(); st.executeUpdate( "INSERT INTO ShoppingCart VALUES ( " + customerID + ", " + bookID + " )" ); st.close(); // commit the transaction tx.commit(); out.println( "<h2>Success</h2>" ); out.println( "</body>" ); out.println( "</html>" ); } catch(Exception x ) { System.err.println( "Rolled back transaction: " + x.toString() ); tx.rollback(); } } private void queryCustomer( Connection con, float price ) throws SQLException, Exception { Statement st = con.createStatement(); ResultSet rs = st.executeQuery( "Select * from customers WHERE customer_name = " + name ); rs.next(); customerID = rs.getInt( "customer_id" ); balance = rs.getFloat( "balance" ); // verify balance is greater than price of book if( balance < price ) { throw new Exception( name + " has insufficient funcds" ); } } private void queryBook( Connection con ) throws SQLException, Exception { Statement st = con.createStatement(); ResultSet rs = st.executeQuery( "Select * from books WHERE title = " + title ); rs.next(); bookID = rs.getInt( "book_id" ); price = rs.getFloat( "price" ); copies = rs.getInt( "copies" ); // verify there is at least 1 copy of the book if( copies == 0 ) { throw new Exception( title + " is out of stock" ); } } private Context ctx; private DataSource ds; private String name; private int customerID; private float balance; private String title; private int bookID; private int copies; private float price; } |