aries-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gno...@apache.org
Subject svn commit: r1482888 - in /aries/trunk/transaction/transaction-jdbc: ./ src/main/java/org/apache/aries/transaction/jdbc/ src/main/java/org/apache/aries/transaction/jdbc/internal/ src/main/resources/OSGI-INF/blueprint/
Date Wed, 15 May 2013 15:08:13 GMT
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;
+        }
+    }
+
+}



Mime
View raw message