/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2009-2012, Open Source Geospatial Foundation (OSGeo)
* (C) 2009-2012, Geomatys
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotoolkit.internal.sql;
import java.util.Set;
import java.util.HashSet;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.LogRecord;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.DatabaseMetaData;
import javax.sql.DataSource;
import org.geotoolkit.resources.Loggings;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.logging.Logging;
import org.apache.sis.util.Classes;
/**
* A data source which get the connection from a {@link DriverManager}.
*
* @author Martin Desruisseaux (Geomatys)
* @author Guilhem Legal (Geomatys)
* @version 3.18
*
* @since 3.00
* @module
*/
public class DefaultDataSource implements DataSource {
/**
* The logger where to report the JDBC driver version. Note that the logger
* name intentionally hides the {@code "internal"} part of the package name.
*/
public static final Logger LOGGER = Logging.getLogger("org.geotoolkit.sql");
/**
* The driver names of the connection returned by {@code DefaultDataSource}.
* This is used for logging purpose only.
*/
private static final Set<String> DRIVERS = new HashSet<>();
/**
* The URL to use for connecting to the database.
* This field can not be {@code null}.
*/
public final String url;
/**
* Creates a data source for the given URL.
*
* @param url The URL to use for connecting to the database.
*/
public DefaultDataSource(final String url) {
ArgumentChecks.ensureNonNull("url", url);
this.url = url;
}
/**
* Logs the driver version if this is the first time we get a connection for that driver.
*/
static Connection log(final Connection connection, final Class<?> source) throws SQLException {
if (LOGGER.isLoggable(Level.CONFIG)) {
final DatabaseMetaData metadata = connection.getMetaData();
final String name = metadata.getDriverName();
final boolean log;
synchronized (DRIVERS) {
log = DRIVERS.add(name);
}
if (log) {
final LogRecord record = Loggings.format(Level.CONFIG, Loggings.Keys.JdbcDriverVersion_3,
name, metadata.getDriverMajorVersion(), metadata.getDriverMinorVersion());
record.setLoggerName(LOGGER.getName());
record.setSourceClassName(source.getName());
record.setSourceMethodName("getConnection");
LOGGER.log(record);
}
}
return connection;
}
/**
* Delegates to {@link DriverManager}.
*
* @throws SQLException If the connection can not be established.
*/
@Override
public Connection getConnection() throws SQLException {
return log(DriverManager.getConnection(url), DefaultDataSource.class);
}
/**
* Delegates to {@link DriverManager}.
*
* @throws SQLException If the connection can not be established.
*/
@Override
public Connection getConnection(String username, String password) throws SQLException {
return log(DriverManager.getConnection(url, username, password), DefaultDataSource.class);
}
/**
* Delegates to {@link DriverManager}.
*/
@Override
public PrintWriter getLogWriter() {
return DriverManager.getLogWriter();
}
/**
* Delegates to {@link DriverManager}. It is better to avoid
* calling this method since it has a system-wide effect.
*/
@Override
public void setLogWriter(final PrintWriter out) {
DriverManager.setLogWriter(out);
}
/**
* Delegates to {@link DriverManager}.
*/
@Override
public int getLoginTimeout() {
return DriverManager.getLoginTimeout();
}
/**
* Delegates to {@link DriverManager}. It is better to avoid
* calling this method since it has a system-wide effect.
*/
@Override
public void setLoginTimeout(final int seconds) {
DriverManager.setLoginTimeout(seconds);
}
/**
* Returns (@code false} in all cases, since this class is not a wrapper
* (omitting {@code DriverManager}).
*/
@Override
public boolean isWrapperFor(Class<?> iface) {
return false;
}
/**
* Throws an exception in all cases, since this class is not a wrapper
* (omitting {@code DriverManager}).
*
* @param <T> Ignored.
*/
@Override
public <T> T unwrap(final Class<T> iface) throws SQLException {
throw new SQLException();
}
/**
* Shutdown the database represented by this data source.
*
* @since 3.03
*/
public void shutdown() {
final Dialect dialect = Dialect.forURL(url);
if (dialect != null) try {
dialect.shutdown(null, url, false);
} catch (SQLException e) {
Logging.unexpectedException(LOGGER, DefaultDataSource.class, "shutdown", e);
}
}
/**
* Compares this data source with the given object for equality.
*
* @param other The object to compare with this data source.
* @return {@code true} if both objects are equal.
*
* @since 3.18
*/
@Override
public boolean equals(final Object other) {
if (other == this) {
return true;
}
if (other != null && other.getClass() == getClass()) {
final DefaultDataSource that = (DefaultDataSource) other;
return Objects.equals(this.url, that.url);
}
return false;
}
/**
* Returns a hash code value for this data source.
*
* @return A hash code value for this data source.
*
* @since 3.18
*/
@Override
public int hashCode() {
return url.hashCode() ^ 335483867;
}
/**
* Returns a string representation of this data source.
*/
@Override
public String toString() {
return Classes.getShortClassName(this) + "[\"" + url + "\"]";
}
/**
* Returns the parent logger for this data source.
*
* @return the parent Logger for this data source
*/
@Override
public Logger getParentLogger() {
return LOGGER;
}
}