org.databene.jdbacl.DBUtil Maven / Gradle / Ivy
Go to download
jdbacl stands for 'Java DataBase ACcess Layer' and provides utilities for accessing JDBC databases from
Java programs, retrieving meta information in an object model and querying database data.
/*
* (c) Copyright 2007-2012 by Volker Bergmann. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted under the terms of the
* GNU General Public License.
*
* For redistributing this software or a derivative work under a license other
* than the GPL-compatible Free Software License as defined by the Free
* Software Foundation or approved by OSI, you must first obtain a commercial
* license to this software product from Volker Bergmann.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS,
* REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE
* HEREBY EXCLUDED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.databene.jdbacl;
import org.databene.commons.ArrayBuilder;
import org.databene.commons.ArrayFormat;
import org.databene.commons.BeanUtil;
import org.databene.commons.ConfigurationError;
import org.databene.commons.ConnectFailedException;
import org.databene.commons.ErrorHandler;
import org.databene.commons.FileUtil;
import org.databene.commons.HeavyweightIterator;
import org.databene.commons.IOUtil;
import org.databene.commons.LogCategories;
import org.databene.commons.ObjectNotFoundException;
import org.databene.commons.ReaderLineIterator;
import org.databene.commons.StringUtil;
import org.databene.commons.SystemInfo;
import org.databene.commons.converter.AnyConverter;
import org.databene.commons.converter.ToStringConverter;
import org.databene.commons.debug.Debug;
import org.databene.commons.depend.DependencyModel;
import org.databene.commons.iterator.ConvertingIterator;
import org.databene.jdbacl.model.DBConstraint;
import org.databene.jdbacl.model.DBPrimaryKeyConstraint;
import org.databene.jdbacl.model.DBTable;
import org.databene.jdbacl.model.DBUniqueConstraint;
import org.databene.jdbacl.model.TableHolder;
import org.databene.jdbacl.proxy.LoggingPreparedStatementHandler;
import org.databene.jdbacl.proxy.LoggingResultSetHandler;
import org.databene.jdbacl.proxy.LoggingStatementHandler;
import org.databene.jdbacl.proxy.PooledConnectionHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Driver;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import javax.sql.PooledConnection;
/**
* Provides database related utility methods.
*
* Created: 06.01.2007 19:27:02
* @author Volker Bergmann
*/
public class DBUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(DBUtil.class);
private static final Logger JDBC_LOGGER = LoggerFactory.getLogger(LogCategories.JDBC);
private static final Logger SQL_LOGGER = LoggerFactory.getLogger(LogCategories.SQL);
/** private constructor for preventing instantiation. */
private DBUtil() {}
// connection handling ---------------------------------------------------------------------------------------------
public static boolean existsEnvironment(String environment) {
try {
getConnectData(environment);
return true;
} catch (Exception e) {
return false;
}
}
public static JDBCConnectData getConnectData(String environment) {
try {
String filename = environment + ".env.properties";
File file = FileUtil.getFileIgnoreCase(new File(filename), false);
if (!file.exists()) {
File defaultUserHomeFile = new File(SystemInfo.getUserHome() + SystemInfo.getFileSeparator() + "databene", filename);
file = FileUtil.getFileIgnoreCase(defaultUserHomeFile, false);
}
String path;
if (file.exists()) {
path = file.getCanonicalPath();
} else if (IOUtil.isURIAvailable(filename)) {
path = filename;
} else {
throw new ConfigurationError("No environment definition '" + filename + "' found");
}
return JDBCConnectData.parseSingleDbProperties(path);
} catch (IOException e) {
throw new ConfigurationError("Error reading environment data for '" + environment + "'");
}
}
public static Connection connect(String environment, boolean readOnly) throws ConnectFailedException {
JDBCConnectData connectData = DBUtil.getConnectData(environment);
return connect(connectData, readOnly);
}
public static Connection connect(JDBCConnectData data, boolean readOnly) throws ConnectFailedException {
if (StringUtil.isEmpty(data.url))
throw new ConfigurationError("No JDBC URL specified");
if (StringUtil.isEmpty(data.driver))
throw new ConfigurationError("No JDBC driver class name specified");
return connect(data.url, data.driver, data.user, data.password, readOnly);
}
public static Connection connect(String url, String driverClassName, String user, String password, boolean readOnly) throws ConnectFailedException {
try {
if (driverClassName == null)
throw new ConfigurationError("No JDBC driver class name provided");
// Instantiate driver
Class driverClass = BeanUtil.forName(driverClassName);
Driver driver = driverClass.newInstance();
// Wrap connection properties
java.util.Properties info = new java.util.Properties();
if (user != null)
info.put("user", user);
if (password != null)
info.put("password", password);
// connect
JDBC_LOGGER.debug("opening connection to " + url);
Connection connection = driver.connect(url, info);
if (connection == null)
throw new ConnectFailedException("Connecting the database failed silently - " +
"probably due to wrong driver (" + driverClassName + ") or wrong URL format (" + url + ")");
connection = wrapWithPooledConnection(connection, readOnly);
return connection;
} catch (Exception e) {
throw new ConnectFailedException("Connecting " + url + " failed: ", e);
}
}
public static boolean available(String url, String driverClass, String user, String password) {
try {
Connection connection = connect(url, driverClass, user, password, false);
close(connection);
return true;
} catch (Exception e) {
return false;
}
}
/** Closes a database connection silently */
public static void close(Connection connection) {
if (connection == null)
return;
try {
connection.close();
} catch (SQLException e) {
LOGGER.error("Error closing connection", e);
}
}
public static Connection wrapWithPooledConnection(Connection connection, boolean readOnly) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
return (Connection) Proxy.newProxyInstance(classLoader,
new Class[] { Connection.class, PooledConnection.class },
new PooledConnectionHandler(connection, readOnly));
}
public static int getOpenConnectionCount() {
return PooledConnectionHandler.getOpenConnectionCount();
}
public static void resetMonitors() {
LoggingPreparedStatementHandler.resetMonitors();
LoggingResultSetHandler.resetMonitors();
LoggingStatementHandler.resetMonitors();
PooledConnectionHandler.resetMonitors();
}
// statement handling ----------------------------------------------------------------------------------------------
public static Statement createLoggingStatementHandler(Statement statement, boolean readOnly) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
statement = (Statement) Proxy.newProxyInstance(classLoader,
new Class[] { Statement.class },
new LoggingStatementHandler(statement, readOnly));
return statement;
}
public static PreparedStatement prepareStatement(Connection connection, String sql, boolean readOnly) throws SQLException {
return prepareStatement(connection, sql, readOnly,
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
}
public static PreparedStatement prepareStatement(
Connection connection,
String sql,
boolean readOnly,
int resultSetType,
int resultSetConcurrency,
int resultSetHoldability) throws SQLException {
JDBC_LOGGER.debug("preparing statement: " + sql);
checkReadOnly(sql, readOnly);
if (connection instanceof PooledConnection)
connection = ((PooledConnection) connection).getConnection();
PreparedStatement statement = connection.prepareStatement(
sql, resultSetType, resultSetConcurrency, resultSetHoldability);
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (SQL_LOGGER.isDebugEnabled() || JDBC_LOGGER.isDebugEnabled())
statement = (PreparedStatement) Proxy.newProxyInstance(classLoader,
new Class[] { PreparedStatement.class },
new LoggingPreparedStatementHandler(statement, sql));
return statement;
}
public static void close(Statement statement) {
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
throw new ConfigurationError("Closing statement failed", e);
}
}
}
public static int getOpenStatementCount() {
return LoggingStatementHandler.getOpenStatementCount();
}
public static int getOpenPreparedStatementCount() {
return LoggingPreparedStatementHandler.getOpenStatementCount();
}
// ResultSet handling ----------------------------------------------------------------------------------------------
public static ResultSet createLoggingResultSet(ResultSet realResultSet, Statement statement) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
return (ResultSet) Proxy.newProxyInstance(classLoader,
new Class[] { ResultSet.class },
new LoggingResultSetHandler(realResultSet, statement));
}
public static Statement getStatement(ResultSet resultSet) {
try {
return resultSet.getStatement();
} catch (SQLException e) {
throw new RuntimeException("Error getting statement from result set", e);
}
}
public static void close(ResultSet resultSet) {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
throw new ConfigurationError("Closing statement failed", e);
}
}
}
public static void closeResultSetAndStatement(ResultSet resultSet) {
if (resultSet != null)
closeResultSetAndStatement(resultSet, getStatement(resultSet));
}
public static void closeResultSetAndStatement(ResultSet resultSet, Statement statement) {
if (resultSet != null) {
try {
close(resultSet);
} finally {
close(statement);
}
} else
close(statement);
}
public static int getOpenResultSetCount() {
return LoggingResultSetHandler.getOpenResultSetCount();
}
public static Object parseAndSimplifyResultSet(ResultSet resultSet) throws SQLException {
List