Author: timothyjward
Date: Fri Jul 22 16:53:02 2016
New Revision: 1753813

URL: http://svn.apache.org/viewvc?rev=1753813&view=rev
Log:
[ARIES-1585] Add tests for JDBC connection cleanup, and fix the leaks!

Added:
    
aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ConnectionLifecycleTest.java
    
aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/AbstractJDBCConnectionProvider.java
      - copied, changed from r1753812, 
aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderImpl.java
    
aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/InternalJDBCConnectionProviderFactory.java
    
aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/JDBCConnectionProviderFactoryServiceFactory.java
    
aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/ResourceTrackingJDBCConnectionProviderFactory.java
Modified:
    
aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractTransactionTest.java
    
aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/Activator.java
    
aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderFactoryImpl.java
    
aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderImpl.java
    
aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/ManagedServiceFactoryImpl.java
    
aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/Activator.java
    
aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderFactoryImpl.java
    
aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderImpl.java
    
aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/ManagedServiceFactoryImpl.java
    
aries/trunk/tx-control/tx-control-service-common/src/main/java/org/apache/aries/tx/control/service/common/impl/AbstractTransactionControlImpl.java
    
aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/Activator.java
    
aries/trunk/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/Activator.java
    
aries/trunk/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/TransactionControlImpl.java
    
aries/trunk/tx-control/tx-control-service-xa/src/test/java/org/apache/aries/tx/control/service/xa/impl/TransactionLogTest.java

Modified: 
aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractTransactionTest.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractTransactionTest.java?rev=1753813&r1=1753812&r2=1753813&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractTransactionTest.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractTransactionTest.java
 Fri Jul 22 16:53:02 2016
@@ -76,7 +76,7 @@ public abstract class AbstractTransactio
 
        private Server server;
        
-       private final List<ServiceTracker<?,?>> trackers = new ArrayList<>();
+       protected final List<ServiceTracker<?,?>> trackers = new ArrayList<>();
 
        @Before
        public void setUp() throws Exception {
@@ -100,7 +100,7 @@ public abstract class AbstractTransactio
                
                jdbc.setProperty(DataSourceFactory.JDBC_URL, jdbcUrl);
                
-               boolean configuredProvider = 
System.getProperties().containsKey(CONFIGURED_PROVIDER_PROPERTY);
+               boolean configuredProvider = isConfigured();
                
                connection = configuredProvider ? configuredConnection(jdbc) : 
programaticConnection(jdbc);
                
@@ -114,7 +114,11 @@ public abstract class AbstractTransactio
                        });
        }
 
