[ARIES-1585] Add tests for JDBC connection cleanup, and fix the leaks!
git-svn-id: https://svn.apache.org/repos/asf/aries/trunk@1753813 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractTransactionTest.java b/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractTransactionTest.java
index e7e340c..ef5542c 100644
--- a/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractTransactionTest.java
+++ b/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractTransactionTest.java
@@ -76,7 +76,7 @@
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 @@
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 @@
});
}
- 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 @@
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 @@
@After
public void tearDown() {
- txControl.required(() -> connection.createStatement()
- .execute("DROP TABLE TEST_TABLE"));
-
-
- if(System.getProperties().containsKey(CONFIGURED_PROVIDER_PROPERTY)) {
+ if(isConfigured()) {
clearConfiguration();
}
diff --git a/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ConnectionLifecycleTest.java b/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ConnectionLifecycleTest.java
new file mode 100644
index 0000000..5fa4101
--- /dev/null
+++ b/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ConnectionLifecycleTest.java
@@ -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());
+ }
+ }
+}
diff --git a/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/AbstractJDBCConnectionProvider.java b/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/AbstractJDBCConnectionProvider.java
new file mode 100644
index 0000000..181a2a1
--- /dev/null
+++ b/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/AbstractJDBCConnectionProvider.java
@@ -0,0 +1,55 @@
+/*
+ * 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.jdbc.common.impl;
+
+import java.sql.Connection;
+
+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 abstract class AbstractJDBCConnectionProvider implements JDBCConnectionProvider {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractJDBCConnectionProvider.class);
+
+ protected final DataSource dataSource;
+
+ public AbstractJDBCConnectionProvider(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ @Override
+ 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);
+ }
+ }
+ }
+}
diff --git a/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/InternalJDBCConnectionProviderFactory.java b/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/InternalJDBCConnectionProviderFactory.java
new file mode 100644
index 0000000..060dbcc
--- /dev/null
+++ b/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/InternalJDBCConnectionProviderFactory.java
@@ -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);
+
+}
diff --git a/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/JDBCConnectionProviderFactoryServiceFactory.java b/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/JDBCConnectionProviderFactoryServiceFactory.java
new file mode 100644
index 0000000..f577907
--- /dev/null
+++ b/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/JDBCConnectionProviderFactoryServiceFactory.java
@@ -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();
+}
diff --git a/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/ResourceTrackingJDBCConnectionProviderFactory.java b/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/ResourceTrackingJDBCConnectionProviderFactory.java
new file mode 100644
index 0000000..5b87f07
--- /dev/null
+++ b/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/ResourceTrackingJDBCConnectionProviderFactory.java
@@ -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
diff --git a/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/Activator.java b/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/Activator.java
index 52693c6..993dbe4 100644
--- a/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/Activator.java
+++ b/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/Activator.java
@@ -23,6 +23,8 @@
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 @@
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() {
diff --git a/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderFactoryImpl.java b/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderFactoryImpl.java
index b2bc786..4aca90d 100644
--- a/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderFactoryImpl.java
+++ b/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderFactoryImpl.java
@@ -32,19 +32,20 @@
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 @@
}
@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 @@
}
@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 @@
}
@Override
- public JDBCConnectionProvider getProviderFor(XADataSource ds, Map<String, Object> resourceProviderProperties) {
+ public AbstractJDBCConnectionProvider getProviderFor(XADataSource ds, Map<String, Object> resourceProviderProperties) {
checkEnlistment(resourceProviderProperties);
DataSource unpooled;
diff --git a/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderImpl.java b/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderImpl.java
index 996f12a..75b5d73 100644
--- a/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderImpl.java
+++ b/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/JDBCConnectionProviderImpl.java
@@ -23,18 +23,16 @@
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 @@
throws TransactionException {
return new TxContextBindingConnection(txControl, dataSource , uuid);
}
-
}
diff --git a/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/ManagedServiceFactoryImpl.java b/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/ManagedServiceFactoryImpl.java
index db09ac2..f6504a6 100644
--- a/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/ManagedServiceFactoryImpl.java
+++ b/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/ManagedServiceFactoryImpl.java
@@ -45,6 +45,7 @@
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 @@
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 @@
}
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 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 @@
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);
}
}
}
diff --git a/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/Activator.java b/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/Activator.java
index dcfa6cf..56754b8 100644
--- a/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/Activator.java
+++ b/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/Activator.java
@@ -23,6 +23,8 @@
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 @@
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);
diff --git a/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderFactoryImpl.java b/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderFactoryImpl.java
index 28204db..9628031 100644
--- a/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderFactoryImpl.java
+++ b/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderFactoryImpl.java
@@ -33,10 +33,10 @@
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 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 @@
}
@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 @@
}
@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 @@
}
@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);
diff --git a/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderImpl.java b/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderImpl.java
index 9adc9af..f036f0f 100644
--- a/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderImpl.java
+++ b/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderImpl.java
@@ -23,16 +23,14 @@
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 JDBCConnectionProviderImpl(DataSource dataSource, boolean xaEnabled,
boolean localEnabled, String recoveryIdentifier) {
- this.dataSource = dataSource;
+ super(dataSource);
this.xaEnabled = xaEnabled;
this.localEnabled = localEnabled;
this.recoveryIdentifier = recoveryIdentifier;
diff --git a/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/ManagedServiceFactoryImpl.java b/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/ManagedServiceFactoryImpl.java
index aa10760..80826c2 100644
--- a/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/ManagedServiceFactoryImpl.java
+++ b/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/ManagedServiceFactoryImpl.java
@@ -47,6 +47,7 @@
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 @@
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 @@
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 @@
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 @@
}
safeUnregister(reg);
safeUnregister(reg2);
+ safeClose(provider);
}
}
return service;
@@ -262,6 +270,16 @@
}
}
+ 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 @@
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();
diff --git a/tx-control/tx-control-service-common/src/main/java/org/apache/aries/tx/control/service/common/impl/AbstractTransactionControlImpl.java b/tx-control/tx-control-service-common/src/main/java/org/apache/aries/tx/control/service/common/impl/AbstractTransactionControlImpl.java
index 00b89df..7149969 100644
--- a/tx-control/tx-control-service-common/src/main/java/org/apache/aries/tx/control/service/common/impl/AbstractTransactionControlImpl.java
+++ b/tx-control/tx-control-service-common/src/main/java/org/apache/aries/tx/control/service/common/impl/AbstractTransactionControlImpl.java
@@ -26,6 +26,7 @@
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 @@
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 @@
@Override
public <T> T required(Callable<T> work)
throws TransactionException, TransactionRolledBackException {
- checkExceptions();
+ checkValid();
boolean endTransaction = false;
@@ -85,7 +91,7 @@
@Override
public <T> T requiresNew(Callable<T> work)
throws TransactionException, TransactionRolledBackException {
- checkExceptions();
+ checkValid();
AbstractTransactionContextImpl existingTran = existingTx.get();
try {
@@ -100,7 +106,7 @@
@Override
public <T> T supports(Callable<T> work) throws TransactionException {
- checkExceptions();
+ checkValid();
boolean endTransaction = false;
@@ -124,7 +130,7 @@
@Override
public <T> T notSupported(Callable<T> work)
throws TransactionException {
- checkExceptions();
+ checkValid();
boolean endTransaction = false;
@@ -219,6 +225,8 @@
}
private final ThreadLocal<AbstractTransactionContextImpl> existingTx = new ThreadLocal<>();
+
+ private final AtomicBoolean closed = new AtomicBoolean();
protected abstract AbstractTransactionContextImpl startTransaction(boolean readOnly);
@@ -291,4 +299,7 @@
}
+ public void close() {
+ closed.set(true);
+ }
}
diff --git a/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/Activator.java b/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/Activator.java
index 02ee5b8..9492c68 100644
--- a/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/Activator.java
+++ b/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/Activator.java
@@ -24,24 +24,35 @@
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<>();
diff --git a/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/Activator.java b/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/Activator.java
index 25d1274..e66ba4f 100644
--- a/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/Activator.java
+++ b/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/Activator.java
@@ -138,7 +138,7 @@
safeUnregister(newReg);
}
if (impl != null) {
- impl.destroy();
+ impl.close();
}
}
boolean cleanUp = true;
@@ -168,7 +168,7 @@
TransactionControlImpl toClose) {
safeUnregister(toUnregister);
if(toClose != null) {
- toClose.destroy();
+ toClose.close();
}
}
diff --git a/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/TransactionControlImpl.java b/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/TransactionControlImpl.java
index c4db2ec..a5f62da 100644
--- a/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/TransactionControlImpl.java
+++ b/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/TransactionControlImpl.java
@@ -140,7 +140,7 @@
recoverableResources = null;
}
} catch (Exception e) {
- destroy();
+ close();
throw e;
}
}
@@ -200,7 +200,9 @@
return o instanceof Integer ? (Integer) o : Integer.valueOf(o.toString());
}
- public void destroy() {
+ @Override
+ public void close() {
+ super.close();
if(recoverableResources != null) {
recoverableResources.close();
}
diff --git a/tx-control/tx-control-service-xa/src/test/java/org/apache/aries/tx/control/service/xa/impl/TransactionLogTest.java b/tx-control/tx-control-service-xa/src/test/java/org/apache/aries/tx/control/service/xa/impl/TransactionLogTest.java
index b1487f8..6de4bae 100644
--- a/tx-control/tx-control-service-xa/src/test/java/org/apache/aries/tx/control/service/xa/impl/TransactionLogTest.java
+++ b/tx-control/tx-control-service-xa/src/test/java/org/apache/aries/tx/control/service/xa/impl/TransactionLogTest.java
@@ -107,7 +107,7 @@
@After
public void destroy() {
- txControl.destroy();
+ txControl.close();
try (Connection conn = dataSource.getConnection()) {
conn.createStatement().execute("shutdown immediately");
} catch (SQLException e) {