home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 November / PCONLINE_11_99.ISO / filesbbs / OS2 / APCHSSL2.ZIP / OS2HTTPD / servlets / DataAccessServlet.java < prev    next >
Encoding:
Java Source  |  1999-08-10  |  19.8 KB  |  531 lines

  1. /*
  2.  * @(#)DataAccessServlet.java  1.0.0 97/09/15
  3.  *
  4.  * Copyright (c) 1997 Sheldon Bradley Wosnick. All Rights Reserved.
  5.  * AUTHOR EMAIL: swosnick@ca.ibm.com
  6.  *
  7.  * DISCLAIMER OF WARRANTIES:
  8.  * The following [enclosed] code is sample code created by Sheldon Bradley
  9.  * Wosnick. This sample code is not part of any standard product
  10.  * and is provided to you solely for the purpose of assisting you in the
  11.  * development of your applications.  The code is provided "AS IS",
  12.  * without warranty of any kind.  Sheldon Bradley Wosnick shall not be
  13.  * liable for any damages arising out of your use of the sample code, even
  14.  * if he has been advised of the possibility of such damages.
  15.  *
  16.  * You may study, use, modify, and distribute this example for any purpose.
  17.  *
  18.  * CopyrightVersion 1.0.0
  19.  */
  20.  
  21. import java.net.URL;
  22. import java.util.*;
  23. import java.sql.*;
  24. import java.io.*;
  25. import javax.servlet.*;
  26. import javax.servlet.http.*;
  27.  
  28. /**
  29.  * This is a demonstration Java servlet which provides a wide range of
  30.  * database access -- SQL query and update -- support via pure JDBC,
  31.  * server-side, to illustrate how to begin construction of a multi-tier
  32.  * (n-tier) distributed architecture that is possible using servlets to
  33.  * communicate with backend (legacy) databases. It shows one of the many
  34.  * potential areas for exploiting servlets, namely to keep the database
  35.  * access on the backend with a better solution than CGI and hide all the
  36.  * programming logic from the client. It is meant to whet the immagination
  37.  * and to spur on further development in this area of server-side Java.
  38.  *
  39.  * <p>A feature of this servlet is that if the servlet throws an SQLException,
  40.  * information about that exception is HTTP-streamed to the browser for
  41.  * debugging purposes so the user can get meaningful feedback on the SQL-JDBC
  42.  * methods that are being executed improperly. For Java exceptions other than
  43.  * SQLException a Java console is required to accept calls to standard err.
  44.  *
  45.  * <p>All JDBC drivers are supported including the JDBC-ODBC Bridge which ships
  46.  * with the JavaSoft JDK (1.1x). The client HTML form has been constructed to
  47.  * allow for ODBC and DB2, but as new PURE JDBC drivers become available by
  48.  * various database vendors, this page (or one functionally like it) can be
  49.  * revised to include those new drivers.
  50.  *
  51.  * <p>PREREQUISITES:<UL>
  52.  *
  53.  * <LI>A working to advanced understanding of SQL query creation.
  54.  *
  55.  * <LI>Either the Servlet Runner which ships with the JavaSoft Java Servlet
  56.  *     Development Kit (JSDK) or a Web server that supports servlets.
  57.  *
  58.  * <LI>An understanding of how to deploy and callup a servlet.
  59.  * </UL>
  60.  *
  61.  * @version  1.0.0 05/15/97
  62.  * @author Sheldon Bradley Wosnick
  63.  */
  64.  
  65. public class DataAccessServlet extends HttpServlet {
  66.  
  67.     /**
  68.      * The user ID.
  69.      */
  70.     private String m_strUID = "";
  71.  
  72.     /**
  73.      * The password.
  74.      */
  75.     private String m_strPWD = "";
  76.  
  77.     /**
  78.      * The URL with protocol and datasource name.
  79.      */
  80.     private String m_strURL = "";
  81.  
  82.     /**
  83.      * The JDBC Driver.
  84.      */
  85.     private String m_strDriver = "";
  86.  
  87.     /**
  88.      * The SQL string to use for query or update.
  89.      */
  90.     private String m_strSQLString = "";
  91.  
  92.     /**
  93.      * The action type, either 'query' or 'update'.
  94.      */
  95.     private String m_strActionType = "";
  96.  
  97.     /**
  98.      * The database name.
  99.      */
  100.     private String m_strDatabase = "";
  101.  
  102.     /**
  103.      * The table name.
  104.      */
  105.     private String m_strTableName = "";
  106.  
  107.     /**
  108.      * Properties to contain password and user ID.
  109.      */
  110.     private Properties m_properties = null;
  111.  
  112.     /**
  113.      * The database connection.
  114.      */
  115.     private Connection m_connection = null;
  116.  
  117.     /**
  118.      * Result set for a given query.
  119.      */
  120.     private ResultSet m_resultSet = null;
  121.  
  122.     /**
  123.      * The Statement used for SQL query or update.
  124.      */
  125.     private Statement m_statement = null;
  126.  
  127.     /**
  128.      * The output stream used for HTTP output to create dynamic HTML page.
  129.      */
  130.     private ServletOutputStream m_outstream = null;
  131.  
  132. /**
  133.  * Checks for and displays SQL warnings. Returns true if a warning existed.
  134.  * @param anSQLwarning SQLWarning
  135.  * @return boolean indicating existence of an SQL warning.
  136.  * @exception SQLException
  137.  */
  138. private static boolean checkForWarning(SQLWarning anSQLwarning)
  139.     throws SQLException {
  140.  
  141.     boolean bReturnValue = false;
  142.  
  143.     if (anSQLwarning != null) {
  144.         System.err.println("\n *** SQL Warning ***\n");
  145.         bReturnValue = true;
  146.         while (anSQLwarning != null) {
  147.             System.err.println("SQLState: " +
  148.                 anSQLwarning.getSQLState());
  149.             System.err.println("Message:  " +
  150.                 anSQLwarning.getMessage());
  151.             System.err.println("Vendor:   " +
  152.                 anSQLwarning.getErrorCode());
  153.             System.err.println("");
  154.             anSQLwarning = anSQLwarning.getNextWarning();
  155.         }
  156.     }
  157.     return bReturnValue;
  158. }
  159. /**
  160.  * Perform the physical connection to the database.
  161.  * @param aURL String, aDriver String, aProperties Properties, aResponse ServletResponse
  162.  */
  163. private void connectToDatabase(String aURL, String aDriver, Properties aProperties, ServletResponse aResponse) {
  164.  
  165.     try {
  166.         trace("Trying the JDBC driver.");
  167.         Class.forName(aDriver);
  168.  
  169.         // The following line will enable driver logging for debugging.
  170.         // It is not required, and may be commented out if desired.
  171.         // Note: this will impact performance!
  172.         //trace("Setting the Log Stream.");
  173.         //DriverManager.setLogStream(System.out);
  174.  
  175.         trace("Getting a database connection.");
  176. //        m_connection = DriverManager.getConnection(aURL, aProperties);
  177.         m_connection = DriverManager.getConnection(aURL, aProperties.get("UID").toString(),
  178.                                                          aProperties.get("PWD").toString());
  179.         trace("Checking for connection warnings.");
  180.         checkForWarning(m_connection.getWarnings());
  181.         trace("Connected to database.");
  182.     }
  183.     catch(SQLException anSQLException) {
  184.         trace("An SQL Exception was thrown:\n" + anSQLException);
  185.         processSQLException(anSQLException, aResponse);
  186.     }
  187.     catch (Exception anException) {
  188.         // some other kind of exception occurred so dump the call stack
  189.         anException.printStackTrace();
  190.     }
  191. }
  192. /**
  193.  * Destroys the servlet upon server shutdown.
  194.  */
  195. public void destroy() {
  196.     trace("Destroying the servlet.");
  197.     try {
  198.         m_connection.commit();
  199.         m_resultSet.close();
  200.         m_resultSet = null;
  201.         m_statement.close();
  202.         m_statement = null;
  203.         m_connection.close();
  204.         m_connection = null;
  205.     }
  206.     catch(SQLException anSQLException) {
  207.  
  208.         System.err.println("\n*** SQLException caught ***\n");
  209.  
  210.         while (anSQLException != null) {
  211.             System.err.println("SQLState: " +
  212.                 anSQLException.getSQLState());
  213.             System.err.println("Message:  " + anSQLException.getMessage());
  214.             System.err.println("Vendor:   " + anSQLException.getErrorCode());
  215.             anSQLException = anSQLException.getNextException();
  216.             System.err.println("");
  217.         }
  218.     }
  219. }
  220. /**
  221.  * Executes a user-defined SQL query on a table.
  222.  * @param anSQLQuery String, aResponse ServletResponse
  223.  */
  224. private void executeTheQuery(String anSQLQuery, ServletResponse aResponse) {
  225.  
  226.     try {
  227.         trace("Executing a query.");
  228.         m_statement = m_connection.createStatement();
  229.         m_resultSet = m_statement.executeQuery(anSQLQuery);
  230.     }
  231.     catch (SQLException anSQLException) {
  232.         trace("An SQL Exception was thrown:\n" + anSQLException);
  233.         processSQLException(anSQLException, aResponse);
  234.     }
  235. }
  236. /**
  237.  * Executes a User-defined SQL update command on a table.
  238.  * @param anUpdateCommand String, aResponse ServletResponse
  239.  */
  240. private void executeTheUpdate(String anUpdateCommand, ServletResponse aResponse) {
  241.  
  242.     try {
  243.         trace("Executing an update.");
  244.         m_statement = m_connection.createStatement();
  245.         m_statement.executeUpdate(anUpdateCommand);
  246.     }
  247.     catch (SQLException anSQLException) {
  248.         trace("An SQL Exception was thrown:\n" + anSQLException);
  249.         processSQLException(anSQLException, aResponse);
  250.     }
  251. }
  252. /**
  253.  * Returns information about this servlet.
  254.  * @return String about the servlet.
  255.  */
  256. public String getServletInfo() {
  257.     return "a data access servlet by Sheldon Bradley Wosnick which demonstrates server-side JDBC programming with servlets";
  258. }
  259. /**
  260.  * One-time initialization of the servlet where expensive, resource-intensive
  261.  * activities should take place, such as file and network IO, and setting up
  262.  * connection to a database. Hence, the database connection could made here,
  263.  * but is made in service() for simplicity of this sample.
  264.  * @param servletConfig ServletConfig
  265.  */
  266. public void init(ServletConfig servletConfig) {
  267.  
  268.     trace("Calling overridden init() method now.");
  269.  
  270.     try{
  271.         super.init(servletConfig);
  272.     }
  273.     catch (ServletException aServletException) {
  274.         System.err.println("ServletException: " + aServletException.getMessage());
  275.     }
  276. }
  277. /**
  278.  * Prepares http output to create new html page with results of query
  279.  * after a user-entered SQL query or update command.
  280.  * @param aResponse HttpServletResponse, anActionDescription String
  281.  * @exeception SQLException
  282.  */
  283. private void outResultSet(ServletResponse aResponse, String anActionDescription)
  284.     throws SQLException {
  285.  
  286.     try {
  287.         trace("Getting an output stream for the HTML response page.");
  288.         m_outstream = aResponse.getOutputStream();
  289.         aResponse.setContentType("text/html");
  290.         m_outstream.println("<html>");
  291.         m_outstream.println("<head><title>A Data Access Servlet using Pure JDBC</title></head>");
  292. //        m_outstream.println("<body BGCOLOR=#000000 TEXT=#C0C0C0>");
  293. //        m_outstream.println("<BASEFONT FACE=\"Verdana, Arial, Helvetica\">");
  294. //        m_outstream.println("<FONT FACE=\"Arial, Helvetica\" SIZE=2>");
  295.  
  296.             try {
  297.                 trace("Preparing some connection information.");
  298.                 ResultSetMetaData resultSetMetaData = m_resultSet.getMetaData();
  299.                 DatabaseMetaData databaseMetaData = m_connection.getMetaData();
  300.  
  301.                 int iNumCols = resultSetMetaData.getColumnCount();
  302.  
  303.                 // extra connection information provided debugging purposes
  304.                 m_outstream.println("JDBC DATABASE CONNECTION DETAILS:");
  305.                 m_outstream.println("<BR>");
  306.  
  307.                 m_outstream.println("<BR>Current date and time: " + new java.util.Date().toString());
  308.  
  309.                 m_outstream.println("<BR>Connection URL: " + databaseMetaData.getURL());
  310.  
  311.                 m_outstream.println("<BR>Driver: " +
  312.                     databaseMetaData.getDriverName());
  313.  
  314.                 m_outstream.println("<BR>Version: " +
  315.                     databaseMetaData.getDriverVersion());
  316.  
  317.                 m_outstream.println("<BR>User Name: " +
  318.                     databaseMetaData.getUserName());
  319.  
  320.                 m_outstream.println("<BR>Driver Major Version: " +
  321.                     databaseMetaData.getDriverMajorVersion());
  322.  
  323.                 m_outstream.println("<BR>Driver Minor Version: " +
  324.                     databaseMetaData.getDriverMinorVersion());
  325.  
  326.                 m_outstream.println("<BR>Database Product Name: " +
  327.                     databaseMetaData.getDatabaseProductName());
  328.  
  329.                 m_outstream.println("<BR>Database Product Version: " +
  330.                     databaseMetaData.getDatabaseProductVersion());
  331.  
  332.                 m_outstream.println("<BR>SQL query or update command processed by servlet: " + m_strSQLString);
  333.                 m_outstream.println("<BR><BR>");
  334.  
  335.                 trace("Preparing an HTML table.");
  336.                 m_outstream.println("<TABLE>");
  337.                 m_outstream.println("<TABLE BORDER=1>");
  338.  
  339.                 String strCaption = "TABLE: " + m_strTableName +  " ***** ACTION TAKEN: " + anActionDescription;
  340.  
  341.                 m_outstream.println("<CAPTION>" + strCaption + "</CAPTION>");
  342.  
  343.                 int i;
  344.                 // create column names
  345.                 trace("Creating the column names");
  346.  
  347.                 for (i = 1; i <= iNumCols; i++) {
  348.                     m_outstream.println("<TH>" + resultSetMetaData.getColumnLabel(i));
  349.                 }
  350.  
  351.                 boolean more = m_resultSet.next();
  352.  
  353.                 // fill cells in table with values extracted from result set
  354.                 trace("Filling in the table elements.");
  355.                 while (more) {
  356.                     m_outstream.println("<TR>");
  357.                     for (i = 1; i <= iNumCols; i++) {
  358.                                  if (m_strTableName.toUpperCase().equals("TESTTT")&& (i == 1 || i == 3)) {
  359.                                      m_outstream.println("<TD>" + new String(m_resultSet.getBytes(i),"ibm819"));
  360.             } else {
  361.                                      m_outstream.println("<TD>" + m_resultSet.getString(i));
  362.             }
  363.                     }
  364.                     more = m_resultSet.next();
  365.                 }
  366.  
  367.                 m_outstream.println("</FONT>");
  368.                 m_outstream.println("</TABLE>");
  369.  
  370.                 trace("Finished preparing the HTML table.");
  371.             }
  372.             catch (SQLException anSQLException) {
  373.                 trace("An SQL Exception was thrown:\n" + anSQLException);
  374.                 processSQLException(anSQLException, aResponse);
  375.             }
  376.  
  377.             m_outstream.println("</body></html>");
  378.             trace("Finished with the output stream.");
  379.             m_outstream.flush();
  380.             m_outstream.close();
  381.             trace("Flushed and closed the output stream.");
  382.     }
  383.     catch(IOException anIOException) {
  384.         System.err.println ("\n*** IOException caught ***\n");
  385.         System.err.println("IOException: " + anIOException.toString());
  386.     }
  387. }
  388. /**
  389.  * Process the SQL exception by extracting relevant information from it.
  390.  * Display to the browser.
  391.  * @param anSQLException SQLException, aResponse ServletResponse
  392.  */
  393. private void processSQLException(SQLException anSQLException, ServletResponse aResponse) {
  394.  
  395.     try {
  396.         trace("Processing an SQL Exception");
  397.         m_outstream = aResponse.getOutputStream();
  398.         aResponse.setContentType("text/html");
  399.         m_outstream.println("<html>");
  400.         m_outstream.println("<head><title>Servlet threw an SQLException</title></head>");
  401.         m_outstream.println("<body BGCOLOR=#000000 TEXT=#C0C0C0>");
  402.  
  403.         m_outstream.println("<P>*** An SQLException was caught ***</P>");
  404.         //while (true) {;//(anSQLException != null) {
  405.         while(anSQLException != null) {
  406.             m_outstream.println("<P>" + "SQLState: " +
  407.                 anSQLException.getSQLState() + "</P>");
  408.             m_outstream.println("<P>Message:  " + anSQLException.getMessage() + "</P>");
  409.             m_outstream.println("<P>Vendor:   " + anSQLException.getErrorCode() + "</P>");
  410.             anSQLException = anSQLException.getNextException();
  411.             m_outstream.flush();
  412.             m_outstream.close();
  413.         }
  414.     }
  415.     catch(IOException anIOException) {
  416.         System.err.println ("\n*** IOException caught ***\n");
  417.         System.err.println("IOException: " + anIOException.toString());
  418.     }
  419. }
  420. /**
  421.  * Required method for a servlet, overridden to perform specialized JDBC work.
  422.  * @param aRequest ServletRequest, aResponse ServletResponse
  423.  * @exception ServletException, IOException
  424.  */
  425. public void service(ServletRequest aRequest, ServletResponse aResponse)
  426.     throws ServletException, IOException {
  427.  
  428.     trace("Calling the service() method now.");
  429.  
  430.     m_properties = new Properties();
  431.     
  432.     trace("Getting request parameters.");
  433.     m_strUID = aRequest.getParameter("UID");
  434.     m_strPWD = aRequest.getParameter("password");
  435.     m_strDriver = aRequest.getParameter("driver");
  436.     m_strTableName = aRequest.getParameter("table");
  437. //    m_strSQLString = new String(aRequest.getParameter("SQL").getBytes(),"ibm819");
  438.     m_strSQLString = aRequest.getParameter("SQL");
  439.     m_strDatabase = aRequest.getParameter("database");
  440.     if (m_strDriver.substring(0,16).equals("org.gjt.mm.mysql") ||
  441.         m_strDriver.substring(0,22).equals("com.imaginary.sql.msql") ||
  442.         m_strDriver.substring(0,20).equals("COM.ibm.db2.jdbc.net")) {
  443.         m_strURL = "jdbc:"+ aRequest.getParameter("URL") + "/" + m_strDatabase;
  444.     } else {
  445.         m_strURL = "jdbc:"+ aRequest.getParameter("URL") + ":" + m_strDatabase;
  446.     }
  447.     m_strActionType = aRequest.getParameter("action");
  448.     m_properties.put("UID", m_strUID);
  449.     m_properties.put("PWD", m_strPWD);
  450.  
  451.     trace("User ID: " + m_strUID);
  452.     trace("Driver: " + m_strDriver);
  453.     trace("URL: " + m_strURL);
  454.     trace("Table Name = " + m_strTableName);
  455.     trace("SQL String = " + m_strSQLString);
  456.     trace("Action Type = " + m_strActionType);
  457.  
  458.      // only attempt a connection if not already successfully connected for
  459.     // this particular client
  460.     if(m_connection == null)
  461.         connectToDatabase(m_strURL, m_strDriver, m_properties, aResponse);
  462.  
  463.     // Decide if the user intends to query the database or to actually update,
  464.     // which translates eventually into the difference between executeQuery() and
  465.     // executeUpdate()
  466.     if (m_strActionType.equals("query")) {
  467.  
  468.         executeTheQuery(m_strSQLString, aResponse);
  469.         try {
  470.             outResultSet(aResponse, "User-defined Query");
  471.         }
  472.         catch (SQLException anSQLException) {
  473.             trace("An SQL Exception was thrown.");
  474.             processSQLException(anSQLException, aResponse);
  475.         }
  476.     }
  477.     else if (m_strActionType.equals("update")) {
  478.         // if it is an update requested, create a result table both before and after just
  479.         // to illustrate that the updates were committed.
  480.         try {
  481.             // requery the current table
  482.             trace("Querying the database for table " + m_strTableName + " before any updates.");
  483.             m_statement = m_connection.createStatement();
  484.             m_resultSet = m_statement.executeQuery("select * from " + m_strTableName);
  485.             outResultSet(aResponse, "Query Before the Update");
  486.         }
  487.         catch (SQLException anSQLException) {
  488.             trace("An SQL Exception was thrown:\n" + anSQLException);
  489.             processSQLException(anSQLException, aResponse);
  490.         }
  491.  
  492.         executeTheUpdate(m_strSQLString, aResponse);
  493.  
  494.         try {
  495.             // requery the current table
  496.             trace("Requerying the database for table " + m_strTableName + " after any updates.");
  497.             m_statement = m_connection.createStatement();
  498.             m_resultSet = m_statement.executeQuery("select * from " + m_strTableName);
  499.             outResultSet(aResponse, "Query after the Update");
  500.         }
  501.         catch (SQLException anSQLException) {
  502.             trace("An SQL Exception was thrown:\n" + anSQLException);
  503.             processSQLException(anSQLException, aResponse);
  504.         }
  505.     }
  506.     else
  507.         System.err.println("ERROR >> For processing purposes, you must explicitly pass 'update' or 'query'");
  508.  
  509.     // close connections and free resources
  510.     try {
  511.         m_connection.commit();
  512.         m_resultSet.close();
  513.         m_resultSet = null;
  514.         m_statement.close();
  515.         m_statement = null;
  516.         m_connection.close();
  517.         m_connection = null;
  518.     }
  519.     catch(SQLException anSQLException) {
  520.         trace("An SQL Exception was thrown:\n" + anSQLException);
  521.         processSQLException(anSQLException, aResponse);
  522.     }
  523. }
  524. /**
  525.  * This method is used to output trace messages to standard output.
  526.  * @param anTraceMessage String
  527.  */
  528. public void trace(String aTraceMessage) {
  529.     System.out.println("DEBUG TRACE:  " + aTraceMessage);
  530. }
  531. }