You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by ti...@apache.org on 2018/03/29 17:23:18 UTC
[aries-tx-control] branch master updated: Make sure that
DataSources are recreated when configuration-driven JPA providers lose and
re-acquire the EMFBuilder service
This is an automated email from the ASF dual-hosted git repository.
timothyjward pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/aries-tx-control.git
The following commit(s) were added to refs/heads/master by this push:
new ad0dec7 Make sure that DataSources are recreated when configuration-driven JPA providers lose and re-acquire the EMFBuilder service
ad0dec7 is described below
commit ad0dec7bf264cab86996bf98d951fec001e8ea92
Author: Tim Ward <ti...@apache.org>
AuthorDate: Thu Mar 29 16:53:56 2018 +0100
Make sure that DataSources are recreated when configuration-driven JPA providers lose and re-acquire the EMFBuilder service
---
.../control/itests/AbstractJPATransactionTest.java | 9 +-
.../aries/tx/control/itests/JPALifecycleTest.java | 25 ++++-
.../impl/AbstractManagedJPADataSourceSetup.java | 12 ++-
.../common/impl/AbstractManagedJPAEMFLocator.java | 17 ++-
.../impl/DelayedJPAEntityManagerProvider.java | 10 +-
.../impl/JPAEntityManagerProviderFactoryImpl.java | 2 +-
.../jpa/local/impl/LocalJPADataSourceSetup.java | 4 +-
.../control/jpa/local/impl/LocalJPAEMFLocator.java | 6 +-
.../local/impl/LocalJPAManagedServiceFactory.java | 2 +-
.../jpa/local/impl/LocalJPAEMFLocatorTest.java | 114 +++++++++++++++++++++
.../impl/JPAEntityManagerProviderFactoryImpl.java | 2 +-
.../control/jpa/xa/impl/XAJPADataSourceSetup.java | 6 +-
.../tx/control/jpa/xa/impl/XAJPAEMFLocator.java | 8 +-
.../jpa/xa/impl/XAJPAManagedServiceFactory.java | 2 +-
.../control/jpa/xa/impl/XAJPAEMFLocatorTest.java | 114 +++++++++++++++++++++
15 files changed, 304 insertions(+), 29 deletions(-)
diff --git a/tx-control-providers/jpa/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractJPATransactionTest.java b/tx-control-providers/jpa/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractJPATransactionTest.java
index 34a911f..a33c17e 100644
--- a/tx-control-providers/jpa/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractJPATransactionTest.java
+++ b/tx-control-providers/jpa/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractJPATransactionTest.java
@@ -94,12 +94,15 @@ public abstract class AbstractJPATransactionTest {
protected final List<ServiceTracker<?,?>> trackers = new ArrayList<>();
@Before
public void setUp() throws Exception {
-
- txControl = getService(TransactionControl.class, System.getProperty(TX_CONTROL_FILTER), 5000);
-
server = Server.createTcpServer("-tcpPort", "0");
server.start();
+ populateTxEntityManager();
+ }
+
+ protected void populateTxEntityManager() throws Exception {
+ txControl = getService(TransactionControl.class, System.getProperty(TX_CONTROL_FILTER), 5000);
+
String jdbcUrl = "jdbc:h2:tcp://127.0.0.1:" + server.getPort() + "/" + getRemoteDBPath();
boolean configuredProvider = isConfigured();
diff --git a/tx-control-providers/jpa/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/JPALifecycleTest.java b/tx-control-providers/jpa/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/JPALifecycleTest.java
index 23b825e..37b1603 100644
--- a/tx-control-providers/jpa/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/JPALifecycleTest.java
+++ b/tx-control-providers/jpa/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/JPALifecycleTest.java
@@ -48,8 +48,10 @@ 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.TransactionControl;
import org.osgi.service.transaction.control.TransactionException;
import org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory;
+import org.osgi.service.transaction.control.jpa.JPAEntityManagerProvider;
import org.osgi.service.transaction.control.jpa.JPAEntityManagerProviderFactory;
@RunWith(PaxExam.class)
@@ -99,18 +101,24 @@ public class JPALifecycleTest extends AbstractJPATransactionTest {
}
@Test
- public void testStopOfTxControlBundle() {
+ public void testStopOfTxControlBundle() throws Exception {
doBundleStoppingTest(b -> b.getSymbolicName().contains("tx-control-service"),
"The transaction control service is closed");
}
@Test
- public void testStopOfJPABundle() {
+ public void testStopOfJPABundle() throws Exception {
doBundleStoppingTest(b -> b.getSymbolicName().contains("tx-control-provider-jpa"),
"There was a problem getting hold of a database connection");
}
- private void doBundleStoppingTest(Predicate<Bundle> p, String exceptionMessage) {
+ @Test
+ public void testStopOfJPAService() throws Exception {
+ doBundleStoppingTest(b -> b.getSymbolicName().contains("org.apache.aries.jpa.container"),
+ "There was a problem getting hold of a database connection");
+ }
+
+ private void doBundleStoppingTest(Predicate<Bundle> p, String exceptionMessage) throws Exception {
Message m = new Message();
m.message = "Hello World";
txControl.required(() -> {em.persist(m); return null;});
@@ -149,6 +157,17 @@ public class JPALifecycleTest extends AbstractJPATransactionTest {
});
getService(JPAEntityManagerProviderFactory.class, 5000);
}
+ if(isConfigured()) {
+ txControl = getService(TransactionControl.class, 5000);
+ em = getService(JPAEntityManagerProvider.class, 5000).getResource(txControl);
+ } else {
+ populateTxEntityManager();
+ }
+
+ m.id = null;
+ txControl.required(() -> {em.persist(m); return null;});
+
+ assertEquals(m.message, txControl.notSupported(() -> em.find(Message.class, m.id).message));
}
@Test
diff --git a/tx-control-providers/jpa/tx-control-provider-jpa-common/src/main/java/org/apache/aries/tx/control/jpa/common/impl/AbstractManagedJPADataSourceSetup.java b/tx-control-providers/jpa/tx-control-provider-jpa-common/src/main/java/org/apache/aries/tx/control/jpa/common/impl/AbstractManagedJPADataSourceSetup.java
index 1324a39..d87ef91 100644
--- a/tx-control-providers/jpa/tx-control-provider-jpa-common/src/main/java/org/apache/aries/tx/control/jpa/common/impl/AbstractManagedJPADataSourceSetup.java
+++ b/tx-control-providers/jpa/tx-control-provider-jpa-common/src/main/java/org/apache/aries/tx/control/jpa/common/impl/AbstractManagedJPADataSourceSetup.java
@@ -27,6 +27,8 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
import org.apache.aries.tx.control.resource.common.impl.LifecycleAware;
import org.osgi.framework.BundleContext;
@@ -90,11 +92,11 @@ public abstract class AbstractManagedJPADataSourceSetup implements LifecycleAwar
DataSourceFactory service = context.getService(reference);
AbstractManagedJPAEMFLocator toReturn;
try {
- Map<String, Object> jpaProps = decorateJPAProperties(service,
+ Supplier<Map<String, Object>> jpaPropsProvider = () -> decorateJPAProperties(service,
unmodifiableMap(providerProperties), (Properties) jdbcProperties.clone(),
new HashMap<>(baseJPAProperties));
- toReturn = getManagedJPAEMFLocator(context, pid, jpaProps, providerProperties,
- () -> cleanupOnClose(jpaProps));
+ toReturn = getManagedJPAEMFLocator(context, pid, jpaPropsProvider, providerProperties,
+ jpaProps -> cleanupOnClose(jpaProps));
} catch (Exception e) {
LOG.error("An error occured creating the Resource provider for pid {}", pid, e);
return null;
@@ -106,12 +108,12 @@ public abstract class AbstractManagedJPADataSourceSetup implements LifecycleAwar
protected abstract Map<String, Object> decorateJPAProperties(DataSourceFactory dsf,
Map<String, Object> providerProperties, Properties jdbcProperties,
- Map<String, Object> jpaProperties) throws Exception;
+ Map<String, Object> jpaProperties);
protected abstract void cleanupOnClose(Map<String, Object> jpaProperties);
protected abstract AbstractManagedJPAEMFLocator getManagedJPAEMFLocator(BundleContext context, String pid,
- Map<String, Object> jpaProps, Map<String, Object> providerProperties, Runnable onClose) throws Exception;
+ Supplier<Map<String, Object>> jpaProps, Map<String, Object> providerProperties, Consumer<Map<String, Object>> onClose) throws Exception;
private void updateService(ServiceReference<DataSourceFactory> reference, AbstractManagedJPAEMFLocator locator) {
boolean setDsf;
diff --git a/tx-control-providers/jpa/tx-control-provider-jpa-common/src/main/java/org/apache/aries/tx/control/jpa/common/impl/AbstractManagedJPAEMFLocator.java b/tx-control-providers/jpa/tx-control-provider-jpa-common/src/main/java/org/apache/aries/tx/control/jpa/common/impl/AbstractManagedJPAEMFLocator.java
index b40b30d..acd27c0 100644
--- a/tx-control-providers/jpa/tx-control-provider-jpa-common/src/main/java/org/apache/aries/tx/control/jpa/common/impl/AbstractManagedJPAEMFLocator.java
+++ b/tx-control-providers/jpa/tx-control-provider-jpa-common/src/main/java/org/apache/aries/tx/control/jpa/common/impl/AbstractManagedJPAEMFLocator.java
@@ -31,7 +31,9 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Consumer;
import java.util.function.Function;
+import java.util.function.Supplier;
import javax.persistence.EntityManagerFactory;
@@ -59,9 +61,9 @@ public abstract class AbstractManagedJPAEMFLocator implements LifecycleAware,
private final BundleContext context;
private final String pid;
- private final Map<String, Object> jpaProperties;
+ private final Supplier<Map<String, Object>> jpaProperties;
private final Map<String, Object> providerProperties;
- private final Runnable onClose;
+ private final Consumer<Map<String, Object>> onClose;
private final ServiceTracker<EntityManagerFactoryBuilder, EntityManagerFactoryBuilder> emfBuilderTracker;
private final AtomicReference<EntityManagerFactoryBuilder> activeEMFB = new AtomicReference<>();
@@ -69,8 +71,8 @@ public abstract class AbstractManagedJPAEMFLocator implements LifecycleAware,
private final AtomicReference<ServiceRegistration<JPAEntityManagerProvider>> serviceReg = new AtomicReference<>();
- public AbstractManagedJPAEMFLocator(BundleContext context, String pid, Map<String, Object> jpaProperties,
- Map<String, Object> providerProperties, Runnable onClose) throws InvalidSyntaxException, ConfigurationException {
+ public AbstractManagedJPAEMFLocator(BundleContext context, String pid, Supplier<Map<String, Object>> jpaProperties,
+ Map<String, Object> providerProperties, Consumer<Map<String, Object>> onClose) throws InvalidSyntaxException, ConfigurationException {
this.context = context;
this.pid = pid;
this.jpaProperties = jpaProperties;
@@ -176,8 +178,10 @@ public abstract class AbstractManagedJPAEMFLocator implements LifecycleAware,
if (setEMFB) {
AbstractJPAEntityManagerProvider provider = null;
+ Map<String, Object> jpaProps = jpaProperties.get();
+ Runnable close = () -> onClose.accept(jpaProps);
try {
- provider = getResourceProvider(context, service, reference, jpaProperties, providerProperties, onClose);
+ provider = getResourceProvider(context, service, reference, jpaProps, providerProperties, close);
providerObject.set(provider);
ServiceRegistration<JPAEntityManagerProvider> reg = context
.registerService(JPAEntityManagerProvider.class, provider, getServiceProperties());
@@ -189,6 +193,9 @@ public abstract class AbstractManagedJPAEMFLocator implements LifecycleAware,
activeEMFB.compareAndSet(service, null);
if(provider != null) {
provider.close();
+ } else {
+ // Make sure that we don't leak the DataSource
+ close.run();
}
}
diff --git a/tx-control-providers/jpa/tx-control-provider-jpa-common/src/main/java/org/apache/aries/tx/control/jpa/common/impl/DelayedJPAEntityManagerProvider.java b/tx-control-providers/jpa/tx-control-provider-jpa-common/src/main/java/org/apache/aries/tx/control/jpa/common/impl/DelayedJPAEntityManagerProvider.java
index 71a70f5..d3245f1 100644
--- a/tx-control-providers/jpa/tx-control-provider-jpa-common/src/main/java/org/apache/aries/tx/control/jpa/common/impl/DelayedJPAEntityManagerProvider.java
+++ b/tx-control-providers/jpa/tx-control-provider-jpa-common/src/main/java/org/apache/aries/tx/control/jpa/common/impl/DelayedJPAEntityManagerProvider.java
@@ -31,14 +31,18 @@ public class DelayedJPAEntityManagerProvider extends AbstractJPAEntityManagerPro
private final ThreadLocal<TransactionControl> commonStore = new ThreadLocal<>();
+ private final Runnable unusedClose;
+
private AbstractJPAEntityManagerProvider delegate;
private boolean closed;
+
public DelayedJPAEntityManagerProvider(Function<ThreadLocal<TransactionControl>,
- AbstractJPAEntityManagerProvider> wireToTransactionControl) {
+ AbstractJPAEntityManagerProvider> wireToTransactionControl, Runnable unusedClose) {
super(null, null);
this.wireToTransactionControl = wireToTransactionControl;
+ this.unusedClose = unusedClose;
}
@Override
@@ -62,11 +66,15 @@ public class DelayedJPAEntityManagerProvider extends AbstractJPAEntityManagerPro
closed = true;
toClose = delegate;
delegate = null;
+ } else {
+ return;
}
}
if(toClose != null) {
toClose.close();
+ } else {
+ unusedClose.run();
}
}
diff --git a/tx-control-providers/jpa/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/JPAEntityManagerProviderFactoryImpl.java b/tx-control-providers/jpa/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/JPAEntityManagerProviderFactoryImpl.java
index d02a3b3..b93d7e7 100644
--- a/tx-control-providers/jpa/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/JPAEntityManagerProviderFactoryImpl.java
+++ b/tx-control-providers/jpa/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/JPAEntityManagerProviderFactoryImpl.java
@@ -108,7 +108,7 @@ public class JPAEntityManagerProviderFactoryImpl implements InternalJPAEntityMan
emf.close();
});
};
- return new DelayedJPAEntityManagerProvider(create);
+ return new DelayedJPAEntityManagerProvider(create, () -> {});
}
public AbstractJPAEntityManagerProvider getProviderFor(EntityManagerFactoryBuilder emfb,
diff --git a/tx-control-providers/jpa/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/LocalJPADataSourceSetup.java b/tx-control-providers/jpa/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/LocalJPADataSourceSetup.java
index c77f38b..f831e57 100644
--- a/tx-control-providers/jpa/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/LocalJPADataSourceSetup.java
+++ b/tx-control-providers/jpa/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/LocalJPADataSourceSetup.java
@@ -26,6 +26,8 @@ import static org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFa
import java.sql.SQLException;
import java.util.Map;
import java.util.Properties;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
import javax.sql.DataSource;
@@ -81,7 +83,7 @@ public class LocalJPADataSourceSetup extends AbstractManagedJPADataSourceSetup {
@Override
protected AbstractManagedJPAEMFLocator getManagedJPAEMFLocator(BundleContext context, String pid,
- Map<String, Object> jpaProps, Map<String, Object> providerProperties, Runnable onClose)
+ Supplier<Map<String, Object>> jpaProps, Map<String, Object> providerProperties, Consumer<Map<String, Object>> onClose)
throws InvalidSyntaxException, ConfigurationException {
return new LocalJPAEMFLocator(context, pid, jpaProps, providerProperties, onClose);
}
diff --git a/tx-control-providers/jpa/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/LocalJPAEMFLocator.java b/tx-control-providers/jpa/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/LocalJPAEMFLocator.java
index ad2364b..990c44f 100644
--- a/tx-control-providers/jpa/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/LocalJPAEMFLocator.java
+++ b/tx-control-providers/jpa/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/LocalJPAEMFLocator.java
@@ -19,6 +19,8 @@
package org.apache.aries.tx.control.jpa.local.impl;
import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
import org.apache.aries.tx.control.jpa.common.impl.AbstractJPAEntityManagerProvider;
import org.apache.aries.tx.control.jpa.common.impl.AbstractManagedJPAEMFLocator;
@@ -30,8 +32,8 @@ import org.osgi.service.jpa.EntityManagerFactoryBuilder;
public class LocalJPAEMFLocator extends AbstractManagedJPAEMFLocator {
- public LocalJPAEMFLocator(BundleContext context, String pid, Map<String, Object> jpaProperties,
- Map<String, Object> providerProperties, Runnable onClose) throws InvalidSyntaxException, ConfigurationException {
+ public LocalJPAEMFLocator(BundleContext context, String pid, Supplier<Map<String, Object>> jpaProperties,
+ Map<String, Object> providerProperties, Consumer<Map<String, Object>> onClose) throws InvalidSyntaxException, ConfigurationException {
super(context, pid, jpaProperties, providerProperties, onClose);
}
diff --git a/tx-control-providers/jpa/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/LocalJPAManagedServiceFactory.java b/tx-control-providers/jpa/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/LocalJPAManagedServiceFactory.java
index e5df72d..3730208 100644
--- a/tx-control-providers/jpa/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/LocalJPAManagedServiceFactory.java
+++ b/tx-control-providers/jpa/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/LocalJPAManagedServiceFactory.java
@@ -50,7 +50,7 @@ public class LocalJPAManagedServiceFactory extends AbstractJPAManagedServiceFact
@Override
protected AbstractManagedJPAEMFLocator emfTracking(BundleContext context, String pid, Map<String, Object> properties,
Map<String, Object> jpaProps) throws InvalidSyntaxException, ConfigurationException {
- return new LocalJPAEMFLocator(context, pid, jpaProps, properties, null);
+ return new LocalJPAEMFLocator(context, pid, () -> jpaProps, properties, null);
}
@Override
diff --git a/tx-control-providers/jpa/tx-control-provider-jpa-local/src/test/java/org/apache/aries/tx/control/jpa/local/impl/LocalJPAEMFLocatorTest.java b/tx-control-providers/jpa/tx-control-provider-jpa-local/src/test/java/org/apache/aries/tx/control/jpa/local/impl/LocalJPAEMFLocatorTest.java
new file mode 100644
index 0000000..099e170
--- /dev/null
+++ b/tx-control-providers/jpa/tx-control-provider-jpa-local/src/test/java/org/apache/aries/tx/control/jpa/local/impl/LocalJPAEMFLocatorTest.java
@@ -0,0 +1,114 @@
+package org.apache.aries.tx.control.jpa.local.impl;
+
+import static java.util.Collections.newSetFromMap;
+import static java.util.Collections.singletonMap;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.anyMapOf;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.when;
+import static org.osgi.framework.FrameworkUtil.createFilter;
+
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Semaphore;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+import javax.persistence.EntityManagerFactory;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.jpa.EntityManagerFactoryBuilder;
+
+@RunWith(MockitoJUnitRunner.class)
+public class LocalJPAEMFLocatorTest {
+
+ private static final String PID = "some.pid";
+ private static final String UNIT_NAME = "foo";
+
+ private final Set<Map<String, Object>> maps = newSetFromMap(new IdentityHashMap<>());
+
+ private final Semaphore getJDBCSem = new Semaphore(0);
+
+ private final Semaphore closeSem = new Semaphore(0);
+
+ @Mock
+ BundleContext ctx;
+
+ @Mock
+ ServiceReference<EntityManagerFactoryBuilder> ref;
+
+ @Mock
+ EntityManagerFactoryBuilder emfb;
+
+ @Mock
+ EntityManagerFactory emf;
+
+ Supplier<Map<String, Object>> propertiesProvider;
+
+ Consumer<Map<String, Object>> closeHandler;
+
+ private LocalJPAEMFLocator locator;
+
+ @Before
+ public void setUp() throws InvalidSyntaxException, ConfigurationException {
+
+ propertiesProvider = () -> {
+ Map<String, Object> m = new HashMap<>();
+ maps.add(m);
+ getJDBCSem.release();
+ return m;
+ };
+
+ closeHandler = m -> {
+ if(maps.remove(m)) {
+ closeSem.release();
+ }
+ };
+
+ when(emfb.createEntityManagerFactory(anyMapOf(String.class, Object.class)))
+ .thenReturn(emf);
+
+ when(ctx.getService(ref)).thenReturn(emfb);
+
+ when(ctx.createFilter(anyString()))
+ .then(i -> createFilter(i.getArguments()[0].toString()));
+
+ locator = new LocalJPAEMFLocator(ctx, PID, propertiesProvider,
+ singletonMap("osgi.unit.name", UNIT_NAME), closeHandler);
+ }
+
+ @Test
+ public void testEMFAddedRemovedThenAddedAgain() {
+
+ locator.addingService(ref);
+
+ assertEquals(1, getJDBCSem.availablePermits());
+ assertEquals(0, closeSem.availablePermits());
+
+ locator.removedService(ref, emfb);
+
+ assertEquals(1, getJDBCSem.availablePermits());
+ assertEquals(1, closeSem.availablePermits());
+
+ locator.addingService(ref);
+
+ assertEquals(2, getJDBCSem.availablePermits());
+ assertEquals(1, closeSem.availablePermits());
+
+ locator.removedService(ref, emfb);
+
+ assertEquals(2, getJDBCSem.availablePermits());
+ assertEquals(2, closeSem.availablePermits());
+ }
+
+}
diff --git a/tx-control-providers/jpa/tx-control-provider-jpa-xa/src/main/java/org/apache/aries/tx/control/jpa/xa/impl/JPAEntityManagerProviderFactoryImpl.java b/tx-control-providers/jpa/tx-control-provider-jpa-xa/src/main/java/org/apache/aries/tx/control/jpa/xa/impl/JPAEntityManagerProviderFactoryImpl.java
index c171faf..a9094b5 100644
--- a/tx-control-providers/jpa/tx-control-provider-jpa-xa/src/main/java/org/apache/aries/tx/control/jpa/xa/impl/JPAEntityManagerProviderFactoryImpl.java
+++ b/tx-control-providers/jpa/tx-control-provider-jpa-xa/src/main/java/org/apache/aries/tx/control/jpa/xa/impl/JPAEntityManagerProviderFactoryImpl.java
@@ -104,7 +104,7 @@ public class JPAEntityManagerProviderFactoryImpl implements InternalJPAEntityMan
create = handleNormalDataSource(emfb, resourceProviderPropsToUse, jpaPropsToUse);
}
- return new DelayedJPAEntityManagerProvider(create);
+ return new DelayedJPAEntityManagerProvider(create, () -> {});
}
private Function<ThreadLocal<TransactionControl>, AbstractJPAEntityManagerProvider> handleJDBCResourceProvider(
diff --git a/tx-control-providers/jpa/tx-control-provider-jpa-xa/src/main/java/org/apache/aries/tx/control/jpa/xa/impl/XAJPADataSourceSetup.java b/tx-control-providers/jpa/tx-control-provider-jpa-xa/src/main/java/org/apache/aries/tx/control/jpa/xa/impl/XAJPADataSourceSetup.java
index e6cb6cf..b773616 100644
--- a/tx-control-providers/jpa/tx-control-provider-jpa-xa/src/main/java/org/apache/aries/tx/control/jpa/xa/impl/XAJPADataSourceSetup.java
+++ b/tx-control-providers/jpa/tx-control-provider-jpa-xa/src/main/java/org/apache/aries/tx/control/jpa/xa/impl/XAJPADataSourceSetup.java
@@ -25,6 +25,8 @@ import static org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFa
import java.sql.SQLException;
import java.util.Map;
import java.util.Properties;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
import javax.sql.DataSource;
@@ -51,7 +53,7 @@ public class XAJPADataSourceSetup extends AbstractManagedJPADataSourceSetup {
@Override
protected Map<String, Object> decorateJPAProperties(DataSourceFactory dsf, Map<String, Object> providerProperties,
- Properties jdbcProperties, Map<String, Object> jpaProperties) throws Exception {
+ Properties jdbcProperties, Map<String, Object> jpaProperties) {
DataSource unpooled;
try {
if (toBoolean(providerProperties, USE_DRIVER, false)) {
@@ -81,7 +83,7 @@ public class XAJPADataSourceSetup extends AbstractManagedJPADataSourceSetup {
@Override
protected AbstractManagedJPAEMFLocator getManagedJPAEMFLocator(BundleContext context, String pid,
- Map<String, Object> jpaProps, Map<String, Object> providerProperties, Runnable onClose) throws Exception {
+ Supplier<Map<String, Object>> jpaProps, Map<String, Object> providerProperties, Consumer<Map<String, Object>> onClose) throws Exception {
return new XAJPAEMFLocator(context, pid, jpaProps, providerProperties, onClose);
}
}
\ No newline at end of file
diff --git a/tx-control-providers/jpa/tx-control-provider-jpa-xa/src/main/java/org/apache/aries/tx/control/jpa/xa/impl/XAJPAEMFLocator.java b/tx-control-providers/jpa/tx-control-provider-jpa-xa/src/main/java/org/apache/aries/tx/control/jpa/xa/impl/XAJPAEMFLocator.java
index 20686d2..12f2ac6 100644
--- a/tx-control-providers/jpa/tx-control-provider-jpa-xa/src/main/java/org/apache/aries/tx/control/jpa/xa/impl/XAJPAEMFLocator.java
+++ b/tx-control-providers/jpa/tx-control-provider-jpa-xa/src/main/java/org/apache/aries/tx/control/jpa/xa/impl/XAJPAEMFLocator.java
@@ -20,6 +20,8 @@ package org.apache.aries.tx.control.jpa.xa.impl;
import java.util.HashMap;
import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
import org.apache.aries.tx.control.jpa.common.impl.AbstractJPAEntityManagerProvider;
import org.apache.aries.tx.control.jpa.common.impl.AbstractManagedJPAEMFLocator;
@@ -32,8 +34,8 @@ import org.osgi.service.jpa.EntityManagerFactoryBuilder;
public class XAJPAEMFLocator extends AbstractManagedJPAEMFLocator {
- public XAJPAEMFLocator(BundleContext context, String pid, Map<String, Object> jpaProperties,
- Map<String, Object> providerProperties, Runnable onClose) throws InvalidSyntaxException, ConfigurationException {
+ public XAJPAEMFLocator(BundleContext context, String pid, Supplier<Map<String, Object>> jpaProperties,
+ Map<String, Object> providerProperties, Consumer<Map<String, Object>> onClose) throws InvalidSyntaxException, ConfigurationException {
super(context, pid, jpaProperties, providerProperties, onClose);
}
@@ -48,6 +50,6 @@ public class XAJPAEMFLocator extends AbstractManagedJPAEMFLocator {
return new DelayedJPAEntityManagerProvider(t -> {
return new JPAEntityManagerProviderFactoryImpl(context).getProviderFor(service,
jpaProps, providerProps, t, onClose);
- });
+ }, onClose);
}
}
\ No newline at end of file
diff --git a/tx-control-providers/jpa/tx-control-provider-jpa-xa/src/main/java/org/apache/aries/tx/control/jpa/xa/impl/XAJPAManagedServiceFactory.java b/tx-control-providers/jpa/tx-control-provider-jpa-xa/src/main/java/org/apache/aries/tx/control/jpa/xa/impl/XAJPAManagedServiceFactory.java
index bb70f5d..c17c744 100644
--- a/tx-control-providers/jpa/tx-control-provider-jpa-xa/src/main/java/org/apache/aries/tx/control/jpa/xa/impl/XAJPAManagedServiceFactory.java
+++ b/tx-control-providers/jpa/tx-control-provider-jpa-xa/src/main/java/org/apache/aries/tx/control/jpa/xa/impl/XAJPAManagedServiceFactory.java
@@ -50,7 +50,7 @@ public class XAJPAManagedServiceFactory extends AbstractJPAManagedServiceFactory
@Override
protected AbstractManagedJPAEMFLocator emfTracking(BundleContext context, String pid, Map<String, Object> properties,
Map<String, Object> jpaProps) throws InvalidSyntaxException, ConfigurationException {
- return new XAJPAEMFLocator(context, pid, jpaProps, properties, null);
+ return new XAJPAEMFLocator(context, pid, () -> jpaProps, properties, null);
}
@Override
diff --git a/tx-control-providers/jpa/tx-control-provider-jpa-xa/src/test/java/org/apache/aries/tx/control/jpa/xa/impl/XAJPAEMFLocatorTest.java b/tx-control-providers/jpa/tx-control-provider-jpa-xa/src/test/java/org/apache/aries/tx/control/jpa/xa/impl/XAJPAEMFLocatorTest.java
new file mode 100644
index 0000000..cc0f546
--- /dev/null
+++ b/tx-control-providers/jpa/tx-control-provider-jpa-xa/src/test/java/org/apache/aries/tx/control/jpa/xa/impl/XAJPAEMFLocatorTest.java
@@ -0,0 +1,114 @@
+package org.apache.aries.tx.control.jpa.xa.impl;
+
+import static java.util.Collections.newSetFromMap;
+import static java.util.Collections.singletonMap;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.anyMapOf;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.when;
+import static org.osgi.framework.FrameworkUtil.createFilter;
+
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Semaphore;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+import javax.persistence.EntityManagerFactory;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.jpa.EntityManagerFactoryBuilder;
+
+@RunWith(MockitoJUnitRunner.class)
+public class XAJPAEMFLocatorTest {
+
+ private static final String PID = "some.pid";
+ private static final String UNIT_NAME = "foo";
+
+ private final Set<Map<String, Object>> maps = newSetFromMap(new IdentityHashMap<>());
+
+ private final Semaphore getJDBCSem = new Semaphore(0);
+
+ private final Semaphore closeSem = new Semaphore(0);
+
+ @Mock
+ BundleContext ctx;
+
+ @Mock
+ ServiceReference<EntityManagerFactoryBuilder> ref;
+
+ @Mock
+ EntityManagerFactoryBuilder emfb;
+
+ @Mock
+ EntityManagerFactory emf;
+
+ Supplier<Map<String, Object>> propertiesProvider;
+
+ Consumer<Map<String, Object>> closeHandler;
+
+ private XAJPAEMFLocator locator;
+
+ @Before
+ public void setUp() throws InvalidSyntaxException, ConfigurationException {
+
+ propertiesProvider = () -> {
+ Map<String, Object> m = new HashMap<>();
+ maps.add(m);
+ getJDBCSem.release();
+ return m;
+ };
+
+ closeHandler = m -> {
+ if(maps.remove(m)) {
+ closeSem.release();
+ }
+ };
+
+ when(emfb.createEntityManagerFactory(anyMapOf(String.class, Object.class)))
+ .thenReturn(emf);
+
+ when(ctx.getService(ref)).thenReturn(emfb);
+
+ when(ctx.createFilter(anyString()))
+ .then(i -> createFilter(i.getArguments()[0].toString()));
+
+ locator = new XAJPAEMFLocator(ctx, PID, propertiesProvider,
+ singletonMap("osgi.unit.name", UNIT_NAME), closeHandler);
+ }
+
+ @Test
+ public void testEMFAddedRemovedThenAddedAgain() {
+
+ locator.addingService(ref);
+
+ assertEquals(1, getJDBCSem.availablePermits());
+ assertEquals(0, closeSem.availablePermits());
+
+ locator.removedService(ref, emfb);
+
+ assertEquals(1, getJDBCSem.availablePermits());
+ assertEquals(1, closeSem.availablePermits());
+
+ locator.addingService(ref);
+
+ assertEquals(2, getJDBCSem.availablePermits());
+ assertEquals(1, closeSem.availablePermits());
+
+ locator.removedService(ref, emfb);
+
+ assertEquals(2, getJDBCSem.availablePermits());
+ assertEquals(2, closeSem.availablePermits());
+ }
+
+}
--
To stop receiving notification emails like this one, please contact
timothyjward@apache.org.