View Javadoc

1   /************************************************************************
2    * Copyright (c) 2000-2006 The Apache Software Foundation.             *
3    * All rights reserved.                                                *
4    * ------------------------------------------------------------------- *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you *
6    * may not use this file except in compliance with the License. You    *
7    * may obtain a copy of the License at:                                *
8    *                                                                     *
9    *     http://www.apache.org/licenses/LICENSE-2.0                      *
10   *                                                                     *
11   * Unless required by applicable law or agreed to in writing, software *
12   * distributed under the License is distributed on an "AS IS" BASIS,   *
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or     *
14   * implied.  See the License for the specific language governing       *
15   * permissions and limitations under the License.                      *
16   ***********************************************************************/
17  
18  package org.apache.james.util;
19  
20  import java.sql.Connection;
21  import java.sql.DatabaseMetaData;
22  import java.sql.ResultSet;
23  import java.sql.SQLException;
24  import java.sql.Statement;
25  import java.util.Locale;
26  
27  /***
28   * <p>Helper class for managing common JDBC tasks.</p>
29   *
30   * <p>This class is abstract to allow implementations to 
31   * take advantage of different logging capabilities/interfaces in
32   * different parts of the code.</p>
33   *
34   * @version CVS $Revision: 365582 $ $Date: 2006-01-03 08:51:21 +0000 (mar, 03 gen 2006) $
35   */
36  abstract public class JDBCUtil
37  {
38      /***
39       * An abstract method which child classes override to handle logging of
40       * errors in their particular environments.
41       *
42       * @param errorString the error message generated
43       */
44      abstract protected void delegatedLog(String errorString);
45  
46      /***
47       * Checks database metadata to see if a table exists.
48       * Try UPPER, lower, and MixedCase, to see if the table is there.
49       *
50       * @param dbMetaData the database metadata to be used to look up this table
51       * @param tableName the table name
52       *
53       * @throws SQLException if an exception is encountered while accessing the database
54       */
55      public boolean tableExists(DatabaseMetaData dbMetaData, String tableName)
56          throws SQLException {
57          return ( tableExistsCaseSensitive(dbMetaData, tableName) ||
58                   tableExistsCaseSensitive(dbMetaData, tableName.toUpperCase(Locale.US)) ||
59                   tableExistsCaseSensitive(dbMetaData, tableName.toLowerCase(Locale.US)) );
60      }
61  
62      /***
63       * Checks database metadata to see if a table exists.  This method
64       * is sensitive to the case of the provided table name.
65       *
66       * @param dbMetaData the database metadata to be used to look up this table
67       * @param tableName the case sensitive table name
68       *
69       * @throws SQLException if an exception is encountered while accessing the database
70       */
71      public boolean tableExistsCaseSensitive(DatabaseMetaData dbMetaData, String tableName)
72          throws SQLException {
73          ResultSet rsTables = dbMetaData.getTables(null, null, tableName, null);
74          try {
75              boolean found = rsTables.next();
76              return found;
77          } finally {
78              closeJDBCResultSet(rsTables);
79          }
80      }
81  
82      /***
83       * Checks database metadata to see if a column exists in a table
84       * Try UPPER, lower, and MixedCase, both on the table name and the column name, to see if the column is there.
85       *
86       * @param dbMetaData the database metadata to be used to look up this column
87       * @param tableName the table name
88       * @param columnName the column name
89       *
90       * @throws SQLException if an exception is encountered while accessing the database
91       */
92      public boolean columnExists(DatabaseMetaData dbMetaData, String tableName, String columnName)
93          throws SQLException {
94          return ( columnExistsCaseSensitive(dbMetaData, tableName, columnName) ||
95                   columnExistsCaseSensitive(dbMetaData, tableName, columnName.toUpperCase(Locale.US)) ||
96                   columnExistsCaseSensitive(dbMetaData, tableName, columnName.toLowerCase(Locale.US)) ||
97                   columnExistsCaseSensitive(dbMetaData, tableName.toUpperCase(Locale.US), columnName) ||
98                   columnExistsCaseSensitive(dbMetaData, tableName.toUpperCase(Locale.US), columnName.toUpperCase(Locale.US)) ||
99                   columnExistsCaseSensitive(dbMetaData, tableName.toUpperCase(Locale.US), columnName.toLowerCase(Locale.US)) ||
100                  columnExistsCaseSensitive(dbMetaData, tableName.toLowerCase(Locale.US), columnName) ||
101                  columnExistsCaseSensitive(dbMetaData, tableName.toLowerCase(Locale.US), columnName.toUpperCase(Locale.US)) ||
102                  columnExistsCaseSensitive(dbMetaData, tableName.toLowerCase(Locale.US), columnName.toLowerCase(Locale.US)) );
103     }
104 
105     /***
106      * Checks database metadata to see if a column exists in a table.  This method
107      * is sensitive to the case of both the provided table name and column name.
108      *
109      * @param dbMetaData the database metadata to be used to look up this column
110      * @param tableName the case sensitive table name
111      * @param columnName the case sensitive column name
112      *
113      * @throws SQLException if an exception is encountered while accessing the database
114      */
115     public boolean columnExistsCaseSensitive(DatabaseMetaData dbMetaData, String tableName, String columnName)
116         throws SQLException {
117         ResultSet rsTables = dbMetaData.getColumns(null, null, tableName, columnName);
118         try {
119             boolean found = rsTables.next();
120             return found;
121         } finally {
122             closeJDBCResultSet(rsTables);
123         }
124     }
125 
126     /***
127      * Closes database connection and logs if an error
128      * is encountered
129      *
130      * @param conn the connection to be closed
131      */
132     public void closeJDBCConnection(Connection conn) {
133         try {
134             if (conn != null) {
135                 conn.close();
136             }
137         } catch (SQLException sqle) {
138             // Log exception and continue
139             subclassLogWrapper("Unexpected exception while closing database connection.");
140         }
141     }
142 
143     /***
144      * Closes database statement and logs if an error
145      * is encountered
146      *
147      * @param stmt the statement to be closed
148      */
149     public void closeJDBCStatement(Statement stmt) {
150         try {
151             if (stmt != null) {
152                 stmt.close();
153             }
154         } catch (SQLException sqle) {
155             // Log exception and continue
156             subclassLogWrapper("Unexpected exception while closing database statement.");
157         }
158     }
159 
160     /***
161      * Closes database result set and logs if an error
162      * is encountered
163      *
164      * @param aResultSet the result set to be closed
165      */
166     public void closeJDBCResultSet(ResultSet aResultSet ) {
167         try {
168             if (aResultSet != null) {
169                 aResultSet.close();
170             }
171         } catch (SQLException sqle) {
172             // Log exception and continue
173             subclassLogWrapper("Unexpected exception while closing database result set.");
174         }
175     }
176 
177     /***
178      * Wraps the delegated call to the subclass logging method with a Throwable
179      * wrapper.  All throwables generated by the subclass logging method are
180      * caught and ignored.
181      *
182      * @param logString the raw string to be passed to the logging method implemented
183      *                  by the subclass
184      */
185     private void subclassLogWrapper(String logString)
186     {
187         try {
188             delegatedLog(logString);
189         }
190         catch(Throwable t) {
191             // Throwables generated by the logging system are ignored
192         }
193     }
194 
195 }