View Javadoc

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