-       private <T> T getService(Class<T> clazz, long timeout) {
+       public boolean isConfigured() {
+               return 
System.getProperties().containsKey(CONFIGURED_PROVIDER_PROPERTY);
+       }
+
+       protected <T> T getService(Class<T> clazz, long timeout) {
                try {
                        return getService(clazz, null, timeout);
                } catch (InvalidSyntaxException e) {
@@ -169,7 +173,7 @@ public abstract class AbstractTransactio
                System.out.println("Configuring connection provider with pid " 
+ pid);
                
                org.osgi.service.cm.Configuration config = 
cm.createFactoryConfiguration(
-                               pid, null);
+                               pid, "?");
                config.update((Hashtable)jdbc);
                
                return getService(JDBCConnectionProvider.class, 
5000).getResource(txControl);
@@ -178,11 +182,7 @@ public abstract class AbstractTransactio
        @After
        public void tearDown() {
 
-               txControl.required(() -> connection.createStatement()
-                               .execute("DROP TABLE TEST_TABLE"));
-               
-               
-               
if(System.getProperties().containsKey(CONFIGURED_PROVIDER_PROPERTY)) {
+               if(isConfigured()) {
                        clearConfiguration();
                }
                

Added: 
aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ConnectionLifecycleTest.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ConnectionLifecycleTest.java?rev=1753813&view=auto
==============================================================================
--- 
aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ConnectionLifecycleTest.java
 (added)
+++ 
aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ConnectionLifecycleTest.java
 Fri Jul 22 16:53:02 2016
@@ -0,0 +1,231 @@
+/*
+ * 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 WARRANTIESOR 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.tx.control.itests;
+
+import static java.util.stream.Collectors.toList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.sql.ResultSet;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Predicate;
+
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.transaction.control.ScopedWorkException;
+import org.osgi.service.transaction.control.TransactionException;
+import org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory;
+
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class ConnectionLifecycleTest extends AbstractTransactionTest {
+
+       @Test
+       public void testStopOfTxControlBundle() {
+               doBundleStoppingTest(b -> 
b.getSymbolicName().contains("tx-control-service"),
+                               "The transaction control service is closed");
+       }
+
+       @Test
+       public void testStopOfJDBCBundle() {
+               doBundleStoppingTest(b -> 
b.getSymbolicName().contains("tx-control-provider-jdbc"), 
+                               "There was a problem getting hold of a database 
connection");
+       }
+
+       private void doBundleStoppingTest(Predicate<Bundle> p, String 
exceptionMessage) {
+               txControl.required(() -> connection.createStatement()
+                               .execute("Insert into TEST_TABLE values ( 
'Hello World!' )"));
+
+               assertEquals("Hello World!", txControl.notSupported(() -> {
+                       ResultSet rs = connection.createStatement()
+                                       .executeQuery("Select * from 
TEST_TABLE");
+                       rs.next();
+                       return rs.getString(1);
+               }));
+               
+               
+               List<Bundle> toStop = Arrays.stream(context.getBundles())
+                       .filter(p)
+                       .collect(toList());
+               
+               System.out.println(toStop);
+               
+               try {
+                       toStop.stream()
+                               .forEach(b -> {
+                                       System.out.println("Stopping " + 
b.getSymbolicName());
+                                       try {
+                                               b.stop();
+                                       } catch (BundleException e) {}
+                               });
+               
+                       try {
+                               assertEquals("Hello World!", 
txControl.notSupported(() -> {
+                                       ResultSet rs = 
connection.createStatement()
+                                                       .executeQuery("Select * 
from TEST_TABLE");
+                                       rs.next();
+                                       return rs.getString(1);
+                               }));
+                               fail("Should not be accessible");
+                       } catch (ScopedWorkException swe) {
+                               assertTrue(swe.getCause().toString(), 
swe.getCause() instanceof TransactionException);
+                               assertEquals(exceptionMessage, 
swe.getCause().getMessage());
+                       } catch (TransactionException te) {
+                               assertEquals(exceptionMessage, te.getMessage());
+                       }
+               } finally {
+                       toStop.stream()
+                               .forEach(b -> {
+                                       try {
+                                               b.start();
+                                       } catch (BundleException e) {}
+                               });
+               }
+       }
+
+       @Test
+       public void testDeleteOfConfig() throws Exception {
+               Assume.assumeTrue("Not a configuration test", isConfigured());
+               
+               
+               txControl.required(() -> connection.createStatement()
+                               .execute("Insert into TEST_TABLE values ( 
'Hello World!' )"));
+
+               assertEquals("Hello World!", txControl.notSupported(() -> {
+                       ResultSet rs = connection.createStatement()
+                                       .executeQuery("Select * from 
TEST_TABLE");
+                       rs.next();
+                       return rs.getString(1);
+               }));
+               
+               
+               ConfigurationAdmin cm = getService(ConfigurationAdmin.class, 
5000);
+               
+               Configuration[] configurations = cm.listConfigurations(
+                               
"(service.factoryPid=org.apache.aries.tx.control.jdbc.*)");
+               
+               assertNotNull(configurations);
+               assertEquals(1, configurations.length);
+               
+               configurations[0].delete();
+               
+               Thread.sleep(2000);
+               
+               try {
+                       assertEquals("Hello World!", txControl.notSupported(() 
-> {
+                               ResultSet rs = connection.createStatement()
+                                               .executeQuery("Select * from 
TEST_TABLE");
+                               rs.next();
+                               return rs.getString(1);
+                       }));
+                       fail("Should not be accessible");
+               } catch (ScopedWorkException swe) {
+                       assertTrue(swe.getCause().toString(), swe.getCause() 
instanceof TransactionException);
+                       assertEquals("There was a problem getting hold of a 
database connection", swe.getCause().getMessage());
+               }
+       }
+
+       @Test
+       public void testUpdateOfConfig() throws Exception {
+               Assume.assumeTrue("Not a configuration test", isConfigured());
+               
+               
+               txControl.required(() -> connection.createStatement()
+                               .execute("Insert into TEST_TABLE values ( 
'Hello World!' )"));
+
+               assertEquals("Hello World!", txControl.notSupported(() -> {
+                       ResultSet rs = connection.createStatement()
+                                       .executeQuery("Select * from 
TEST_TABLE");
+                       rs.next();
+                       return rs.getString(1);
+               }));
+               
+               
+               ConfigurationAdmin cm = getService(ConfigurationAdmin.class, 
5000);
+               
+               Configuration[] configurations = cm.listConfigurations(
+                               
"(service.factoryPid=org.apache.aries.tx.control.jdbc.*)");
+               
+               assertNotNull(configurations);
+               assertEquals(1, configurations.length);
+               
+               configurations[0].update();
+               
+               Thread.sleep(2000);
+               
+               try {
+                       assertEquals("Hello World!", txControl.notSupported(() 
-> {
+                               ResultSet rs = connection.createStatement()
+                                               .executeQuery("Select * from 
TEST_TABLE");
+                               rs.next();
+                               return rs.getString(1);
+                       }));
+                       fail("Should not be accessible");
+               } catch (ScopedWorkException swe) {
+                       assertTrue(swe.getCause().toString(), swe.getCause() 
instanceof TransactionException);
+                       assertEquals("There was a problem getting hold of a 
database connection", swe.getCause().getMessage());
+               }
+       }
+       
+       @Test
+       public void testReleaseOfFactoryService() {
+               Assume.assumeFalse("Not a factory test", isConfigured());
+               
+               txControl.required(() -> connection.createStatement()
+                               .execute("Insert into TEST_TABLE values ( 
'Hello World!' )"));
+
+               assertEquals("Hello World!", txControl.notSupported(() -> {
+                       ResultSet rs = connection.createStatement()
+                                       .executeQuery("Select * from 
TEST_TABLE");
+                       rs.next();
+                       return rs.getString(1);
+               }));
+               
+               
+               trackers.stream()
+                       .filter(t -> t.getService() instanceof 
JDBCConnectionProviderFactory)
+                       .findFirst()
+                       .get().close();;
+               
+               
+               try {
+                       assertEquals("Hello World!", txControl.notSupported(() 
-> {
+                               ResultSet rs = connection.createStatement()
+                                               .executeQuery("Select * from 
TEST_TABLE");
+                               rs.next();
+                               return rs.getString(1);
+                       }));
+                       fail("Should not be accessible");
+               } catch (ScopedWorkException swe) {
+                       assertTrue(swe.getCause().toString(), swe.getCause() 
instanceof TransactionException);
+                       assertEquals("There was a problem getting hold of a 
database connection", swe.getCause().getMessage());
+               }
+       }
+}

Copied: 
aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/AbstractJDBCConnectionProvider.java
 (from r1753812, 
aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderImpl.java)
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/AbstractJDBCConnectionProvider.java?p2=aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/AbstractJDBCConnectionProvider.java&p1=aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderImpl.java&r1=1753812&r2=1753813&rev=1753813&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderImpl.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/AbstractJDBCConnectionProvider.java
 Fri Jul 22 16:53:02 2016
@@ -16,31 +16,40 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.aries.tx.control.jdbc.local.impl;
+package org.apache.aries.tx.control.jdbc.common.impl;
 
 import java.sql.Connection;
-import java.util.UUID;
 
 import javax.sql.DataSource;
 
 import org.osgi.service.transaction.control.TransactionControl;
 import org.osgi.service.transaction.control.TransactionException;
 import org.osgi.service.transaction.control.jdbc.JDBCConnectionProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-public class JDBCConnectionProviderImpl implements JDBCConnectionProvider {
+public abstract class AbstractJDBCConnectionProvider implements 
JDBCConnectionProvider {
 
-       private final UUID                      uuid    = UUID.randomUUID();
-
-       private final DataSource dataSource;
+       private static final Logger LOG = 
LoggerFactory.getLogger(AbstractJDBCConnectionProvider.class);
+       
+       protected final DataSource dataSource;
        
-       public JDBCConnectionProviderImpl(DataSource dataSource) {
+       public AbstractJDBCConnectionProvider(DataSource dataSource) {
                this.dataSource = dataSource;
        }
 
        @Override
-       public Connection getResource(TransactionControl txControl)
-                       throws TransactionException {
-               return new TxContextBindingConnection(txControl, dataSource , 
uuid);
-       }
+       public abstract Connection getResource(TransactionControl txControl)
+                       throws TransactionException;
 
+       
+       public void close() {
+               if(dataSource instanceof AutoCloseable) {
+                       try {
+                               ((AutoCloseable) dataSource).close();
+                       } catch (Exception e) {
+                               LOG.warn("An error occurred shutting down the 
JDBCConnectionProvider {}", dataSource, e);
+                       }
+               }
+       }
 }

Added: 
aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/InternalJDBCConnectionProviderFactory.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/InternalJDBCConnectionProviderFactory.java?rev=1753813&view=auto
==============================================================================
--- 
aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/InternalJDBCConnectionProviderFactory.java
 (added)
+++ 
aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/InternalJDBCConnectionProviderFactory.java
 Fri Jul 22 16:53:02 2016
@@ -0,0 +1,27 @@
+package org.apache.aries.tx.control.jdbc.common.impl;
+
+import java.sql.Driver;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.sql.DataSource;
+import javax.sql.XADataSource;
+
+import org.osgi.service.jdbc.DataSourceFactory;
+import org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory;
+
+public interface InternalJDBCConnectionProviderFactory extends 
JDBCConnectionProviderFactory {
+
+       @Override
+       AbstractJDBCConnectionProvider getProviderFor(DataSourceFactory dsf, 
Properties jdbcProperties,
+                       Map<String, Object> resourceProviderProperties);
+
+       AbstractJDBCConnectionProvider getProviderFor(DataSource ds, 
Map<String, Object> resourceProviderProperties);
+
+       @Override
+       AbstractJDBCConnectionProvider getProviderFor(Driver driver, Properties 
jdbcProperties,
+                       Map<String, Object> resourceProviderProperties);
+
+       AbstractJDBCConnectionProvider getProviderFor(XADataSource ds, 
Map<String, Object> resourceProviderProperties);
+
+}

Added: 
aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/JDBCConnectionProviderFactoryServiceFactory.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/JDBCConnectionProviderFactoryServiceFactory.java?rev=1753813&view=auto
==============================================================================
--- 
aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/JDBCConnectionProviderFactoryServiceFactory.java
 (added)
+++ 
aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/JDBCConnectionProviderFactoryServiceFactory.java
 Fri Jul 22 16:53:02 2016
@@ -0,0 +1,38 @@
+package org.apache.aries.tx.control.jdbc.common.impl;
+
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+
+public abstract class JDBCConnectionProviderFactoryServiceFactory implements 
+       ServiceFactory<ResourceTrackingJDBCConnectionProviderFactory> {
+
+       Set<ResourceTrackingJDBCConnectionProviderFactory> factories = new 
CopyOnWriteArraySet<>();
+       
+       @Override
+       public ResourceTrackingJDBCConnectionProviderFactory getService(Bundle 
bundle,
+                       
ServiceRegistration<ResourceTrackingJDBCConnectionProviderFactory> 
registration) {
+               ResourceTrackingJDBCConnectionProviderFactory factory = new 
ResourceTrackingJDBCConnectionProviderFactory(
+                                               
getInternalJDBCConnectionProviderFactory());
+               factories.add(factory);
+               return factory;
+       }
+
+       @Override
+       public void ungetService(Bundle bundle, 
ServiceRegistration<ResourceTrackingJDBCConnectionProviderFactory> registration,
+                       ResourceTrackingJDBCConnectionProviderFactory service) {
+               factories.remove(service);
+               service.closeAll();
+       }
+       
+       public void close() {
+               factories.stream()
+                       .forEach(r -> r.closeAll());
+       }
+       
+       protected abstract InternalJDBCConnectionProviderFactory 
+               getInternalJDBCConnectionProviderFactory();
+}

Added: 
aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/ResourceTrackingJDBCConnectionProviderFactory.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/ResourceTrackingJDBCConnectionProviderFactory.java?rev=1753813&view=auto
==============================================================================
--- 
aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/ResourceTrackingJDBCConnectionProviderFactory.java
 (added)
+++ 
aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/ResourceTrackingJDBCConnectionProviderFactory.java
 Fri Jul 22 16:53:02 2016
@@ -0,0 +1,91 @@
+package org.apache.aries.tx.control.jdbc.common.impl;
+
+import java.sql.Driver;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.function.Supplier;
+
+import javax.sql.DataSource;
+import javax.sql.XADataSource;
+
+import org.osgi.service.jdbc.DataSourceFactory;
+import org.osgi.service.transaction.control.jdbc.JDBCConnectionProvider;
+import org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory;
+
+class ResourceTrackingJDBCConnectionProviderFactory implements
+       JDBCConnectionProviderFactory {
+
+       private final List<AbstractJDBCConnectionProvider> toClose = new 
ArrayList<>();
+       
+       private final InternalJDBCConnectionProviderFactory factory;
+       
+       private boolean closed;
+       
+       public 
ResourceTrackingJDBCConnectionProviderFactory(InternalJDBCConnectionProviderFactory
 factory) {
+               this.factory = factory;
+       }
+
+       @Override
+       public JDBCConnectionProvider getProviderFor(DataSourceFactory dsf, 
Properties jdbcProperties,
+                       Map<String, Object> resourceProviderProperties) {
+               return doGetResult(() -> factory.getProviderFor(dsf, 
+                               jdbcProperties, resourceProviderProperties));
+       }
+
+       @Override
+       public JDBCConnectionProvider getProviderFor(DataSource ds, Map<String, 
Object> resourceProviderProperties) {
+               return doGetResult(() -> factory.getProviderFor(ds, 
+                               resourceProviderProperties));
+       }
+
+       @Override
+       public JDBCConnectionProvider getProviderFor(Driver driver, Properties 
jdbcProperties,
+                       Map<String, Object> resourceProviderProperties) {
+               return doGetResult(() -> factory.getProviderFor(driver, 
+                               jdbcProperties, resourceProviderProperties));
+       }
+
+       @Override
+       public JDBCConnectionProvider getProviderFor(XADataSource ds, 
Map<String, Object> resourceProviderProperties) {
+               return doGetResult(() -> factory.getProviderFor(ds, 
+                               resourceProviderProperties));
+       }
+       
+       private AbstractJDBCConnectionProvider 
doGetResult(Supplier<AbstractJDBCConnectionProvider> getter) {
+               synchronized (getter) {
+                       if (closed) {
+                               throw new IllegalStateException("This 
ResourceProvider has been reclaimed because the factory service that provided 
it was released");
+                       }
+               }
+               AbstractJDBCConnectionProvider ajcp = getter.get();
+               boolean destroy = false;
+               synchronized (toClose) {
+                       if (closed) {
+                               destroy = true;
+                       } else {
+                           toClose.add(ajcp);
+                       }
+               }
+               if(destroy) {
+                       ajcp.close();
+                       throw new IllegalStateException("This ResourceProvider 
has been reclaimed because the factory service that provided it was released");
+               }
+               return ajcp;
+       }
+
+       public void closeAll() {
+               synchronized (toClose) {
+                       closed = true;
+               }
+               // toClose is now up to date and no other thread will write it
+               toClose.stream().forEach(ajcp -> {
+                       try {
+                               ajcp.close();
+                       } catch (Exception e) {}
+               });
+               
+               toClose.clear();
+       }
+}
\ No newline at end of file

Modified: 
aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/Activator.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/Activator.java?rev=1753813&r1=1753812&r2=1753813&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/Activator.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/Activator.java
 Fri Jul 22 16:53:02 2016
@@ -23,6 +23,8 @@ import static org.osgi.framework.Constan
 import java.util.Dictionary;
 import java.util.Hashtable;
 
+import 
org.apache.aries.tx.control.jdbc.common.impl.InternalJDBCConnectionProviderFactory;
+import 
org.apache.aries.tx.control.jdbc.common.impl.JDBCConnectionProviderFactoryServiceFactory;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
@@ -31,22 +33,42 @@ import org.osgi.service.transaction.cont
 
 public class Activator implements BundleActivator {
 
-       private ServiceRegistration<JDBCConnectionProviderFactory> reg;
+       private ServiceRegistration<?> reg;
        private ServiceRegistration<ManagedServiceFactory> factoryReg;
+       private JDBCConnectionProviderFactoryServiceFactory service;
+       private ManagedServiceFactoryImpl msf;
        
        @Override
        public void start(BundleContext context) throws Exception {
-               reg = 
context.registerService(JDBCConnectionProviderFactory.class, 
-                               new JDBCConnectionProviderFactoryImpl(), 
getProperties());
                
+               InternalJDBCConnectionProviderFactory ijcpf = new 
JDBCConnectionProviderFactoryImpl();
+               
+               service = new JDBCConnectionProviderFactoryServiceFactory() {
+                       @Override
+                       protected InternalJDBCConnectionProviderFactory 
getInternalJDBCConnectionProviderFactory() {
+                               return ijcpf;
+                       }
+               };
+               reg = 
context.registerService(JDBCConnectionProviderFactory.class.getName(), 
+                               service, getProperties());
+               
+               msf = new ManagedServiceFactoryImpl(context);
                factoryReg = 
context.registerService(ManagedServiceFactory.class, 
-                               new ManagedServiceFactoryImpl(context), 
getMSFProperties());
+                               msf, getMSFProperties());
        }
 
        @Override
        public void stop(BundleContext context) throws Exception {
-               reg.unregister();
-               factoryReg.unregister();
+               safeUnregister(reg);
+               safeUnregister(factoryReg);
+               service.close();
+               msf.stop();
+       }
+
+       private void safeUnregister(ServiceRegistration<?> reg) {
+               try {
+                       reg.unregister();
+               } catch (IllegalStateException ise) {}
        }
 
        private Dictionary<String, Object> getProperties() {

Modified: 
aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderFactoryImpl.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderFactoryImpl.java?rev=1753813&r1=1753812&r2=1753813&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderFactoryImpl.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderFactoryImpl.java
 Fri Jul 22 16:53:02 2016
@@ -32,19 +32,20 @@ import java.util.concurrent.TimeUnit;
 import javax.sql.DataSource;
 import javax.sql.XADataSource;
 
+import 
org.apache.aries.tx.control.jdbc.common.impl.AbstractJDBCConnectionProvider;
 import org.apache.aries.tx.control.jdbc.common.impl.DriverDataSource;
+import 
org.apache.aries.tx.control.jdbc.common.impl.InternalJDBCConnectionProviderFactory;
 import org.osgi.service.jdbc.DataSourceFactory;
 import org.osgi.service.transaction.control.TransactionException;
-import org.osgi.service.transaction.control.jdbc.JDBCConnectionProvider;
 import org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory;
 
 import com.zaxxer.hikari.HikariConfig;
 import com.zaxxer.hikari.HikariDataSource;
 
-public class JDBCConnectionProviderFactoryImpl implements 
JDBCConnectionProviderFactory {
+public class JDBCConnectionProviderFactoryImpl implements 
JDBCConnectionProviderFactory, InternalJDBCConnectionProviderFactory {
 
        @Override
-       public JDBCConnectionProvider getProviderFor(DataSourceFactory dsf, 
Properties jdbcProperties,
+       public AbstractJDBCConnectionProvider getProviderFor(DataSourceFactory 
dsf, Properties jdbcProperties,
                        Map<String, Object> resourceProviderProperties) {
 
                checkEnlistment(resourceProviderProperties);
@@ -67,7 +68,7 @@ public class JDBCConnectionProviderFacto
        }
 
        @Override
-       public JDBCConnectionProvider getProviderFor(DataSource ds, Map<String, 
Object> resourceProviderProperties) {
+       public AbstractJDBCConnectionProvider getProviderFor(DataSource ds, 
Map<String, Object> resourceProviderProperties) {
                checkEnlistment(resourceProviderProperties);
                DataSource toUse = poolIfNecessary(resourceProviderProperties, 
ds);
 
@@ -75,7 +76,7 @@ public class JDBCConnectionProviderFacto
        }
 
        @Override
-       public JDBCConnectionProvider getProviderFor(Driver driver, Properties 
jdbcProperties, 
+       public AbstractJDBCConnectionProvider getProviderFor(Driver driver, 
Properties jdbcProperties, 
                        Map<String, Object> resourceProviderProperties) {
                checkEnlistment(resourceProviderProperties);
                DataSource toUse = poolIfNecessary(resourceProviderProperties, 
@@ -85,7 +86,7 @@ public class JDBCConnectionProviderFacto
        }
 
        @Override
-       public JDBCConnectionProvider getProviderFor(XADataSource ds, 
Map<String, Object> resourceProviderProperties) {
+       public AbstractJDBCConnectionProvider getProviderFor(XADataSource ds, 
Map<String, Object> resourceProviderProperties) {
                checkEnlistment(resourceProviderProperties);
                
                DataSource unpooled;

Modified: 
aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderImpl.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderImpl.java?rev=1753813&r1=1753812&r2=1753813&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderImpl.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderImpl.java
 Fri Jul 22 16:53:02 2016
@@ -23,18 +23,16 @@ import java.util.UUID;
 
 import javax.sql.DataSource;
 
+import 
org.apache.aries.tx.control.jdbc.common.impl.AbstractJDBCConnectionProvider;
 import org.osgi.service.transaction.control.TransactionControl;
 import org.osgi.service.transaction.control.TransactionException;
-import org.osgi.service.transaction.control.jdbc.JDBCConnectionProvider;
 
-public class JDBCConnectionProviderImpl implements JDBCConnectionProvider {
+public class JDBCConnectionProviderImpl extends AbstractJDBCConnectionProvider 
{
 
        private final UUID                      uuid    = UUID.randomUUID();
 
-       private final DataSource dataSource;
-       
        public JDBCConnectionProviderImpl(DataSource dataSource) {
-               this.dataSource = dataSource;
+               super(dataSource);
        }
 
        @Override
@@ -42,5 +40,4 @@ public class JDBCConnectionProviderImpl
                        throws TransactionException {
                return new TxContextBindingConnection(txControl, dataSource , 
uuid);
        }
-
 }

Modified: 
aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/ManagedServiceFactoryImpl.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/ManagedServiceFactoryImpl.java?rev=1753813&r1=1753812&r2=1753813&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/ManagedServiceFactoryImpl.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/ManagedServiceFactoryImpl.java
 Fri Jul 22 16:53:02 2016
@@ -45,6 +45,7 @@ import java.util.Properties;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicReference;
 
+import 
org.apache.aries.tx.control.jdbc.common.impl.AbstractJDBCConnectionProvider;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
@@ -150,6 +151,7 @@ public class ManagedServiceFactoryImpl i
 
                private final AtomicReference<DataSourceFactory> activeDsf = 
new AtomicReference<>();
                private final 
AtomicReference<ServiceRegistration<JDBCConnectionProvider>> serviceReg = new 
AtomicReference<>();
+               private final AtomicReference<AbstractJDBCConnectionProvider> 
providerObject = new AtomicReference<>();
 
                public ManagedJDBCResourceProvider(BundleContext context, 
String pid, Properties jdbcProperties,
                                Map<String, Object> providerProperties) throws 
InvalidSyntaxException, ConfigurationException {
@@ -197,17 +199,24 @@ public class ManagedServiceFactoryImpl i
                        }
 
                        if (setDsf) {
+                               AbstractJDBCConnectionProvider provider = null;
+                               ServiceRegistration<JDBCConnectionProvider> reg 
= null;
                                try {
-                                       JDBCConnectionProvider provider = new 
JDBCConnectionProviderFactoryImpl().getProviderFor(service,
+                                       provider = new 
JDBCConnectionProviderFactoryImpl().getProviderFor(service,
                                                        jdbcProperties, 
providerProperties);
-                                       
ServiceRegistration<JDBCConnectionProvider> reg = context
-                                                       
.registerService(JDBCConnectionProvider.class, provider, 
getServiceProperties());
-                                       if (!serviceReg.compareAndSet(null, 
reg)) {
-                                               throw new 
IllegalStateException("Unable to set the JDBC connection provider 
registration");
+                                       reg = 
context.registerService(JDBCConnectionProvider.class, 
+                                                       provider, 
getServiceProperties());
+                                       synchronized (this) {
+                                               if 
(!serviceReg.compareAndSet(null, reg)) {
+                                                       throw new 
IllegalStateException("Unable to set the JDBC connection provider 
registration");
+                                               } else {
+                                                       
providerObject.set(provider);
+                                               }
                                        }
                                } catch (Exception e) {
-                                       LOG.error("An error occurred when 
creating the connection provider for {}.", pid, e);
                                        activeDsf.compareAndSet(service, null);
+                                       safeUnregister(reg, provider);
+                                       LOG.error("An error occurred when 
creating the connection provider for {}.", pid, e);
                                }
                        }
                }
@@ -229,13 +238,27 @@ public class ManagedServiceFactoryImpl i
                public void removedService(ServiceReference<DataSourceFactory> 
reference, DataSourceFactory service) {
                        boolean dsfLeft;
                        ServiceRegistration<JDBCConnectionProvider> oldReg = 
null;
+                       AbstractJDBCConnectionProvider oldProvider = null;
                        synchronized (this) {
                                dsfLeft = activeDsf.compareAndSet(service, 
null);
                                if (dsfLeft) {
                                        oldReg = serviceReg.getAndSet(null);
+                                       oldProvider = 
providerObject.getAndSet(null);
                                }
                        }
+                       
+                       safeUnregister(oldReg, oldProvider);
 
+                       if (dsfLeft) {
+                               DataSourceFactory newDSF = 
dsfTracker.getService();
+                               if (newDSF != null) {
+                                       updateService(dsfTracker.getService());
+                               }
+                       }
+               }
+
+               private void safeUnregister(ServiceRegistration<?> oldReg, 
+                               AbstractJDBCConnectionProvider provider) {
                        if (oldReg != null) {
                                try {
                                        oldReg.unregister();
@@ -243,11 +266,11 @@ public class ManagedServiceFactoryImpl i
                                        LOG.debug("An exception occurred when 
unregistering a service for {}", pid);
                                }
                        }
-
-                       if (dsfLeft) {
-                               DataSourceFactory newDSF = 
dsfTracker.getService();
-                               if (newDSF != null) {
-                                       updateService(dsfTracker.getService());
+                       if(provider != null) {
+                               try {
+                                       provider.close();
+                               } catch (Exception e) {
+                                       LOG.debug("An exception occurred when 
closing a provider for {}", pid, e);
                                }
                        }
                }

Modified: 
aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/Activator.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/Activator.java?rev=1753813&r1=1753812&r2=1753813&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/Activator.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/Activator.java
 Fri Jul 22 16:53:02 2016
@@ -23,6 +23,8 @@ import static org.osgi.framework.Constan
 import java.util.Dictionary;
 import java.util.Hashtable;
 
+import 
org.apache.aries.tx.control.jdbc.common.impl.InternalJDBCConnectionProviderFactory;
+import 
org.apache.aries.tx.control.jdbc.common.impl.JDBCConnectionProviderFactoryServiceFactory;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
@@ -33,22 +35,42 @@ public class Activator implements Bundle
 
        private ServiceRegistration<JDBCConnectionProviderFactory> reg;
        private ServiceRegistration<ManagedServiceFactory> factoryReg;
+       private JDBCConnectionProviderFactoryServiceFactory service;
+       private ManagedServiceFactoryImpl msf;
        
        @Override
        public void start(BundleContext context) throws Exception {
+               InternalJDBCConnectionProviderFactory ijcpf = new 
JDBCConnectionProviderFactoryImpl();
+               
+               service = new JDBCConnectionProviderFactoryServiceFactory() {
+                       @Override
+                       protected InternalJDBCConnectionProviderFactory 
getInternalJDBCConnectionProviderFactory() {
+                               return ijcpf;
+                       }
+               };
+               
                reg = 
context.registerService(JDBCConnectionProviderFactory.class, 
                                new JDBCConnectionProviderFactoryImpl(), 
getProperties());
                
+               msf = new ManagedServiceFactoryImpl(context);
                factoryReg = 
context.registerService(ManagedServiceFactory.class, 
-                               new ManagedServiceFactoryImpl(context), 
getMSFProperties());
+                               msf, getMSFProperties());
        }
 
        @Override
        public void stop(BundleContext context) throws Exception {
-               reg.unregister();
-               factoryReg.unregister();
+               safeUnregister(reg);
+               safeUnregister(factoryReg);
+               service.close();
+               msf.stop();
        }
 
+       private void safeUnregister(ServiceRegistration<?> reg) {
+               try {
+                       reg.unregister();
+               } catch (IllegalStateException ise) {}
+       }
+       
        private Dictionary<String, Object> getProperties() {
                Dictionary<String, Object> props = new Hashtable<>();
                props.put("osgi.local.enabled", Boolean.TRUE);

Modified: 
aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderFactoryImpl.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderFactoryImpl.java?rev=1753813&r1=1753812&r2=1753813&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderFactoryImpl.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderFactoryImpl.java
 Fri Jul 22 16:53:02 2016
@@ -33,10 +33,10 @@ import javax.sql.DataSource;
 import javax.sql.XADataSource;
 
 import org.apache.aries.tx.control.jdbc.common.impl.DriverDataSource;
+import 
org.apache.aries.tx.control.jdbc.common.impl.InternalJDBCConnectionProviderFactory;
 import org.apache.aries.tx.control.jdbc.xa.connection.impl.XADataSourceMapper;
 import org.osgi.service.jdbc.DataSourceFactory;
 import org.osgi.service.transaction.control.TransactionException;
-import org.osgi.service.transaction.control.jdbc.JDBCConnectionProvider;
 import org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -44,7 +44,7 @@ import org.slf4j.LoggerFactory;
 import com.zaxxer.hikari.HikariConfig;
 import com.zaxxer.hikari.HikariDataSource;
 
-public class JDBCConnectionProviderFactoryImpl implements 
JDBCConnectionProviderFactory {
+public class JDBCConnectionProviderFactoryImpl implements 
JDBCConnectionProviderFactory, InternalJDBCConnectionProviderFactory {
 
        private static final Logger LOG = 
LoggerFactory.getLogger(ManagedServiceFactoryImpl.class);
        
@@ -91,7 +91,7 @@ public class JDBCConnectionProviderFacto
        }
 
        @Override
-       public JDBCConnectionProvider getProviderFor(DataSource ds, Map<String, 
Object> resourceProviderProperties) {
+       public JDBCConnectionProviderImpl getProviderFor(DataSource ds, 
Map<String, Object> resourceProviderProperties) {
                boolean xaEnabled = toBoolean(resourceProviderProperties, 
XA_ENLISTMENT_ENABLED, true);
                boolean localEnabled = toBoolean(resourceProviderProperties, 
LOCAL_ENLISTMENT_ENABLED, true);
                
@@ -108,7 +108,7 @@ public class JDBCConnectionProviderFacto
        }
 
        @Override
-       public JDBCConnectionProvider getProviderFor(Driver driver, Properties 
jdbcProperties, 
+       public JDBCConnectionProviderImpl getProviderFor(Driver driver, 
Properties jdbcProperties, 
                        Map<String, Object> resourceProviderProperties) {
                
                boolean xaEnabled = toBoolean(resourceProviderProperties, 
XA_ENLISTMENT_ENABLED, false);
@@ -124,7 +124,7 @@ public class JDBCConnectionProviderFacto
        }
 
        @Override
-       public JDBCConnectionProvider getProviderFor(XADataSource ds, 
Map<String, Object> resourceProviderProperties) {
+       public JDBCConnectionProviderImpl getProviderFor(XADataSource ds, 
Map<String, Object> resourceProviderProperties) {
                
                boolean xaEnabled = toBoolean(resourceProviderProperties, 
XA_ENLISTMENT_ENABLED, true);
                boolean localEnabled = toBoolean(resourceProviderProperties, 
LOCAL_ENLISTMENT_ENABLED, true);

Modified: 
aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderImpl.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderImpl.java?rev=1753813&r1=1753812&r2=1753813&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderImpl.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderImpl.java
 Fri Jul 22 16:53:02 2016
@@ -23,16 +23,14 @@ import java.util.UUID;
 
 import javax.sql.DataSource;
 
+import 
org.apache.aries.tx.control.jdbc.common.impl.AbstractJDBCConnectionProvider;
 import org.osgi.service.transaction.control.TransactionControl;
 import org.osgi.service.transaction.control.TransactionException;
-import org.osgi.service.transaction.control.jdbc.JDBCConnectionProvider;
 
-public class JDBCConnectionProviderImpl implements JDBCConnectionProvider {
+public class JDBCConnectionProviderImpl extends AbstractJDBCConnectionProvider 
{
 
        private final UUID                      uuid    = UUID.randomUUID();
 
-       private final DataSource dataSource;
-       
        private final boolean xaEnabled;
        
        private final boolean localEnabled;
@@ -41,7 +39,7 @@ public class JDBCConnectionProviderImpl
        
        public JDBCConnectionProviderImpl(DataSource dataSource, boolean 
xaEnabled,
                        boolean localEnabled, String recoveryIdentifier) {
-               this.dataSource = dataSource;
+               super(dataSource);
                this.xaEnabled = xaEnabled;
                this.localEnabled = localEnabled;
                this.recoveryIdentifier = recoveryIdentifier;

Modified: 
aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/ManagedServiceFactoryImpl.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/ManagedServiceFactoryImpl.java?rev=1753813&r1=1753812&r2=1753813&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/ManagedServiceFactoryImpl.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/ManagedServiceFactoryImpl.java
 Fri Jul 22 16:53:02 2016
@@ -47,6 +47,7 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.concurrent.ConcurrentHashMap;
 
+import 
org.apache.aries.tx.control.jdbc.common.impl.AbstractJDBCConnectionProvider;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
@@ -154,6 +155,7 @@ public class ManagedServiceFactoryImpl i
                private DataSourceFactory activeDsf;
                private ServiceRegistration<JDBCConnectionProvider> serviceReg;
                private ServiceRegistration<RecoverableXAResource> recoveryReg;
+               private AbstractJDBCConnectionProvider provider;
 
                public ManagedJDBCResourceProvider(BundleContext context, 
String pid, Properties jdbcProperties,
                                Map<String, Object> providerProperties) throws 
InvalidSyntaxException, ConfigurationException {
@@ -202,9 +204,10 @@ public class ManagedServiceFactoryImpl i
 
                        ServiceRegistration<JDBCConnectionProvider> reg = null;
                        ServiceRegistration<RecoverableXAResource> reg2 = null;
+                       JDBCConnectionProviderImpl provider = null;
                        if (setDsf) {
                                try {
-                                       JDBCConnectionProviderImpl provider = 
new JDBCConnectionProviderFactoryImpl().getProviderFor(service,
+                                       provider = new 
JDBCConnectionProviderFactoryImpl().getProviderFor(service,
                                                        jdbcProperties, 
providerProperties);
                                        String recoveryId = (String) 
providerProperties.get(OSGI_RECOVERY_IDENTIFIER);
                                        if(recoveryId !=null) {
@@ -223,20 +226,24 @@ public class ManagedServiceFactoryImpl i
 
                                        
ServiceRegistration<JDBCConnectionProvider> oldReg;
                                        
ServiceRegistration<RecoverableXAResource> oldReg2;
-                                       
+                                       AbstractJDBCConnectionProvider 
oldProvider;
                                        synchronized (this) {
                                                if(activeDsf == service) {
                                                        oldReg = serviceReg;
                                                        serviceReg = reg;
                                                        oldReg2 = recoveryReg;
                                                        recoveryReg = reg2;
+                                                       oldProvider = 
this.provider;
+                                                       this.provider = 
provider;
                                                } else {
                                                        oldReg = reg;
                                                        oldReg2 = reg2;
+                                                       oldProvider = provider;
                                                }
                                        }
                                        safeUnregister(oldReg);
                                        safeUnregister(oldReg2);
+                                       safeClose(oldProvider);
                                } catch (Exception e) {
                                        LOG.error("An error occurred when 
creating the connection provider for {}.", pid, e);
                                        
@@ -247,6 +254,7 @@ public class ManagedServiceFactoryImpl i
                                        }
                                        safeUnregister(reg);
                                        safeUnregister(reg2);
+                                       safeClose(provider);
                                }
                        }
                        return service;
@@ -262,6 +270,16 @@ public class ManagedServiceFactoryImpl i
                        }
                }
                        
+               private void safeClose(AbstractJDBCConnectionProvider 
oldProvider) {
+                       if(oldProvider != null) {
+                               try {
+                                       oldProvider.close();
+                               } catch (Exception e) {
+                                       LOG.debug("An exception occurred when 
closing a provider for {}", pid, e);
+                               }
+                       }
+               }
+
                private Dictionary<String, ?> getServiceProperties() {
                        Hashtable<String, Object> props = new Hashtable<>();
                        providerProperties.keySet().stream()
@@ -280,18 +298,22 @@ public class ManagedServiceFactoryImpl i
                        boolean dsfLeft;
                        ServiceRegistration<JDBCConnectionProvider> oldReg = 
null;
                        ServiceRegistration<RecoverableXAResource> oldReg2 = 
null;
+                       AbstractJDBCConnectionProvider oldProvider = null;
                        synchronized (this) {
                                dsfLeft = activeDsf == service;
                                if (dsfLeft) {
                                        activeDsf = null;
                                        oldReg = serviceReg;
                                        oldReg2 = recoveryReg;
+                                       oldProvider = provider;
                                        serviceReg = null;
                                        recoveryReg = null;
+                                       provider = null;
                                }
                        }
                        safeUnregister(oldReg);
                        safeUnregister(oldReg2);
+                       safeClose(oldProvider);
 
                        if (dsfLeft) {
                                DataSourceFactory newDSF = 
dsfTracker.getService();

Modified: 
aries/trunk/tx-control/tx-control-service-common/src/main/java/org/apache/aries/tx/control/service/common/impl/AbstractTransactionControlImpl.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-service-common/src/main/java/org/apache/aries/tx/control/service/common/impl/AbstractTransactionControlImpl.java?rev=1753813&r1=1753812&r2=1753813&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-service-common/src/main/java/org/apache/aries/tx/control/service/common/impl/AbstractTransactionControlImpl.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-service-common/src/main/java/org/apache/aries/tx/control/service/common/impl/AbstractTransactionControlImpl.java
 Fri Jul 22 16:53:02 2016
@@ -26,6 +26,7 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.osgi.service.transaction.control.ScopedWorkException;
 import org.osgi.service.transaction.control.TransactionBuilder;
@@ -46,7 +47,12 @@ public abstract class AbstractTransactio
                        return this;
                }
 
-               private void checkExceptions() {
+               private void checkValid() {
+                       
+                       if(closed.get()) {
+                               throw new TransactionException("The transaction 
control service is closed");
+                       }
+                       
                        List<Class<? extends Throwable>> duplicates = 
rollbackFor.stream()
                                        .filter(noRollbackFor::contains)
                                        .collect(toList());
@@ -59,7 +65,7 @@ public abstract class AbstractTransactio
                @Override
                public <T> T required(Callable<T> work)
                                throws TransactionException, 
TransactionRolledBackException {
-                       checkExceptions();
+                       checkValid();
                        
                        boolean endTransaction = false;
 
@@ -85,7 +91,7 @@ public abstract class AbstractTransactio
                @Override
                public <T> T requiresNew(Callable<T> work)
                                throws TransactionException, 
TransactionRolledBackException {
-                       checkExceptions();
+                       checkValid();
                        
                        AbstractTransactionContextImpl existingTran = 
existingTx.get();
                        try {
@@ -100,7 +106,7 @@ public abstract class AbstractTransactio
 
                @Override
                public <T> T supports(Callable<T> work) throws 
TransactionException {
-                       checkExceptions();
+                       checkValid();
                        
                        boolean endTransaction = false;
 
@@ -124,7 +130,7 @@ public abstract class AbstractTransactio
                @Override
                public <T> T notSupported(Callable<T> work)
                                throws TransactionException {
-                       checkExceptions();
+                       checkValid();
                        
                        boolean endTransaction = false;
 
@@ -219,6 +225,8 @@ public abstract class AbstractTransactio
        }
 
        private final ThreadLocal<AbstractTransactionContextImpl> existingTx = 
new ThreadLocal<>();
+       
+       private final AtomicBoolean closed = new AtomicBoolean();
 
        protected abstract AbstractTransactionContextImpl 
startTransaction(boolean readOnly);
 
@@ -291,4 +299,7 @@ public abstract class AbstractTransactio
 
        }
 
+       public void close() {
+               closed.set(true);
+       }
 }

Modified: 
aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/Activator.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/Activator.java?rev=1753813&r1=1753812&r2=1753813&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/Activator.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/Activator.java
 Fri Jul 22 16:53:02 2016
@@ -24,24 +24,35 @@ import java.util.Hashtable;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.transaction.control.TransactionControl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class Activator implements BundleActivator {
 
-private static final Logger logger = LoggerFactory.getLogger(Activator.class);
+       private static final Logger logger = 
LoggerFactory.getLogger(Activator.class);
+       private TransactionControlImpl service;
+       private ServiceRegistration<TransactionControl> reg;
        
        @Override
        public void start(BundleContext context) throws Exception {
                Dictionary<String, Object> properties = getProperties();
                logger.info("Registering a new Local TransactionControl service 
with properties {}", properties);
-               context.registerService(TransactionControl.class, 
-                               new TransactionControlImpl(), properties);
+               service = new TransactionControlImpl();
+               reg = context.registerService(TransactionControl.class, 
+                               service, properties);
        }
 
        @Override
-       public void stop(BundleContext context) throws Exception { }
+       public void stop(BundleContext context) throws Exception {
+               if(reg != null) {
+                       try {
+                               reg.unregister();
+                       } catch (IllegalStateException ise) { }
+               }
+               service.close();
+       }
 
        private Dictionary<String, Object> getProperties() {
                Dictionary<String, Object> props = new Hashtable<>();

Modified: 
aries/trunk/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/Activator.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/Activator.java?rev=1753813&r1=1753812&r2=1753813&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/Activator.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/Activator.java
 Fri Jul 22 16:53:02 2016
@@ -138,7 +138,7 @@ public class Activator implements Bundle
                                                                        
safeUnregister(newReg);
                                                                } 
                                                                if (impl != 
null) {
-                                                                       
impl.destroy();
+                                                                       
impl.close();
                                                                }
                                                        }
                                                        boolean cleanUp = true;
@@ -168,7 +168,7 @@ public class Activator implements Bundle
                        TransactionControlImpl toClose) {
                safeUnregister(toUnregister);
                if(toClose != null) {
-                       toClose.destroy();
+                       toClose.close();
                }
        }
        

Modified: 
aries/trunk/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/TransactionControlImpl.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/TransactionControlImpl.java?rev=1753813&r1=1753812&r2=1753813&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/TransactionControlImpl.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/TransactionControlImpl.java
 Fri Jul 22 16:53:02 2016
@@ -140,7 +140,7 @@ public class TransactionControlImpl exte
                                recoverableResources = null;
                        }
                } catch (Exception e) {
-                       destroy();
+                       close();
                        throw e;
                }
        }
@@ -200,7 +200,9 @@ public class TransactionControlImpl exte
                return o instanceof Integer ? (Integer) o : 
Integer.valueOf(o.toString());
        }
        
-       public void destroy() {
+       @Override
+       public void close() {
+               super.close();
                if(recoverableResources != null) {
                        recoverableResources.close();
                }

Modified: 
aries/trunk/tx-control/tx-control-service-xa/src/test/java/org/apache/aries/tx/control/service/xa/impl/TransactionLogTest.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-service-xa/src/test/java/org/apache/aries/tx/control/service/xa/impl/TransactionLogTest.java?rev=1753813&r1=1753812&r2=1753813&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-service-xa/src/test/java/org/apache/aries/tx/control/service/xa/impl/TransactionLogTest.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-service-xa/src/test/java/org/apache/aries/tx/control/service/xa/impl/TransactionLogTest.java
 Fri Jul 22 16:53:02 2016
@@ -107,7 +107,7 @@ public class TransactionLogTest {
        
        @After
        public void destroy() {
-               txControl.destroy();
+               txControl.close();
                try (Connection conn = dataSource.getConnection()) {
                        conn.createStatement().execute("shutdown immediately");
                } catch (SQLException e) {


Reply via email to