| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.aries.transaction.jdbc; |
| |
| import org.apache.aries.transaction.AriesTransactionManager; |
| import org.apache.aries.transaction.jdbc.internal.AbstractMCFFactory; |
| import org.apache.aries.transaction.jdbc.internal.ConnectionManagerFactory; |
| import org.apache.aries.transaction.jdbc.internal.DataSourceMCFFactory; |
| import org.apache.aries.transaction.jdbc.internal.Recovery; |
| import org.apache.aries.transaction.jdbc.internal.XADataSourceMCFFactory; |
| import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement; |
| |
| import javax.sql.CommonDataSource; |
| import javax.sql.DataSource; |
| import javax.sql.XADataSource; |
| import java.io.PrintWriter; |
| import java.sql.Connection; |
| import java.sql.SQLException; |
| import java.sql.SQLFeatureNotSupportedException; |
| |
| /** |
| * Defines a JDBC DataSource that will auto-enlist into existing XA transactions. |
| * The DataSource will also be registered with the Aries/Geronimo transaction |
| * manager in order to provide proper transaction recovery at startup. |
| * Other considerations such as connection pooling and error handling are |
| * completely ignored. |
| * |
| * @org.apache.xbean.XBean |
| */ |
| public class RecoverableDataSource implements DataSource, RecoverableDataSourceMBean { |
| |
| private CommonDataSource dataSource; |
| private AriesTransactionManager transactionManager; |
| private String name; |
| private String exceptionSorter = "all"; |
| private String username = ""; |
| private String password = ""; |
| private boolean allConnectionsEquals = true; |
| private int connectionMaxIdleMinutes = 15; |
| private int connectionMaxWaitMilliseconds = 5000; |
| private String partitionStrategy = "none"; |
| private boolean pooling = true; |
| private int poolMaxSize = 10; |
| private int poolMinSize = 0; |
| private String transaction; |
| private boolean validateOnMatch = true; |
| private boolean backgroundValidation = false; |
| private int backgroundValidationMilliseconds = 600000; |
| |
| private ConnectionManagerFactory cm; |
| private DataSource delegate; |
| |
| /** |
| * The unique name for this managed XAResource. This name will be used |
| * by the transaction manager to recover transactions. |
| */ |
| public void setName(String name) { |
| this.name = name; |
| } |
| |
| /** |
| * The CommonDataSource to wrap. |
| * |
| * @org.apache.xbean.Property required=true |
| */ |
| public void setDataSource(CommonDataSource dataSource) { |
| this.dataSource = dataSource; |
| } |
| |
| /** |
| * The XA TransactionManager to use to enlist the JDBC connections into. |
| * |
| * @org.apache.xbean.Property required=true |
| */ |
| public void setTransactionManager(AriesTransactionManager transactionManager) { |
| this.transactionManager = transactionManager; |
| } |
| |
| /** |
| * Specify which SQL exceptions are fatal. |
| * Can be all, none, known or custom(xx,yy...). |
| */ |
| public void setExceptionSorter(String exceptionSorter) { |
| this.exceptionSorter = exceptionSorter; |
| } |
| |
| /** |
| * The user name used to establish the connection. |
| */ |
| public void setUsername(String username) { |
| this.username = username; |
| } |
| |
| /** |
| * The password credential used to establish the connection. |
| */ |
| public void setPassword(String password) { |
| this.password = password; |
| } |
| |
| public void setAllConnectionsEquals(boolean allConnectionsEquals) { |
| this.allConnectionsEquals = allConnectionsEquals; |
| } |
| |
| public void setConnectionMaxIdleMinutes(int connectionMaxIdleMinutes) { |
| this.connectionMaxIdleMinutes = connectionMaxIdleMinutes; |
| } |
| |
| public void setConnectionMaxWaitMilliseconds(int connectionMaxWaitMilliseconds) { |
| this.connectionMaxWaitMilliseconds = connectionMaxWaitMilliseconds; |
| } |
| |
| /** |
| * Pool partition strategy. |
| * Can be none, by-connector-properties or by-subject (defaults to none). |
| */ |
| public void setPartitionStrategy(String partitionStrategy) { |
| this.partitionStrategy = partitionStrategy; |
| } |
| |
| /** |
| * If pooling is enabled (defaults to true). |
| * @param pooling |
| */ |
| public void setPooling(boolean pooling) { |
| this.pooling = pooling; |
| } |
| |
| /** |
| * Maximum pool size (defaults to 10). |
| */ |
| public void setPoolMaxSize(int poolMaxSize) { |
| this.poolMaxSize = poolMaxSize; |
| } |
| |
| /** |
| * Minimum pool size (defaults to 0). |
| */ |
| public void setPoolMinSize(int poolMinSize) { |
| this.poolMinSize = poolMinSize; |
| } |
| |
| /** |
| * If validation on connection matching is enabled (defaults to true). |
| * @param validateOnMatch |
| */ |
| public void setValidateOnMatch(boolean validateOnMatch) { |
| this.validateOnMatch = validateOnMatch; |
| } |
| |
| /** |
| * If periodically background validation is enabled (defaults to false). |
| * @param backgroundValidation |
| */ |
| public void setBackgroundValidation(boolean backgroundValidation) { |
| this.backgroundValidation = backgroundValidation; |
| } |
| |
| /** |
| * Background validation period (defaults to 600000) |
| * @param backgroundValidationMilliseconds |
| */ |
| public void setBackgroundValidationMilliseconds(int backgroundValidationMilliseconds) { |
| this.backgroundValidationMilliseconds = backgroundValidationMilliseconds; |
| } |
| |
| /** |
| * Transaction support. |
| * Can be none, local or xa (defaults to xa). |
| */ |
| public void setTransaction(String transaction) { |
| this.transaction = transaction; |
| } |
| |
| /** |
| * @org.apache.xbean.InitMethod |
| */ |
| public void start() throws Exception { |
| AbstractMCFFactory mcf; |
| if (("xa".equals(transaction) || "local".equals(transaction)) && transactionManager == null) { |
| throw new IllegalArgumentException("xa or local transactions specified, but no TransactionManager set"); |
| } |
| if ("xa".equals(transaction) && !(dataSource instanceof XADataSource)) { |
| throw new IllegalArgumentException("xa transactions specified, but DataSource does not implement javax.sql.XADataSource"); |
| } |
| if ("xa".equals(transaction) || (transactionManager != null && dataSource instanceof XADataSource)) { |
| mcf = new XADataSourceMCFFactory(); |
| if (transaction == null) { |
| transaction = "xa"; |
| } |
| } else if (dataSource instanceof DataSource) { |
| mcf = new DataSourceMCFFactory(); |
| if (transaction == null) { |
| transaction = transactionManager != null ? "local" : "none"; |
| } |
| } else { |
| throw new IllegalArgumentException("dataSource must be of type javax.sql.DataSource/XADataSource"); |
| } |
| mcf.setDataSource(dataSource); |
| mcf.setExceptionSorterAsString(exceptionSorter); |
| mcf.setUserName(username); |
| mcf.setPassword(password); |
| mcf.init(); |
| |
| cm = new ConnectionManagerFactory(); |
| cm.setManagedConnectionFactory(mcf.getConnectionFactory()); |
| cm.setTransactionManager(transactionManager); |
| cm.setAllConnectionsEqual(allConnectionsEquals); |
| cm.setConnectionMaxIdleMinutes(connectionMaxIdleMinutes); |
| cm.setConnectionMaxWaitMilliseconds(connectionMaxWaitMilliseconds); |
| cm.setPartitionStrategy(partitionStrategy); |
| cm.setPooling(pooling); |
| cm.setPoolMaxSize(poolMaxSize); |
| cm.setPoolMinSize(poolMinSize); |
| cm.setValidateOnMatch(validateOnMatch); |
| cm.setBackgroundValidation(backgroundValidation); |
| cm.setBackgroundValidationMilliseconds(backgroundValidationMilliseconds); |
| cm.setTransaction(transaction); |
| cm.setName(name); |
| cm.init(); |
| |
| delegate = (DataSource) cm.getManagedConnectionFactory().createConnectionFactory(cm.getConnectionManager()); |
| |
| if (dataSource instanceof XADataSource) { |
| Recovery.recover(name, (XADataSource) dataSource, transactionManager); |
| } |
| } |
| |
| /** |
| * @org.apache.xbean.DestroyMethod |
| */ |
| public void stop() throws Exception { |
| if (cm != null) { |
| cm.destroy(); |
| } |
| } |
| |
| //--------------------------- |
| // MBean implementation |
| //--------------------------- |
| |
| public String getName() { |
| return name; |
| } |
| |
| public String getExceptionSorter() { |
| return exceptionSorter; |
| } |
| |
| public String getUsername() { |
| return username; |
| } |
| |
| public String getPassword() { |
| return password; |
| } |
| |
| public boolean isAllConnectionsEquals() { |
| return allConnectionsEquals; |
| } |
| |
| public int getConnectionMaxIdleMinutes() { |
| return connectionMaxIdleMinutes; |
| } |
| |
| public int getConnectionMaxWaitMilliseconds() { |
| return connectionMaxWaitMilliseconds; |
| } |
| |
| public String getPartitionStrategy() { |
| return partitionStrategy; |
| } |
| |
| public boolean isPooling() { |
| return pooling; |
| } |
| |
| public int getPoolMaxSize() { |
| return poolMaxSize; |
| } |
| |
| public int getPoolMinSize() { |
| return poolMinSize; |
| } |
| |
| public boolean isValidateOnMatch() { |
| return validateOnMatch; |
| } |
| |
| public boolean isBackgroundValidation() { |
| return backgroundValidation; |
| } |
| |
| public int getBackgroundValidationMilliseconds() { |
| return backgroundValidationMilliseconds; |
| } |
| |
| public String getTransaction() { |
| return transaction; |
| } |
| |
| public int getConnectionCount() { |
| return cm.getPoolingSupport().getConnectionCount(); |
| } |
| |
| public int getIdleConnectionCount() { |
| return cm.getPoolingSupport().getIdleConnectionCount(); |
| } |
| |
| //--------------------------- |
| // DataSource implementation |
| //--------------------------- |
| |
| public Connection getConnection() throws SQLException { |
| return delegate.getConnection(); |
| } |
| |
| public Connection getConnection(String username, String password) throws SQLException { |
| return delegate.getConnection(username, password); |
| } |
| |
| public PrintWriter getLogWriter() throws SQLException { |
| return delegate.getLogWriter(); |
| } |
| |
| /** |
| * @org.apache.xbean.Property hidden=true |
| */ |
| public void setLogWriter(PrintWriter out) throws SQLException { |
| delegate.setLogWriter(out); |
| } |
| |
| /** |
| * @org.apache.xbean.Property hidden=true |
| */ |
| public void setLoginTimeout(int seconds) throws SQLException { |
| delegate.setLoginTimeout(seconds); |
| } |
| |
| public int getLoginTimeout() throws SQLException { |
| return delegate.getLoginTimeout(); |
| } |
| |
| @IgnoreJRERequirement |
| public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { |
| throw new SQLFeatureNotSupportedException(); |
| } |
| |
| public <T> T unwrap(Class<T> iface) throws SQLException { |
| return null; |
| } |
| |
| public boolean isWrapperFor(Class<?> iface) throws SQLException { |
| return false; |
| } |
| |
| } |