Allow Builder clients to close the EMF, but not service clients
diff --git a/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/AriesEntityManagerFactoryBuilder.java b/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/AriesEntityManagerFactoryBuilder.java
index cdeb31d..56ad2c2 100644
--- a/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/AriesEntityManagerFactoryBuilder.java
+++ b/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/AriesEntityManagerFactoryBuilder.java
@@ -18,6 +18,9 @@
*/
package org.apache.aries.jpa.container.impl;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
@@ -163,7 +166,22 @@
closeEMF();
- return createAndPublishEMF(processedProperties);
+ final EntityManagerFactory toUse = createAndPublishEMF(processedProperties);
+
+ return (EntityManagerFactory) Proxy.newProxyInstance(getClass().getClassLoader(),
+ new Class<?>[] {EntityManagerFactory.class}, new InvocationHandler() {
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if("close".equals(method.getName())) {
+ // Close the registration as per the spec
+ closeEMF();
+ // Do not delegate as the closeEMF call already closes
+ return null;
+ }
+ return method.invoke(toUse, args);
+ }
+ });
}
public String getPUName() {
@@ -336,7 +354,7 @@
}
}
- EntityManagerFactory tmp = provider.createContainerEntityManagerFactory(persistenceUnit, overrides);
+ final EntityManagerFactory tmp = provider.createContainerEntityManagerFactory(persistenceUnit, overrides);
boolean register = false;
synchronized (this) {
if(emf == null) {
@@ -349,7 +367,20 @@
Dictionary<String, Object> props = createBuilderProperties(overrides);
BundleContext uctx = bundle.getBundleContext();
ServiceRegistration<EntityManagerFactory> tmpReg =
- uctx.registerService(EntityManagerFactory.class, emf, props);
+ uctx.registerService(EntityManagerFactory.class,
+ (EntityManagerFactory) Proxy.newProxyInstance(getClass().getClassLoader(),
+ new Class<?>[] {EntityManagerFactory.class},
+ new InvocationHandler() {
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if("close".equals(method.getName())) {
+ // Ignore close as per the spec
+ return null;
+ }
+ return method.invoke(tmp, args);
+ }
+ }), props);
synchronized (this) {
if(emf == tmp) {
diff --git a/jpa-container/src/test/java/org/apache/aries/jpa/container/impl/PropsConfigurationTest.java b/jpa-container/src/test/java/org/apache/aries/jpa/container/impl/PropsConfigurationTest.java
index 20cd2b9..b0f1f7e 100644
--- a/jpa-container/src/test/java/org/apache/aries/jpa/container/impl/PropsConfigurationTest.java
+++ b/jpa-container/src/test/java/org/apache/aries/jpa/container/impl/PropsConfigurationTest.java
@@ -29,6 +29,7 @@
import static org.mockito.Matchers.anyMap;
import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
@@ -53,6 +54,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
@@ -140,7 +142,7 @@
}
});
- when(punitContext.registerService(eq(EntityManagerFactory.class), eq(emf),
+ when(punitContext.registerService(eq(EntityManagerFactory.class), any(EntityManagerFactory.class),
any(Dictionary.class))).thenReturn(emfReg);
when(emf.isOpen()).thenReturn(true);
@@ -234,7 +236,7 @@
verify(punit).setNonJtaDataSource(ds);
verify(punitContext).registerService(eq(EntityManagerFactory.class),
- eq(emf), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")));
+ any(EntityManagerFactory.class), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")));
emfb.close();
@@ -262,7 +264,7 @@
verify(punitContext).registerService(eq(EntityManagerFactory.class),
- eq(emf), and(argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")),
+ any(EntityManagerFactory.class), and(argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")),
argThat(servicePropsMatcher("hibernate.hbm2ddl.auto", "create-drop"))));
emfb.close();
@@ -291,7 +293,7 @@
verify(punit).setJtaDataSource(ds);
verify(punitContext).registerService(eq(EntityManagerFactory.class),
- eq(emf), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")));
+ any(EntityManagerFactory.class), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")));
emfb.close();
verify(emfReg).unregister();
@@ -319,7 +321,8 @@
verify(punit).setJtaDataSource(ds);
verify(punitContext).registerService(eq(EntityManagerFactory.class),
- eq(emf), and(and(argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")),
+ any(EntityManagerFactory.class),
+ and(and(argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")),
argThat(servicePropsMatcher("javax.persistence.jdbc.user", JDBC_USER))),
not(argThat(servicePropsMatcher("javax.persistence.jdbc.password", JDBC_PASSWORD)))));
@@ -362,7 +365,7 @@
verify(punit).setJtaDataSource(ds);
verify(punitContext).registerService(eq(EntityManagerFactory.class),
- eq(emf), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")));
+ any(EntityManagerFactory.class), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")));
try {
@@ -394,7 +397,7 @@
verify(punit).setJtaDataSource(ds);
verify(punitContext).registerService(eq(EntityManagerFactory.class),
- eq(emf), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")));
+ any(EntityManagerFactory.class), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")));
emfb.close();
}
@@ -419,7 +422,63 @@
verify(punit).setNonJtaDataSource(ds);
verify(punitContext).registerService(eq(EntityManagerFactory.class),
- eq(emf), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")));
+ any(EntityManagerFactory.class), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")));
+
+ emfb.close();
+ }
+
+ @Test
+ public void testReturnedEmfClose() throws InvalidSyntaxException, ConfigurationException {
+
+ when(provider.createContainerEntityManagerFactory(eq(punit),
+ eq(singletonMap(PersistenceUnitTransactionType.class.getName(), JTA))))
+ .thenReturn(emf);
+
+ Map<String, Object> props = new Hashtable<String, Object>();
+ props.put("javax.persistence.dataSource", ds);
+
+ AriesEntityManagerFactoryBuilder emfb = new AriesEntityManagerFactoryBuilder(
+ containerContext, provider, punit);
+
+ EntityManagerFactory returnedEMF = emfb.createEntityManagerFactory(props);
+
+
+ verify(punit).setNonJtaDataSource(ds);
+ verify(punitContext).registerService(eq(EntityManagerFactory.class),
+ any(EntityManagerFactory.class), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")));
+
+ returnedEMF.close();
+
+ verify(emfReg).unregister();
+ verify(emf).close();
+
+ emfb.close();
+ }
+
+ @Test
+ public void testServiceEmfClose() throws InvalidSyntaxException, ConfigurationException {
+
+ when(provider.createContainerEntityManagerFactory(eq(punit),
+ eq(singletonMap(PersistenceUnitTransactionType.class.getName(), JTA))))
+ .thenReturn(emf);
+
+ Map<String, Object> props = new Hashtable<String, Object>();
+ props.put("javax.persistence.dataSource", ds);
+
+ AriesEntityManagerFactoryBuilder emfb = new AriesEntityManagerFactoryBuilder(
+ containerContext, provider, punit);
+
+ emfb.createEntityManagerFactory(props);
+
+ ArgumentCaptor<EntityManagerFactory> emfCaptor = ArgumentCaptor.forClass(EntityManagerFactory.class);
+
+ verify(punit).setNonJtaDataSource(ds);
+ verify(punitContext).registerService(eq(EntityManagerFactory.class),
+ emfCaptor.capture(), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")));
+
+ emfCaptor.getValue().close();
+
+ verifyZeroInteractions(emfReg, emf);
emfb.close();
}