Author: gnodet
Date: Wed May 15 15:08:12 2013
New Revision: 1482888
URL: http://svn.apache.org/r1482888
Log:
[ARIES-1070] Provide a correct JDBC wrapping for XA data sources
Added:
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ConnectionManagerFactory.java
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ManagedDataSourceFactory.java
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/Recovery.java
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/XADataSourceMCFFactory.java
Removed:
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ConnectionKey.java
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ConnectionWrapper.java
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/GenericResourceManager.java
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/NLS.java
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/XADatasourceEnlistingWrapper.java
aries/trunk/transaction/transaction-jdbc/src/main/resources/OSGI-INF/blueprint/transaction-jdbc.xml
Modified:
aries/trunk/transaction/transaction-jdbc/pom.xml
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/RecoverableDataSource.java
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/Activator.java
Modified: aries/trunk/transaction/transaction-jdbc/pom.xml
URL:
http://svn.apache.org/viewvc/aries/trunk/transaction/transaction-jdbc/pom.xml?rev=1482888&r1=1482887&r2=1482888&view=diff
==============================================================================
--- aries/trunk/transaction/transaction-jdbc/pom.xml (original)
+++ aries/trunk/transaction/transaction-jdbc/pom.xml Wed May 15 15:08:12 2013
@@ -28,7 +28,7 @@
<groupId>org.apache.aries.transaction</groupId>
<artifactId>org.apache.aries.transaction.jdbc</artifactId>
<name>Apache Aries Transaction Enlisting JDBC Datasource</name>
- <version>1.0.1-SNAPSHOT</version>
+ <version>2.0.0-SNAPSHOT</version>
<packaging>bundle</packaging>
<scm>
@@ -39,14 +39,18 @@
<properties>
<aries.osgi.export.pkg>
- org.apache.aries.transaction.jdbc;-noimport:=true
+ org.apache.aries.transaction.jdbc;-noimport:=true;version="2.0",
+ javax.resource*;version="1.6.0",
</aries.osgi.export.pkg>
<aries.osgi.import>
org.osgi.service.blueprint;resolution:=optional,
+ javax.validation;resolution:=optional,
*
</aries.osgi.import>
<aries.osgi.private.pkg>
- org.apache.aries.transaction.jdbc.internal
+ org.apache.aries.transaction.jdbc.internal,
+ org.apache.geronimo.connector*,
+ org.tranql*,
</aries.osgi.private.pkg>
<aries.osgi.activator>
org.apache.aries.transaction.jdbc.internal.Activator
@@ -54,11 +58,11 @@
</properties>
<dependencies>
- <dependency>
- <groupId>org.apache.aries.transaction</groupId>
- <artifactId>org.apache.aries.transaction.manager</artifactId>
- <version>1.0.0</version>
- </dependency>
+ <dependency>
+ <groupId>org.apache.aries.transaction</groupId>
+ <artifactId>org.apache.aries.transaction.manager</artifactId>
+ <version>1.1.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.aries</groupId>
<artifactId>org.apache.aries.util</artifactId>
@@ -80,6 +84,18 @@
<scope>provided</scope>
</dependency>
<dependency>
+ <groupId>org.tranql</groupId>
+ <artifactId>tranql-connector</artifactId>
+ <version>1.8</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.geronimo.components</groupId>
+ <artifactId>geronimo-connector</artifactId>
+ <version>3.1.1</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
<groupId>org.apache.aries.blueprint</groupId>
<artifactId>org.apache.aries.blueprint.core</artifactId>
<version>1.0.0</version>
@@ -116,7 +132,7 @@
<goal>mapping</goal>
</goals>
<configuration>
-
<namespace>http://aries.apache.org/xmlns/transaction-jdbc/1.0</namespace>
+
<namespace>http://aries.apache.org/xmlns/transaction-jdbc/2.0</namespace>
</configuration>
</execution>
</executions>
Modified:
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/RecoverableDataSource.java
URL:
http://svn.apache.org/viewvc/aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/RecoverableDataSource.java?rev=1482888&r1=1482887&r2=1482888&view=diff
==============================================================================
---
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/RecoverableDataSource.java
(original)
+++
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/RecoverableDataSource.java
Wed May 15 15:08:12 2013
@@ -18,8 +18,18 @@
*/
package org.apache.aries.transaction.jdbc;
-import org.apache.aries.transaction.jdbc.internal.GenericResourceManager;
-import org.apache.aries.transaction.jdbc.internal.XADatasourceEnlistingWrapper;
+import org.apache.aries.transaction.AriesTransactionManager;
+import org.apache.aries.transaction.jdbc.internal.ConnectionManagerFactory;
+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.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.
@@ -30,28 +40,197 @@ import org.apache.aries.transaction.jdbc
*
* @org.apache.xbean.XBean
*/
-public class RecoverableDataSource extends XADatasourceEnlistingWrapper {
+public class RecoverableDataSource implements DataSource {
+ private XADataSource 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 = "xa";
- public String getName() {
- return name;
- }
+ private DataSource delegate;
/**
* The unique name for this managed XAResource. This name will be used
* by the transaction manager to recover transactions.
- *
- * @param name
*/
public void setName(String name) {
this.name = name;
}
/**
+ * The XADataSource to wrap.
+ *
+ * @org.apache.xbean.Property required=true
+ */
+ public void setDataSource(XADataSource 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;
+ }
+
+ /**
+ * 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() {
- new GenericResourceManager(getName(), getTransactionManager(),
getDataSource()).recoverResource();
+ public void start() throws Exception {
+ XADataSourceMCFFactory mcf = new XADataSourceMCFFactory();
+ mcf.setDataSource(dataSource);
+ mcf.setExceptionSorterAsString(exceptionSorter);
+ mcf.setUserName(username);
+ mcf.setPassword(password);
+ mcf.init();
+
+ ConnectionManagerFactory 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.setTransaction(transaction);
+ cm.init();
+
+ delegate = (DataSource)
mcf.getConnectionFactory().createConnectionFactory(cm.getConnectionManager());
+
+ Recovery.recover(name, dataSource, transactionManager);
+ }
+
+ //---------------------------
+ // 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;
+ }
+
}
Modified:
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/Activator.java
URL:
http://svn.apache.org/viewvc/aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/Activator.java?rev=1482888&r1=1482887&r2=1482888&view=diff
==============================================================================
---
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/Activator.java
(original)
+++
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/Activator.java
Wed May 15 15:08:12 2013
@@ -18,14 +18,11 @@
*/
package org.apache.aries.transaction.jdbc.internal;
-import java.util.Hashtable;
-import javax.sql.DataSource;
-import javax.sql.XADataSource;
-import javax.transaction.TransactionManager;
-
+import org.apache.aries.blueprint.NamespaceHandler;
+import org.apache.aries.transaction.AriesTransactionManager;
+import org.apache.xbean.blueprint.context.impl.XBeanNamespaceHandler;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
@@ -33,118 +30,131 @@ import org.osgi.framework.ServiceReferen
import org.osgi.framework.ServiceRegistration;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.transaction.TransactionManager;
+import java.util.Hashtable;
+
+public class Activator implements BundleActivator, ServiceTrackerCustomizer,
ServiceListener {
+
+ private static final Logger LOGGER =
LoggerFactory.getLogger(Activator.class);
+
+ private AriesTransactionManager tm;
+ private ServiceTracker t;
+ private ServiceReference ref;
+ private BundleContext context;
+ private ServiceRegistration nshReg;
+
+ public void start(BundleContext ctx) {
+ context = ctx;
+
+ // Expose blueprint namespace handler if xbean is present
+ try {
+ nshReg = JdbcNamespaceHandler.register(ctx);
+ } catch (NoClassDefFoundError e) {
+ LOGGER.warn("Unable to register JDBC blueprint namespace handler
(xbean-blueprint not available).");
+ } catch (Exception e) {
+ LOGGER.error("Unable to register JDBC blueprint namespace
handler", e);
+ }
+
+ t = new ServiceTracker(ctx, javax.sql.XADataSource.class.getName(),
this);
+
+ try {
+ ctx.addServiceListener(this, "(objectClass=" +
AriesTransactionManager.class.getName() + ")");
+ } catch (InvalidSyntaxException e) {
+ }
+ ref = ctx.getServiceReference(TransactionManager.class.getName());
+ if (ref != null) {
+ tm = (AriesTransactionManager) ctx.getService(ref);
+ }
+
+ if (tm != null) {
+ t.open();
+ }
+ }
+
+ public void stop(BundleContext ctx) {
+ // it is possible these are not cleaned by serviceChanged method when
the
+ // tm service is still active
+ if (t != null) {
+ t.close();
+ }
+ if (ref != null) {
+ context.ungetService(ref);
+ }
+ if (nshReg != null) {
+ nshReg.unregister();
+ }
+ }
+
+ public Object addingService(ServiceReference ref) {
+ try {
+ LOGGER.info("Wrapping XADataSource " + ref);
+ ManagedDataSourceFactory mdsf = new ManagedDataSourceFactory(ref,
tm);
+ return mdsf.register();
+ } catch (Exception e) {
+ LOGGER.warn("Error wrapping XADataSource " + ref, e);
+ return null;
+ }
+ }
+
+ public void modifiedService(ServiceReference ref, Object service) {
+ ServiceRegistration reg = (ServiceRegistration) service;
+
+ Hashtable<String, Object> map = new Hashtable<String, Object>();
+ for (String key : ref.getPropertyKeys()) {
+ map.put(key, ref.getProperty(key));
+ }
+ map.put("aries.xa.aware", "true");
+
+ reg.setProperties(map);
+ }
+
+ public void removedService(ServiceReference ref, Object service) {
+ safeUnregisterService((ServiceRegistration) service);
+ }
+
+ public void serviceChanged(ServiceEvent event) {
+ if (event.getType() == ServiceEvent.REGISTERED && tm == null) {
+ ref = event.getServiceReference();
+ tm = (AriesTransactionManager) context.getService(ref);
+
+ if (tm == null) ref = null;
+ else t.open();
+ } else if (event.getType() == ServiceEvent.UNREGISTERING && tm != null
&&
+
ref.getProperty("service.id").equals(event.getServiceReference().getProperty("service.id")))
{
+ t.close();
+ context.ungetService(ref);
+ ref = null;
+ tm = null;
+ }
+ }
+
+ static void safeUnregisterService(ServiceRegistration reg) {
+ if (reg != null) {
+ try {
+ reg.unregister();
+ } catch (IllegalStateException e) {
+ //This can be safely ignored
+ }
+ }
+ }
+
+ static class JdbcNamespaceHandler {
+
+ public static ServiceRegistration register(BundleContext context)
throws Exception {
+ XBeanNamespaceHandler nsh = new XBeanNamespaceHandler(
+ "http://aries.apache.org/xmlns/transaction-jdbc/2.0",
+ "org.apache.aries.transaction.jdbc.xsd",
+ context.getBundle(),
+
"META-INF/services/org/apache/xbean/spring/http/aries.apache.org/xmlns/transaction-jdbc/2.0"
+ );
+ Hashtable<String, Object> props = new Hashtable<String, Object>();
+ props.put("osgi.service.blueprint.namespace",
"http://aries.apache.org/xmlns/transaction-jdbc/2.0");
+ return context.registerService(NamespaceHandler.class.getName(),
nsh, props);
+ }
-public class Activator implements BundleActivator, ServiceTrackerCustomizer,
ServiceListener
-{
- private TransactionManager tm;
- private ServiceTracker t;
- private ServiceReference ref;
- private BundleContext context;
-
- public void start(BundleContext ctx)
- {
- context = ctx;
-
- t = new ServiceTracker(ctx, javax.sql.XADataSource.class.getName(), this);
-
- try {
- ctx.addServiceListener(this,
"(objectClass=javax.transaction.TransactionManager)");
- } catch (InvalidSyntaxException e) {
- }
- ref = ctx.getServiceReference(TransactionManager.class.getName());
- if (ref != null) {
- tm = (TransactionManager) ctx.getService(ref);
- }
-
- if (tm != null) {
- t.open();
- }
- }
-
- public void stop(BundleContext ctx)
- {
- // it is possible these are not cleaned by serviceChanged method when the
- // tm service is still active
- if (t != null) {
- t.close();
- }
- if (ref != null) {
- context.ungetService(ref);
- }
- }
-
- public Object addingService(ServiceReference ref)
- {
- BundleContext ctx = ref.getBundle().getBundleContext();
-
- Hashtable<String, Object> map = new Hashtable<String, Object>();
- for (String key : ref.getPropertyKeys()) {
- map.put(key, ref.getProperty(key));
- }
- map.put("aries.xa.aware", "true");
-
- // make the ranking for our new better wrappered data source higher so
- // it is the default object looked up using osgi.service.jndi.name.
- Object rankingProp = map.get(Constants.SERVICE_RANKING);
-
- int ranking = 1000;
-
- if (rankingProp != null) ranking = ((Integer)rankingProp) + 1000;
-
- map.put(Constants.SERVICE_RANKING, ranking);
-
- XADatasourceEnlistingWrapper wrapper = new XADatasourceEnlistingWrapper();
- wrapper.setTransactionManager(tm);
- wrapper.setDataSource((XADataSource) ctx.getService(ref));
-
- ServiceRegistration reg = ctx.registerService(DataSource.class.getName(),
wrapper, map);
-
- return reg;
- }
-
- public void modifiedService(ServiceReference ref, Object service)
- {
- ServiceRegistration reg = (ServiceRegistration) service;
-
- Hashtable<String, Object> map = new Hashtable<String, Object>();
- for (String key : ref.getPropertyKeys()) {
- map.put(key, ref.getProperty(key));
- }
- map.put("aries.xa.aware", "true");
-
- reg.setProperties(map);
- }
-
- public void removedService(ServiceReference ref, Object service)
- {
- safeUnregisterService((ServiceRegistration)service);
- }
-
- public void serviceChanged(ServiceEvent event)
- {
- if (event.getType() == ServiceEvent.REGISTERED && tm == null) {
- ref = event.getServiceReference();
- tm = (TransactionManager) context.getService(ref);
-
- if (tm == null) ref = null;
- else t.open();
- } else if (event.getType() == ServiceEvent.UNREGISTERING && tm != null &&
-
ref.getProperty("service.id").equals(event.getServiceReference().getProperty("service.id")))
{
- t.close();
- context.ungetService(ref);
- ref = null;
- tm = null;
- }
- }
-
- static void safeUnregisterService(ServiceRegistration reg)
- {
- if(reg != null) {
- try {
- reg.unregister();
- } catch (IllegalStateException e) {
- //This can be safely ignored
- }
}
- }
+
}
Added:
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ConnectionManagerFactory.java
URL:
http://svn.apache.org/viewvc/aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ConnectionManagerFactory.java?rev=1482888&view=auto
==============================================================================
---
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ConnectionManagerFactory.java
(added)
+++
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ConnectionManagerFactory.java
Wed May 15 15:08:12 2013
@@ -0,0 +1,267 @@
+/*
+ * 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.internal;
+
+import org.apache.aries.transaction.AriesTransactionManager;
+import org.apache.geronimo.connector.outbound.GenericConnectionManager;
+import org.apache.geronimo.connector.outbound.SubjectSource;
+import
org.apache.geronimo.connector.outbound.connectionmanagerconfig.LocalTransactions;
+import org.apache.geronimo.connector.outbound.connectionmanagerconfig.NoPool;
+import
org.apache.geronimo.connector.outbound.connectionmanagerconfig.NoTransactions;
+import
org.apache.geronimo.connector.outbound.connectionmanagerconfig.PartitionedPool;
+import
org.apache.geronimo.connector.outbound.connectionmanagerconfig.PoolingSupport;
+import
org.apache.geronimo.connector.outbound.connectionmanagerconfig.SinglePool;
+import
org.apache.geronimo.connector.outbound.connectionmanagerconfig.TransactionSupport;
+import
org.apache.geronimo.connector.outbound.connectionmanagerconfig.XATransactions;
+import
org.apache.geronimo.connector.outbound.connectiontracking.ConnectionTrackingCoordinator;
+import
org.apache.geronimo.connector.outbound.connectiontracking.GeronimoTransactionListener;
+import org.apache.geronimo.transaction.manager.TransactionManagerMonitor;
+
+import javax.resource.spi.ConnectionManager;
+import javax.resource.spi.ManagedConnectionFactory;
+
+public class ConnectionManagerFactory {
+
+ private AriesTransactionManager transactionManager;
+ private ManagedConnectionFactory managedConnectionFactory;
+
+ private TransactionSupport transactionSupport;
+ private String transaction;
+
+ private PoolingSupport poolingSupport;
+ private boolean pooling = true;
+ private String partitionStrategy; //: none, by-subject,
by-connector-properties
+ private int poolMaxSize = 10;
+ private int poolMinSize = 0;
+ private boolean allConnectionsEqual = true;
+ private int connectionMaxWaitMilliseconds = 5000;
+ private int connectionMaxIdleMinutes = 15;
+
+ private SubjectSource subjectSource;
+
+ private ConnectionTrackingCoordinator connectionTracker;
+ private TransactionManagerMonitor transactionManagerMonitor;
+ private GenericConnectionManager connectionManager;
+
+ public ConnectionManager getConnectionManager() {
+ return connectionManager;
+ }
+
+ public void init() throws Exception {
+ if (transactionManager == null) {
+ throw new IllegalArgumentException("transactionManager must be
set");
+ }
+ if (managedConnectionFactory == null) {
+ throw new IllegalArgumentException("managedConnectionFactory must
be set");
+ }
+ // Apply the default value for property if necessary
+ if (transactionSupport == null) {
+ // No transaction
+ if (transaction == null || "local".equalsIgnoreCase(transaction)) {
+ transactionSupport = LocalTransactions.INSTANCE;
+ } else if ("none".equalsIgnoreCase(transaction)) {
+ transactionSupport = NoTransactions.INSTANCE;
+ } else if ("xa".equalsIgnoreCase(transaction)) {
+ transactionSupport = new XATransactions(true, false);
+ } else {
+ throw new IllegalArgumentException("Unknown transaction type "
+ transaction + " (must be local, none or xa)");
+ }
+ }
+ if (poolingSupport == null) {
+ // No pool
+ if (!pooling) {
+ poolingSupport = new NoPool();
+ } else {
+ if (partitionStrategy == null ||
"none".equalsIgnoreCase(partitionStrategy)) {
+
+ // unpartitioned pool
+ poolingSupport = new SinglePool(poolMaxSize,
+ poolMinSize,
+ connectionMaxWaitMilliseconds,
+ connectionMaxIdleMinutes,
+ allConnectionsEqual,
+ !allConnectionsEqual,
+ false);
+
+ } else if
("by-connector-properties".equalsIgnoreCase(partitionStrategy)) {
+
+ // partition by connector properties such as username and
password on a jdbc connection
+ poolingSupport = new PartitionedPool(poolMaxSize,
+ poolMinSize,
+ connectionMaxWaitMilliseconds,
+ connectionMaxIdleMinutes,
+ allConnectionsEqual,
+ !allConnectionsEqual,
+ false,
+ true,
+ false);
+ } else if ("by-subject".equalsIgnoreCase(partitionStrategy)) {
+
+ // partition by caller subject
+ poolingSupport = new PartitionedPool(poolMaxSize,
+ poolMinSize,
+ connectionMaxWaitMilliseconds,
+ connectionMaxIdleMinutes,
+ allConnectionsEqual,
+ !allConnectionsEqual,
+ false,
+ false,
+ true);
+ } else {
+ throw new IllegalArgumentException("Unknown partition
strategy " + partitionStrategy + " (must be none, by-connector-properties or
by-subject)");
+ }
+ }
+ }
+ if (connectionTracker == null) {
+ connectionTracker = new ConnectionTrackingCoordinator();
+ }
+ if (transactionManagerMonitor == null) {
+ transactionManagerMonitor = new
GeronimoTransactionListener(connectionTracker);
+
transactionManager.addTransactionAssociationListener(transactionManagerMonitor);
+ }
+ if (connectionManager == null) {
+ // Instantiate the Geronimo Connection Manager
+ connectionManager = new GenericConnectionManager(
+ transactionSupport,
+ poolingSupport,
+ subjectSource,
+ connectionTracker,
+ transactionManager,
+ managedConnectionFactory,
+ getClass().getName(),
+ getClass().getClassLoader());
+
+ connectionManager.doStart();
+ }
+ }
+
+ public void destroy() throws Exception {
+ if (connectionManager != null) {
+ connectionManager.doStop();
+ connectionManager = null;
+ }
+ if (transactionManagerMonitor != null && transactionManager != null) {
+
transactionManager.removeTransactionAssociationListener(transactionManagerMonitor);
+ }
+ }
+
+ public AriesTransactionManager getTransactionManager() {
+ return transactionManager;
+ }
+
+ public void setTransactionManager(AriesTransactionManager
transactionManager) {
+ this.transactionManager = transactionManager;
+ }
+
+ public ManagedConnectionFactory getManagedConnectionFactory() {
+ return managedConnectionFactory;
+ }
+
+ public void setManagedConnectionFactory(ManagedConnectionFactory
managedConnectionFactory) {
+ this.managedConnectionFactory = managedConnectionFactory;
+ }
+
+ public TransactionSupport getTransactionSupport() {
+ return transactionSupport;
+ }
+
+ public void setTransactionSupport(TransactionSupport transactionSupport) {
+ this.transactionSupport = transactionSupport;
+ }
+
+ public String getTransaction() {
+ return transaction;
+ }
+
+ public void setTransaction(String transaction) {
+ this.transaction = transaction;
+ }
+
+ public PoolingSupport getPoolingSupport() {
+ return poolingSupport;
+ }
+
+ public void setPoolingSupport(PoolingSupport poolingSupport) {
+ this.poolingSupport = poolingSupport;
+ }
+
+ public boolean isPooling() {
+ return pooling;
+ }
+
+ public void setPooling(boolean pooling) {
+ this.pooling = pooling;
+ }
+
+ public String getPartitionStrategy() {
+ return partitionStrategy;
+ }
+
+ public void setPartitionStrategy(String partitionStrategy) {
+ this.partitionStrategy = partitionStrategy;
+ }
+
+ public int getPoolMaxSize() {
+ return poolMaxSize;
+ }
+
+ public void setPoolMaxSize(int poolMaxSize) {
+ this.poolMaxSize = poolMaxSize;
+ }
+
+ public int getPoolMinSize() {
+ return poolMinSize;
+ }
+
+ public void setPoolMinSize(int poolMinSize) {
+ this.poolMinSize = poolMinSize;
+ }
+
+ public boolean isAllConnectionsEqual() {
+ return allConnectionsEqual;
+ }
+
+ public void setAllConnectionsEqual(boolean allConnectionsEqual) {
+ this.allConnectionsEqual = allConnectionsEqual;
+ }
+
+ public int getConnectionMaxWaitMilliseconds() {
+ return connectionMaxWaitMilliseconds;
+ }
+
+ public void setConnectionMaxWaitMilliseconds(int
connectionMaxWaitMilliseconds) {
+ this.connectionMaxWaitMilliseconds = connectionMaxWaitMilliseconds;
+ }
+
+ public int getConnectionMaxIdleMinutes() {
+ return connectionMaxIdleMinutes;
+ }
+
+ public void setConnectionMaxIdleMinutes(int connectionMaxIdleMinutes) {
+ this.connectionMaxIdleMinutes = connectionMaxIdleMinutes;
+ }
+
+ public SubjectSource getSubjectSource() {
+ return subjectSource;
+ }
+
+ public void setSubjectSource(SubjectSource subjectSource) {
+ this.subjectSource = subjectSource;
+ }
+}
Added:
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ManagedDataSourceFactory.java
URL:
http://svn.apache.org/viewvc/aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ManagedDataSourceFactory.java?rev=1482888&view=auto
==============================================================================
---
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ManagedDataSourceFactory.java
(added)
+++
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ManagedDataSourceFactory.java
Wed May 15 15:08:12 2013
@@ -0,0 +1,126 @@
+/*
+ * 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.internal;
+
+import org.apache.aries.transaction.AriesTransactionManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+import javax.sql.DataSource;
+import javax.sql.XADataSource;
+import java.util.Hashtable;
+import java.util.Map;
+
+public class ManagedDataSourceFactory {
+
+ private final ServiceReference reference;
+ private final AriesTransactionManager transactionManager;
+ private final XADataSource dataSource;
+ private final Map<String, Object> properties;
+
+ public ManagedDataSourceFactory(ServiceReference reference,
+ AriesTransactionManager
transactionManager) {
+ this.reference = reference;
+ this.transactionManager = transactionManager;
+ this.properties = new Hashtable<String, Object>();
+ for (String key : reference.getPropertyKeys()) {
+ this.properties.put(key, reference.getProperty(key));
+ }
+ this.dataSource = (XADataSource)
reference.getBundle().getBundleContext().getService(reference);
+ }
+
+ public AriesTransactionManager getTransactionManager() {
+ return transactionManager;
+ }
+
+ public XADataSource getDataSource() {
+ return dataSource;
+ }
+
+ public String getResourceName() {
+ return getString("aries.xa.name", null);
+ }
+
+ private String getString(String name, String def) {
+ Object v = properties.get(name);
+ if (v instanceof String) {
+ return (String) v;
+ } else {
+ return def;
+ }
+ }
+
+ private int getInt(String name, int def) {
+ Object v = properties.get(name);
+ if (v instanceof Integer) {
+ return (Integer) v;
+ } else if (v instanceof String) {
+ return Integer.parseInt((String) v);
+ } else {
+ return def;
+ }
+ }
+
+ private boolean getBool(String name, boolean def) {
+ Object v = properties.get(name);
+ if (v instanceof Boolean) {
+ return (Boolean) v;
+ } else if (v instanceof String) {
+ return Boolean.parseBoolean((String) v);
+ } else {
+ return def;
+ }
+ }
+
+ public ServiceRegistration register() throws Exception {
+ Hashtable<String, Object> props = new Hashtable<String,
Object>(this.properties);
+ props.put("aries.xa.aware", "true");
+ props.put(Constants.SERVICE_RANKING, getInt(Constants.SERVICE_RANKING,
0) + 1000);
+
+ XADataSourceMCFFactory mcf = new XADataSourceMCFFactory();
+ mcf.setDataSource(dataSource);
+ mcf.setExceptionSorterAsString(getString("aries.xa.exceptionSorter",
"all"));
+ mcf.setUserName(getString("aries.xa.username", null));
+ mcf.setPassword(getString("aries.xa.password", null));
+ mcf.init();
+
+ ConnectionManagerFactory cm = new ConnectionManagerFactory();
+ cm.setManagedConnectionFactory(mcf.getConnectionFactory());
+ cm.setTransactionManager(transactionManager);
+ cm.setAllConnectionsEqual(getBool("aries.xa.allConnectionsEquals",
true));
+
cm.setConnectionMaxIdleMinutes(getInt("aries.xa.connectionMadIdleMinutes", 15));
+
cm.setConnectionMaxWaitMilliseconds(getInt("aries.xa.connectionMaxWaitMilliseconds",
5000));
+ cm.setPartitionStrategy(getString("aries.xa.partitionStrategy", null));
+ cm.setPooling(getBool("aries.xa.pooling", true));
+ cm.setPoolMaxSize(getInt("aries.xa.poolMaxSize", 10));
+ cm.setPoolMinSize(getInt("aries.xa.poolMinSize", 0));
+ cm.setTransaction(getString("aries.xa.transaction", "xa"));
+ cm.init();
+
+ BundleContext context = reference.getBundle().getBundleContext();
+ DataSource ds = (DataSource)
mcf.getConnectionFactory().createConnectionFactory(cm.getConnectionManager());
+ ServiceRegistration registration =
context.registerService(DataSource.class.getName(), ds, props);
+ Recovery.recover(getResourceName(), dataSource, transactionManager);
+ return registration;
+
+ }
+
+}
Added:
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/Recovery.java
URL:
http://svn.apache.org/viewvc/aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/Recovery.java?rev=1482888&view=auto
==============================================================================
---
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/Recovery.java
(added)
+++
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/Recovery.java
Wed May 15 15:08:12 2013
@@ -0,0 +1,94 @@
+/*
+ * 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.internal;
+
+import org.apache.geronimo.transaction.manager.NamedXAResource;
+import org.apache.geronimo.transaction.manager.NamedXAResourceFactory;
+import org.apache.geronimo.transaction.manager.RecoverableTransactionManager;
+import org.apache.geronimo.transaction.manager.WrapperNamedXAResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.sql.XAConnection;
+import javax.sql.XADataSource;
+import javax.transaction.SystemException;
+import javax.transaction.xa.XAResource;
+import java.io.IOException;
+
+/**
+ * This class will ensure the broker is properly recovered when wired with
+ * the Geronimo transaction manager.
+ */
+public class Recovery {
+
+ private static final Logger LOGGER =
LoggerFactory.getLogger(Recovery.class);
+
+ public static boolean recover(final String name,
+ final XADataSource dataSource,
+ final RecoverableTransactionManager
transactionManager) throws IOException {
+
+ if (name != null && name.length() > 0) {
+ transactionManager.registerNamedXAResourceFactory(new
NamedXAResourceFactory() {
+
+ public String getName() {
+ return name;
+ }
+
+ public NamedXAResource getNamedXAResource() throws
SystemException {
+ try {
+ final XAConnection connection =
dataSource.getXAConnection();
+ LOGGER.debug("new namedXAResource's connection: " +
connection);
+
+ return new
ConnectionAndWrapperNamedXAResource(connection.getXAResource(), getName(),
connection);
+ } catch (Exception e) {
+ SystemException se = new SystemException("Failed to
create ConnectionAndWrapperNamedXAResource, " + e.getLocalizedMessage());
+ se.initCause(e);
+ LOGGER.error(se.getLocalizedMessage(), se);
+ throw se;
+ }
+ }
+
+ public void returnNamedXAResource(NamedXAResource
namedXaResource) {
+ if (namedXaResource instanceof
ConnectionAndWrapperNamedXAResource) {
+ try {
+ LOGGER.debug("closing returned namedXAResource's
connection: " +
((ConnectionAndWrapperNamedXAResource)namedXaResource).connection);
+
((ConnectionAndWrapperNamedXAResource)namedXaResource).connection.close();
+ } catch (Exception ignored) {
+ LOGGER.debug("failed to close returned
namedXAResource: " + namedXaResource, ignored);
+ }
+ }
+ }
+ });
+ return true;
+ } else {
+ LOGGER.warn("Unable to recover XADataSource: aries.xa.name
property not set");
+ return false;
+ }
+ }
+
+ public static class ConnectionAndWrapperNamedXAResource extends
WrapperNamedXAResource {
+
+ final XAConnection connection;
+
+ public ConnectionAndWrapperNamedXAResource(XAResource xaResource,
String name, XAConnection connection) {
+ super(xaResource, name);
+ this.connection = connection;
+ }
+ }
+}
Added:
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/XADataSourceMCFFactory.java
URL:
http://svn.apache.org/viewvc/aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/XADataSourceMCFFactory.java?rev=1482888&view=auto
==============================================================================
---
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/XADataSourceMCFFactory.java
(added)
+++
aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/XADataSourceMCFFactory.java
Wed May 15 15:08:12 2013
@@ -0,0 +1,122 @@
+/*
+ * 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.internal;
+
+import org.tranql.connector.AllExceptionsAreFatalSorter;
+import org.tranql.connector.ExceptionSorter;
+import org.tranql.connector.NoExceptionsAreFatalSorter;
+import org.tranql.connector.jdbc.AbstractXADataSourceMCF;
+import org.tranql.connector.jdbc.ConfigurableSQLStateExceptionSorter;
+import org.tranql.connector.jdbc.KnownSQLStateExceptionSorter;
+
+import javax.resource.spi.ManagedConnectionFactory;
+import javax.sql.XADataSource;
+import java.util.ArrayList;
+import java.util.List;
+
+public class XADataSourceMCFFactory {
+
+ private XADataSource dataSource;
+ private ExceptionSorter exceptionSorter = new
AllExceptionsAreFatalSorter();
+ private String userName;
+ private String password;
+
+ private ManagedConnectionFactory connectionFactory;
+
+ public ManagedConnectionFactory getConnectionFactory() {
+ return connectionFactory;
+ }
+
+ public void init() throws Exception {
+ if (dataSource == null) {
+ throw new IllegalArgumentException("dataSource must be set");
+ }
+ if (connectionFactory == null) {
+ connectionFactory = new XADataSourceMCF();
+ }
+ }
+
+ public void setExceptionSorterAsString(String sorter) {
+ if ("all".equalsIgnoreCase(sorter)) {
+ this.exceptionSorter = new AllExceptionsAreFatalSorter();
+ } else if ("none".equalsIgnoreCase(sorter)) {
+ this.exceptionSorter = new NoExceptionsAreFatalSorter();
+ } else if ("known".equalsIgnoreCase(sorter)) {
+ this.exceptionSorter = new KnownSQLStateExceptionSorter();
+ } else if (sorter.toLowerCase().startsWith("custom(") &&
sorter.endsWith(")")) {
+ List<String> states = new ArrayList<String>();
+ for (String s : sorter.substring(7, sorter.length() -
2).split(",")) {
+ if (s != null && s.length() > 0) {
+ states.add(s);
+ }
+ }
+ this.exceptionSorter = new
ConfigurableSQLStateExceptionSorter(states);
+ } else {
+ throw new IllegalArgumentException("Unknown exceptionSorter " +
sorter);
+ }
+ }
+
+ public XADataSource getDataSource() {
+ return dataSource;
+ }
+
+ public void setDataSource(XADataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ public ExceptionSorter getExceptionSorter() {
+ return exceptionSorter;
+ }
+
+ public void setExceptionSorter(ExceptionSorter exceptionSorter) {
+ this.exceptionSorter = exceptionSorter;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public class XADataSourceMCF extends AbstractXADataSourceMCF<XADataSource>
{
+
+ public XADataSourceMCF() {
+ super(XADataSourceMCFFactory.this.dataSource,
XADataSourceMCFFactory.this.exceptionSorter);
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+ }
+
+}