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 }