/* * HA-JDBC: High-Availability JDBC * Copyright (C) 2012 Paul Ferraro * * This program 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, either version 3 of the License, or * (at your option) any later version. * * This program 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. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.sf.hajdbc.sql; import java.io.PrintWriter; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.AbstractMap; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Logger; import net.sf.hajdbc.Database; import net.sf.hajdbc.DatabaseBuilder; import net.sf.hajdbc.DatabaseCluster; import net.sf.hajdbc.DatabaseClusterConfigurationBuilderProvider; import net.sf.hajdbc.DatabaseClusterConfigurationFactory; import net.sf.hajdbc.DatabaseClusterFactory; import net.sf.hajdbc.xml.XMLDatabaseClusterConfigurationFactory; /** * @author Paul Ferraro * @param <Z> data source class */ public abstract class CommonDataSource<Z extends javax.sql.CommonDataSource, D extends Database<Z>, B extends DatabaseBuilder<Z, D>, F extends CommonDataSourceProxyFactory<Z, D>> implements javax.sql.CommonDataSource, CommonDataSourceProxyFactoryFactory<Z, D, F>, DatabaseClusterConfigurationBuilderProvider<Z, D, B>, AutoCloseable { private final AtomicReference<Map.Entry<F, Z>> reference = new AtomicReference<>(); private volatile String cluster; private volatile String config; private volatile String user; private volatile String password; private volatile DatabaseClusterFactory<Z, D> factory = new DatabaseClusterFactoryImpl<>(); private volatile DatabaseClusterConfigurationFactory<Z, D> configurationFactory; @Deprecated public void stop() throws SQLException { this.close(); } @Override public void close() throws SQLException { Map.Entry<F, Z> entry = this.reference.getAndSet(null); if (entry != null) { entry.getKey().close(); entry.getKey().getDatabaseCluster().stop(); } } public Z getProxy() throws SQLException { Map.Entry<F, Z> entry = this.reference.get(); if (entry == null) { String id = this.cluster; if (id == null) { throw new SQLException(); } DatabaseClusterConfigurationFactory<Z, D> configurationFactory = this.configurationFactory; DatabaseClusterConfigurationFactory<Z, D> factory = (configurationFactory == null) ? new XMLDatabaseClusterConfigurationFactory<>(id, this.config) : configurationFactory; DatabaseCluster<Z, D> cluster = this.factory.createDatabaseCluster(id, factory, this.getConfigurationBuilder()); cluster.start(); @SuppressWarnings("resource") F proxyFactory = this.createProxyFactory(cluster); entry = new AbstractMap.SimpleImmutableEntry<>(proxyFactory, proxyFactory.createProxy()); if (!this.reference.compareAndSet(null, entry)) { proxyFactory.close(); cluster.stop(); return this.getProxy(); } } return entry.getValue(); } /** * @return the cluster */ public String getCluster() { return this.cluster; } /** * @param cluster the cluster to set */ public void setCluster(String cluster) { this.cluster = cluster; } /** * @return the config */ public String getConfig() { return this.config; } /** * @param config the config to set */ public void setConfig(String config) { this.config = config; } public String getUser() { return this.user; } public void setUser(String user) { this.user = user; } public String getPassword() { return this.password; } public void setPassword(String password) { this.password = password; } public DatabaseClusterConfigurationFactory<Z, D> getConfigurationFactory() { return this.configurationFactory; } public void setConfigurationFactory(DatabaseClusterConfigurationFactory<Z, D> configurationFactory) { this.configurationFactory = configurationFactory; } public DatabaseClusterFactory<Z, D> getFactory() { return this.factory; } public void setFactory(DatabaseClusterFactory<Z, D> clusterFactory) { this.factory = clusterFactory; } /** * @throws SQLFeatureNotSupportedException * @see javax.sql.CommonDataSource#getParentLogger() */ @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { try { return this.getProxy().getParentLogger(); } catch (SQLFeatureNotSupportedException e) { throw e; } catch (SQLException e) { throw new SQLFeatureNotSupportedException(e.getMessage(), e.getSQLState(), e.getErrorCode(), e.getCause()); } } /** * @see javax.sql.CommonDataSource#getLoginTimeout() */ @Override public int getLoginTimeout() throws SQLException { return this.getProxy().getLoginTimeout(); } /** * @see javax.sql.CommonDataSource#getLogWriter() */ @Override public PrintWriter getLogWriter() throws SQLException { return this.getProxy().getLogWriter(); } /** * @see javax.sql.CommonDataSource#setLoginTimeout(int) */ @Override public void setLoginTimeout(int timeout) throws SQLException { this.getProxy().setLoginTimeout(timeout); } /** * @see javax.sql.CommonDataSource#setLogWriter(java.io.PrintWriter) */ @Override public void setLogWriter(PrintWriter writer) throws SQLException { this.getProxy().setLogWriter(writer); } }