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.ai.classic;
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>
31   * Helper class for managing common JDBC tasks.
32   * </p>
33   * 
34   * <p>
35   * This class is abstract to allow implementations to take advantage of
36   * different logging capabilities/interfaces in different parts of the code.
37   * </p>
38   */
39  abstract class JDBCUtil {
40      /**
41       * An abstract method which child classes override to handle logging of
42       * errors in their particular environments.
43       * 
44       * @param errorString
45       *            the error message generated
46       */
47      abstract protected void delegatedLog(String errorString);
48  
49      /**
50       * Checks database metadata to see if a table exists. Try UPPER, lower, and
51       * MixedCase, to see if the table is there.
52       * 
53       * @param dbMetaData
54       *            the database metadata to be used to look up this table
55       * @param tableName
56       *            the table name
57       * 
58       * @throws SQLException
59       *             if an exception is encountered while accessing the database
60       */
61      public boolean tableExists(DatabaseMetaData dbMetaData, String tableName) throws SQLException {
62          return (tableExistsCaseSensitive(dbMetaData, tableName) || tableExistsCaseSensitive(dbMetaData, tableName.toUpperCase(Locale.US)) || tableExistsCaseSensitive(dbMetaData, tableName.toLowerCase(Locale.US)));
63      }
64  
65      /**
66       * Checks database metadata to see if a table exists. This method is
67       * sensitive to the case of the provided table name.
68       * 
69       * @param dbMetaData
70       *            the database metadata to be used to look up this table
71       * @param tableName
72       *            the case sensitive table name
73       * 
74       * @throws SQLException
75       *             if an exception is encountered while accessing the database
76       */
77      public boolean tableExistsCaseSensitive(DatabaseMetaData dbMetaData, String tableName) throws SQLException {
78          ResultSet rsTables = dbMetaData.getTables(null, null, tableName, null);
79          try {
80              boolean found = rsTables.next();
81              return found;
82          } finally {
83              closeJDBCResultSet(rsTables);
84          }
85      }
86  
87      /**
88       * Checks database metadata to see if a column exists in a table. Try UPPER,
89       * lower, and MixedCase, both on the table name and the column name, to see
90       * if the column is there.
91       * 
92       * @param dbMetaData
93       *            the database metadata to be used to look up this column
94       * @param tableName
95       *            the table name
96       * @param columnName
97       *            the column name
98       * 
99       * @throws SQLException
100      *             if an exception is encountered while accessing the database
101      */
102     public boolean columnExists(DatabaseMetaData dbMetaData, String tableName, String columnName) throws SQLException {
103         return (columnExistsCaseSensitive(dbMetaData, tableName, columnName) || columnExistsCaseSensitive(dbMetaData, tableName, columnName.toUpperCase(Locale.US)) || columnExistsCaseSensitive(dbMetaData, tableName, columnName.toLowerCase(Locale.US))
104                 || columnExistsCaseSensitive(dbMetaData, tableName.toUpperCase(Locale.US), columnName) || columnExistsCaseSensitive(dbMetaData, tableName.toUpperCase(Locale.US), columnName.toUpperCase(Locale.US))
105                 || columnExistsCaseSensitive(dbMetaData, tableName.toUpperCase(Locale.US), columnName.toLowerCase(Locale.US)) || columnExistsCaseSensitive(dbMetaData, tableName.toLowerCase(Locale.US), columnName)
106                 || columnExistsCaseSensitive(dbMetaData, tableName.toLowerCase(Locale.US), columnName.toUpperCase(Locale.US)) || columnExistsCaseSensitive(dbMetaData, tableName.toLowerCase(Locale.US), columnName.toLowerCase(Locale.US)));
107     }
108 
109     /**
110      * Checks database metadata to see if a column exists in a table. This
111      * method is sensitive to the case of both the provided table name and
112      * column name.
113      * 
114      * @param dbMetaData
115      *            the database metadata to be used to look up this column
116      * @param tableName
117      *            the case sensitive table name
118      * @param columnName
119      *            the case sensitive column name
120      * 
121      * @throws SQLException
122      *             if an exception is encountered while accessing the database
123      */
124     public boolean columnExistsCaseSensitive(DatabaseMetaData dbMetaData, String tableName, String columnName) throws SQLException {
125         ResultSet rsTables = dbMetaData.getColumns(null, null, tableName, columnName);
126         try {
127             boolean found = rsTables.next();
128             return found;
129         } finally {
130             closeJDBCResultSet(rsTables);
131         }
132     }
133 
134     /**
135      * Closes database connection and logs if an error is encountered
136      * 
137      * @param conn
138      *            the connection to be closed
139      */
140     public void closeJDBCConnection(Connection conn) {
141         try {
142             if (conn != null) {
143                 conn.close();
144             }
145         } catch (SQLException sqle) {
146             // Log exception and continue
147             subclassLogWrapper("Unexpected exception while closing database connection.");
148         }
149     }
150 
151     /**
152      * Closes database statement and logs if an error is encountered
153      * 
154      * @param stmt
155      *            the statement to be closed
156      */
157     public void closeJDBCStatement(Statement stmt) {
158         try {
159             if (stmt != null) {
160                 stmt.close();
161             }
162         } catch (SQLException sqle) {
163             // Log exception and continue
164             subclassLogWrapper("Unexpected exception while closing database statement.");
165         }
166     }
167 
168     /**
169      * Closes database result set and logs if an error is encountered
170      * 
171      * @param aResultSet
172      *            the result set to be closed
173      */
174     public void closeJDBCResultSet(ResultSet aResultSet) {
175         try {
176             if (aResultSet != null) {
177                 aResultSet.close();
178             }
179         } catch (SQLException sqle) {
180             // Log exception and continue
181             subclassLogWrapper("Unexpected exception while closing database result set.");
182         }
183     }
184 
185     /**
186      * Wraps the delegated call to the subclass logging method with a Throwable
187      * wrapper. All throwables generated by the subclass logging method are
188      * caught and ignored.
189      * 
190      * @param logString
191      *            the raw string to be passed to the logging method implemented
192      *            by the subclass
193      */
194     private void subclassLogWrapper(String logString) {
195         try {
196             delegatedLog(logString);
197         } catch (Throwable t) {
198             // Throwables generated by the logging system are ignored
199         }
200     }
201 
202 }