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 2017/06/20 18:00:20 UTC
aries-jpa git commit: Add support for dynamic registration and update
of EMF service properties through the EMFBuilder
Repository: aries-jpa
Updated Branches:
refs/heads/master 9beff6f42 -> d2f7ae9e1
Add support for dynamic registration and update of EMF service properties through the EMFBuilder
Project: http://git-wip-us.apache.org/repos/asf/aries-jpa/repo
Commit: http://git-wip-us.apache.org/repos/asf/aries-jpa/commit/d2f7ae9e
Tree: http://git-wip-us.apache.org/repos/asf/aries-jpa/tree/d2f7ae9e
Diff: http://git-wip-us.apache.org/repos/asf/aries-jpa/diff/d2f7ae9e
Branch: refs/heads/master
Commit: d2f7ae9e1caa78784b255fb94ed59364532a8b3b
Parents: 9beff6f
Author: timothyjward <ti...@apache.org>
Authored: Tue Jun 20 19:00:00 2017 +0100
Committer: timothyjward <ti...@apache.org>
Committed: Tue Jun 20 19:00:00 2017 +0100
----------------------------------------------------------------------
.../container/itest/EclipseAdditionalTest.java | 2 +-
.../jpa/container/itest/JPAContainerTest.java | 9 +
.../src/test/resources/persistence.xml | 3 +
.../impl/AriesEntityManagerFactoryBuilder.java | 509 +++++++++++++++++--
.../aries/jpa/container/impl/DSFTracker.java | 86 ++--
.../jpa/container/impl/DataSourceTracker.java | 52 +-
.../aries/jpa/container/impl/ManagedEMF.java | 147 ++----
.../impl/PersistenceProviderTracker.java | 50 +-
.../jpa/container/impl/StoredPerProvider.java | 3 +-
.../container/impl/DataSourceTrackerTest.java | 15 +-
.../jpa/container/impl/ManagedEMFTest.java | 58 +++
.../container/impl/PropsConfigurationTest.java | 430 ++++++++++++++--
12 files changed, 1006 insertions(+), 358 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/d2f7ae9e/itests/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/EclipseAdditionalTest.java
----------------------------------------------------------------------
diff --git a/itests/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/EclipseAdditionalTest.java b/itests/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/EclipseAdditionalTest.java
index 6c1dcf6..a1aabcf 100644
--- a/itests/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/EclipseAdditionalTest.java
+++ b/itests/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/EclipseAdditionalTest.java
@@ -56,7 +56,7 @@ public class EclipseAdditionalTest extends AbstractJPAItest {
@Test
public void testEntityManagerFactoryBuilderWithIncompletePersistenceUnitAddPlugin() throws Exception {
- EntityManagerFactoryBuilder builder = getService(EntityManagerFactoryBuilder.class, "(osgi.unit.name=incompleteTestUnit)", 1000);
+ EntityManagerFactoryBuilder builder = getService(EntityManagerFactoryBuilder.class, "(osgi.unit.name=incompleteTestUnit2)", 1000);
DataSourceFactory dsf = getService(DataSourceFactory.class,
"(" + OSGI_JDBC_DRIVER_CLASS + "=org.apache.derby.jdbc.EmbeddedDriver)");
http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/d2f7ae9e/itests/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerTest.java
----------------------------------------------------------------------
diff --git a/itests/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerTest.java b/itests/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerTest.java
index 7ba38fe..c5c0edd 100644
--- a/itests/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerTest.java
+++ b/itests/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerTest.java
@@ -54,6 +54,15 @@ public abstract class JPAContainerTest extends AbstractCarJPAITest {
}
@Test
+ public void testTruckEMFBuilder() throws Exception {
+ EntityManagerFactoryBuilder emfBuilder = getService(EntityManagerFactoryBuilder.class,
+ "(osgi.unit.name=" + DSF_TEST_UNIT + ")");
+ Map<String, Object> props = new HashMap<String, Object>();
+ EntityManagerFactory emf = emfBuilder.createEntityManagerFactory(props);
+ truckLifecycleRL(emf.createEntityManager());
+ }
+
+ @Test
public void testCarEMF() throws Exception {
carLifecycleRL(getEMF(TEST_UNIT).createEntityManager());
}
http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/d2f7ae9e/itests/jpa-container-itest/src/test/resources/persistence.xml
----------------------------------------------------------------------
diff --git a/itests/jpa-container-itest/src/test/resources/persistence.xml b/itests/jpa-container-itest/src/test/resources/persistence.xml
index 457d310..f448c14 100644
--- a/itests/jpa-container-itest/src/test/resources/persistence.xml
+++ b/itests/jpa-container-itest/src/test/resources/persistence.xml
@@ -24,4 +24,7 @@
<persistence-unit name="incompleteTestUnit">
<description>Persistence unit for testing an incomplete persistence unit</description>
</persistence-unit>
+ <persistence-unit name="incompleteTestUnit2">
+ <description>Second Persistence unit for testing an incomplete persistence unit</description>
+ </persistence-unit>
</persistence>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/d2f7ae9e/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/AriesEntityManagerFactoryBuilder.java
----------------------------------------------------------------------
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 fecb927..cdeb31d 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,81 +18,478 @@
*/
package org.apache.aries.jpa.container.impl;
+import java.util.Dictionary;
import java.util.HashMap;
+import java.util.Hashtable;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.persistence.spi.PersistenceProvider;
+import javax.persistence.spi.PersistenceUnitInfo;
import javax.persistence.spi.PersistenceUnitTransactionType;
import javax.sql.DataSource;
import org.apache.aries.jpa.container.parser.impl.PersistenceUnit;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.jdbc.DataSourceFactory;
import org.osgi.service.jpa.EntityManagerFactoryBuilder;
+import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* FIXME We are currently not configuring a DataSource for the persistence unit.
- * It still works in the tests as the DataSource is defined in the DataSourceTracker or DSFTracker.
- * This not fully correct though.
+ * It still works in the tests as the DataSource is defined in the
+ * DataSourceTracker or DSFTracker. This not fully correct though.
*/
public class AriesEntityManagerFactoryBuilder implements EntityManagerFactoryBuilder {
- private static final String JAVAX_PERSISTENCE_JDBC_DRIVER = "javax.persistence.jdbc.driver";
- private static final String JAVAX_PERSISTENCE_JTA_DATASOURCE = "javax.persistence.jtaDataSource";
- private static final String JAVAX_PERSISTENCE_DATASOURCE = "javax.persistence.dataSource";
- private static final String JAVAX_PERSISTENCE_NON_JTA_DATASOURCE = "javax.persistence.nonJtaDataSource";
- private static final String JAVAX_PERSISTENCE_TX_TYPE = "javax.persistence.transactionType";
-
- private PersistenceProvider provider;
- private PersistenceUnit persistenceUnit;
- private String driver;
-
-
- public AriesEntityManagerFactoryBuilder(PersistenceProvider provider, PersistenceUnit persistenceUnit) {
- this.provider = provider;
- this.persistenceUnit = persistenceUnit;
- this.driver = (String)persistenceUnit.getProperties().get(JAVAX_PERSISTENCE_JDBC_DRIVER);
- }
- @Override
- public EntityManagerFactory createEntityManagerFactory(Map<String, Object> props) {
- props = new HashMap<String, Object>(props);
-
- String newDriver = (String)props.get(JAVAX_PERSISTENCE_JDBC_DRIVER);
- if (driver == null) {
- driver = newDriver;
- } else if (newDriver != null && !newDriver.equals(driver)){
- throw new IllegalArgumentException("Can not rebind to a different database driver");
- }
-
- // Handle overridden datasources in a provider agnostic way
- // This isn't necessary for EclipseLink, but Hibernate and
- // OpenJPA both need some extra help.
- Object o = props.get(JAVAX_PERSISTENCE_JTA_DATASOURCE);
- if(o instanceof DataSource) {
- persistenceUnit.setJtaDataSource((DataSource) o);
- props.remove(JAVAX_PERSISTENCE_JTA_DATASOURCE);
- }
+ private static final Logger LOGGER = LoggerFactory.getLogger(AriesEntityManagerFactoryBuilder.class);
+
+ private static final String JPA_CONFIGURATION_PREFIX = "org.apache.aries.jpa.";
+
+ private static final String JAVAX_PERSISTENCE_JDBC_DRIVER = "javax.persistence.jdbc.driver";
+ private static final String JAVAX_PERSISTENCE_JTA_DATASOURCE = "javax.persistence.jtaDataSource";
+ private static final String JAVAX_PERSISTENCE_DATASOURCE = "javax.persistence.dataSource";
+ private static final String JAVAX_PERSISTENCE_NON_JTA_DATASOURCE = "javax.persistence.nonJtaDataSource";
+ private static final String JAVAX_PERSISTENCE_TX_TYPE = "javax.persistence.transactionType";
+
+
+ private boolean closed;
+
+ private final PersistenceProvider provider;
+ private final PersistenceUnit persistenceUnit;
+ private final BundleContext containerContext;
+ private final PersistenceUnitTransactionType originalTxType;
+ private final Bundle bundle;
+ private String driver;
+
+ private EntityManagerFactory emf;
+ private ServiceRegistration<EntityManagerFactory> reg;
+ private ServiceRegistration<?> configReg;
+ private Object activeConnectionProvider;
+ private Map<String, Object> activeProps;
+ private ServiceTracker<?,?> tracker;
+
+ private boolean complete;
- o = props.get(JAVAX_PERSISTENCE_NON_JTA_DATASOURCE);
- if(o instanceof DataSource) {
- persistenceUnit.setNonJtaDataSource((DataSource) o);
- props.remove(JAVAX_PERSISTENCE_NON_JTA_DATASOURCE);
+
+ public AriesEntityManagerFactoryBuilder(BundleContext containerContext, PersistenceProvider provider, PersistenceUnit persistenceUnit) {
+ this.provider = provider;
+ this.persistenceUnit = persistenceUnit;
+ this.containerContext = containerContext;
+ this.originalTxType = persistenceUnit.getTransactionType();
+ this.bundle = persistenceUnit.getBundle();
+ this.driver = persistenceUnit.getProperties().getProperty(JAVAX_PERSISTENCE_JDBC_DRIVER);
+ this.tracker = createDataSourceTracker(provider);
+ // This must be done separately to avoid an immediate callback seeing the wrong state
+ if(this.tracker != null) {
+ this.tracker.open();
+ }
+ registerManagedService(containerContext, persistenceUnit);
+ }
+
+ private ServiceTracker<?, ?> createDataSourceTracker(PersistenceProvider provider) {
+ if (usesDataSource()) {
+ synchronized (this) {
+ driver = "Pre Configured DataSource";
+ }
+ if (!usesDataSourceService()) {
+ LOGGER.warn("Persistence unit " + persistenceUnit.getPersistenceUnitName() + " refers to a non OSGi service DataSource");
+ return null;
+ }
+ DataSourceTracker dsTracker = new DataSourceTracker(containerContext, this,
+ DataSourceTracker.getDsName(persistenceUnit));
+ return dsTracker;
+ } else if (usesDSF()) {
+ String jdbcClass = DSFTracker.getDriverName(persistenceUnit);
+ synchronized (this) {
+ driver = jdbcClass;
+ }
+ DSFTracker dsfTracker = new DSFTracker(containerContext, this,
+ jdbcClass);
+ return dsfTracker;
} else {
- o = props.get(JAVAX_PERSISTENCE_DATASOURCE);
- if(o != null && o instanceof DataSource) {
- persistenceUnit.setNonJtaDataSource((DataSource) o);
- props.remove(JAVAX_PERSISTENCE_DATASOURCE);
- }
- }
-
- o = props.get(JAVAX_PERSISTENCE_TX_TYPE);
- if(o instanceof PersistenceUnitTransactionType) {
- persistenceUnit.setTransactionType((PersistenceUnitTransactionType) o);
- } else if (o instanceof String) {
- persistenceUnit.setTransactionType(
- PersistenceUnitTransactionType.valueOf((String) o));
+ LOGGER.debug("Persistence unit " + getPUName() + " does not refer a DataSource. "
+ +"It can only be used with EntityManagerFactoryBuilder.");
+ return null;
}
-
- return provider.createContainerEntityManagerFactory(persistenceUnit, props);
}
+ private boolean usesDataSource() {
+ return persistenceUnit.getJtaDataSourceName() != null || persistenceUnit.getNonJtaDataSourceName() != null;
+ }
+
+ private boolean usesDSF() {
+ return DSFTracker.getDriverName(persistenceUnit) != null;
+ }
+
+ private boolean usesDataSourceService() {
+ return persistenceUnit.getJtaDataSourceName() != null && persistenceUnit.getJtaDataSourceName().startsWith(DataSourceTracker.DS_PREFIX)
+ || persistenceUnit.getNonJtaDataSourceName() != null && persistenceUnit.getNonJtaDataSourceName().startsWith(DataSourceTracker.DS_PREFIX);
+ }
+
+ @Override
+ public EntityManagerFactory createEntityManagerFactory(Map<String, Object> props) {
+
+ synchronized (this) {
+ if (closed) {
+ throw new IllegalStateException("The EntityManagerFactoryBuilder for " +
+ getPUName() + " is no longer valid");
+ }
+ }
+
+ if (bundle.getState() == Bundle.UNINSTALLED || bundle.getState() == Bundle.INSTALLED
+ || bundle.getState() == Bundle.STOPPING) {
+ // Not sure why but during the TCK tests updated sometimes was
+ // called for uninstalled bundles
+ throw new IllegalStateException("The EntityManagerFactoryBuilder for " +
+ getPUName() + " is no longer valid");
+ }
+
+ Map<String, Object> processedProperties = processProperties(props);
+
+ synchronized (this) {
+ if(processedProperties.equals(activeProps) && emf != null) {
+ return emf;
+ }
+ }
+
+ closeEMF();
+
+ return createAndPublishEMF(processedProperties);
+ }
+
+ public String getPUName() {
+ return persistenceUnit.getPersistenceUnitName();
+ }
+
+ private Map<String, Object> processProperties(Map<String, Object> props) {
+ Map<String, Object> processed = new HashMap<String, Object>();
+
+ Properties punitProps = persistenceUnit.getProperties();
+
+ for(String key : punitProps.stringPropertyNames()) {
+ processed.put(key, punitProps.get(key));
+ }
+
+ if(props != null) {
+ processed.putAll(props);
+ }
+
+ String newDriver = (String) processed.get(JAVAX_PERSISTENCE_JDBC_DRIVER);
+
+ synchronized (this) {
+ if(newDriver != null) {
+ if(driver == null) {
+ driver = newDriver;
+ } else if (!newDriver.equals(driver)) {
+ throw new IllegalArgumentException("Cannot rebind to a different database driver, as per the JPA service specification");
+ }
+ }
+ }
+
+ boolean dataSourceProvided = false;
+
+ // Handle overridden datasources in a provider agnostic way
+ // This isn't necessary for EclipseLink, but Hibernate and
+ // OpenJPA both need some extra help.
+ Object o = processed.get(JAVAX_PERSISTENCE_JTA_DATASOURCE);
+
+ if (o instanceof DataSource) {
+ persistenceUnit.setJtaDataSource((DataSource) o);
+ processed.remove(JAVAX_PERSISTENCE_JTA_DATASOURCE);
+ dataSourceProvided = true;
+ }
+
+ o = processed.get(JAVAX_PERSISTENCE_NON_JTA_DATASOURCE);
+ if (o instanceof DataSource) {
+ persistenceUnit.setNonJtaDataSource((DataSource) o);
+ processed.remove(JAVAX_PERSISTENCE_NON_JTA_DATASOURCE);
+ dataSourceProvided = true;
+ } else {
+ o = processed.get(JAVAX_PERSISTENCE_DATASOURCE);
+ if (o != null && o instanceof DataSource) {
+ persistenceUnit.setNonJtaDataSource((DataSource) o);
+ processed.remove(JAVAX_PERSISTENCE_DATASOURCE);
+ dataSourceProvided = true;
+ }
+ }
+
+ o = processed.get(JAVAX_PERSISTENCE_TX_TYPE);
+ if (o instanceof PersistenceUnitTransactionType) {
+ persistenceUnit.setTransactionType((PersistenceUnitTransactionType) o);
+ } else if (o instanceof String) {
+ persistenceUnit.setTransactionType(PersistenceUnitTransactionType.valueOf((String) o));
+ } else {
+ LOGGER.debug("No transaction type set in config, restoring the original value {}", originalTxType);
+ persistenceUnit.setTransactionType(originalTxType);
+ }
+
+ // This Aries extension is used to communicate the actual transaction type to clients
+ processed.put(PersistenceUnitTransactionType.class.getName(), persistenceUnit.getTransactionType());
+
+ synchronized (this) {
+ // Either they provide a datasource, or we're already provided and using a tracker
+ complete = dataSourceProvided || (complete && tracker != null);
+ }
+ return processed;
+ }
+
+ private void registerManagedService(BundleContext containerContext, PersistenceUnitInfo persistenceUnit) {
+ Dictionary<String, Object> configuration = new Hashtable<String, Object>(); // NOSONAR
+ configuration.put(Constants.SERVICE_PID, JPA_CONFIGURATION_PREFIX + persistenceUnit.getPersistenceUnitName());
+ configReg = containerContext.registerService(ManagedService.class,
+ new ManagedEMF(this, persistenceUnit.getPersistenceUnitName()), configuration);
+ }
+
+ public void closeEMF() {
+
+ EntityManagerFactory emf;
+ ServiceRegistration<EntityManagerFactory> emfReg;
+
+ synchronized (this) {
+ emf = this.emf;
+ this.emf = null;
+
+ emfReg = this.reg;
+ this.reg = null;
+ }
+
+ if (emfReg != null) {
+ try {
+ emfReg.unregister();
+ } catch (Exception e) {
+ LOGGER.debug("Exception on unregister", e);
+ }
+ }
+ if (emf != null && emf.isOpen()) {
+ try {
+ emf.close();
+ } catch (Exception e) {
+ LOGGER.warn("Error closing EntityManagerFactory for " + getPUName(), e);
+ }
+ }
+ }
+
+ public void close() {
+ boolean unregister = false;
+ ServiceTracker<?, ?> toClose;
+ synchronized (this) {
+ closed = true;
+ unregister = true;
+ toClose = tracker;
+ }
+
+ if(unregister) {
+ try {
+ configReg.unregister();
+ } catch (Exception e) {
+ LOGGER.debug("Exception on unregister", e);
+ }
+ }
+
+ if (toClose != null) {
+ toClose.close();
+ }
+
+ closeEMF();
+ }
+
+ private EntityManagerFactory createAndPublishEMF(Map<String, Object> overrides) {
+
+ boolean makeTracker;
+ String dbDriver;
+ synchronized (this) {
+ makeTracker = driver != null && tracker == null;
+ dbDriver = driver;
+ }
+
+ if(makeTracker) {
+ ServiceTracker<?, ?> dsfTracker = new DSFTracker(containerContext,
+ this, dbDriver);
+ synchronized (this) {
+ tracker = dsfTracker;
+ activeProps = overrides;
+ }
+ dsfTracker.open();
+
+ synchronized (this) {
+ if(emf == null) {
+ throw new IllegalStateException("No database driver is currently available for class " + dbDriver);
+ } else {
+ return emf;
+ }
+ }
+ } else {
+ synchronized (this) {
+ if(!complete) {
+ throw new IllegalArgumentException("The persistence unit " + getPUName() +
+ " has incomplete configuration and cannot be created. The configuration is" + overrides);
+ }
+ }
+ }
+
+ EntityManagerFactory tmp = provider.createContainerEntityManagerFactory(persistenceUnit, overrides);
+ boolean register = false;
+ synchronized (this) {
+ if(emf == null) {
+ emf = tmp;
+ activeProps = overrides;
+ register = true;
+ }
+ }
+ if(register) {
+ Dictionary<String, Object> props = createBuilderProperties(overrides);
+ BundleContext uctx = bundle.getBundleContext();
+ ServiceRegistration<EntityManagerFactory> tmpReg =
+ uctx.registerService(EntityManagerFactory.class, emf, props);
+
+ synchronized (this) {
+ if(emf == tmp) {
+ reg = tmpReg;
+ } else {
+ register = false;
+ }
+ }
+
+ if(!register) {
+ tmpReg.unregister();
+ }
+ } else {
+ tmp.close();
+ synchronized (this) {
+ return emf;
+ }
+ }
+ return tmp;
+ }
+
+ private Dictionary<String, Object> createBuilderProperties(Map<String, Object> config) {
+ Dictionary<String, Object> props = new Hashtable<String, Object>(); // NOSONAR
+
+ for(Entry<String,Object> e : config.entrySet()) {
+ String key = e.getKey();
+ // Don't display the password
+ if(DSFTracker.JDBC_PASSWORD.equals(key)) {
+ continue;
+ }
+
+ Object value = e.getValue();
+
+ if(key != null && value != null) {
+ props.put(key, e.getValue());
+ }
+ }
+
+ if (persistenceUnit.getPersistenceProviderClassName() != null) {
+ props.put(JPA_UNIT_PROVIDER, persistenceUnit.getPersistenceProviderClassName());
+ }
+ props.put(JPA_UNIT_VERSION, bundle.getVersion().toString());
+ props.put(JPA_UNIT_NAME, persistenceUnit.getPersistenceUnitName());
+ return props;
+ }
+
+ public static Dictionary<String, String> createBuilderProperties(PersistenceUnitInfo persistenceUnit, Bundle puBundle) {
+ Dictionary<String, String> props = new Hashtable<String, String>(); // NOSONAR
+ props.put(JPA_UNIT_NAME, persistenceUnit.getPersistenceUnitName());
+ if (persistenceUnit.getPersistenceProviderClassName() != null) {
+ props.put(JPA_UNIT_PROVIDER, persistenceUnit.getPersistenceProviderClassName());
+ }
+ props.put(JPA_UNIT_VERSION, puBundle.getVersion().toString());
+ return props;
+ }
+
+ public void foundDSF(DataSourceFactory dsf) {
+ boolean build = false;
+ Map<String,Object> props = null;
+ synchronized (this) {
+ if(activeConnectionProvider == null) {
+ activeConnectionProvider = dsf;
+ build = true;
+ props = activeProps == null ? new HashMap<String, Object>() :
+ new HashMap<String, Object>(activeProps);
+ }
+ }
+
+ if(build) {
+ Properties punitProps = persistenceUnit.getProperties();
+ for(String key : punitProps.stringPropertyNames()) {
+ if(!props.containsKey(key)) {
+ props.put(key, punitProps.get(key));
+ }
+ }
+
+ DataSource ds = DSFTracker.createDataSource(dsf, props, persistenceUnit.getName());
+ dataSourceReady(ds, props);
+ }
+ }
+
+ public void lostDSF(DataSourceFactory dsf, DataSourceFactory replacement) {
+ boolean destroy = false;
+ synchronized (this) {
+ if(activeConnectionProvider == dsf) {
+ activeConnectionProvider = null;
+ destroy = true;
+ }
+ }
+
+ if(destroy) {
+ closeEMF();
+ }
+
+ if(replacement != null) {
+ foundDSF(replacement);
+ }
+ }
+
+ public void foundDS(DataSource ds) {
+ boolean build = false;
+ Map<String,Object> props = null;
+ synchronized (this) {
+ if(activeConnectionProvider == null) {
+ activeConnectionProvider = ds;
+ build = true;
+ props = activeProps == null ? new HashMap<String, Object>() :
+ new HashMap<String, Object>(activeProps);
+ }
+ }
+
+ if(build) {
+ dataSourceReady(ds, props);
+ }
+ }
+
+ public void lostDS(DataSource ds, DataSource replacement) {
+ boolean destroy = false;
+ synchronized (this) {
+ if(activeConnectionProvider == ds) {
+ activeConnectionProvider = null;
+ destroy = true;
+ }
+ }
+
+ if(destroy) {
+ closeEMF();
+ }
+
+ if(replacement != null) {
+ foundDS(replacement);
+ }
+ }
+
+ private void dataSourceReady(DataSource ds, Map<String, Object> props) {
+ if (persistenceUnit.getTransactionType() == PersistenceUnitTransactionType.JTA) {
+ props.put(JAVAX_PERSISTENCE_JTA_DATASOURCE, ds);
+ } else {
+ props.put(JAVAX_PERSISTENCE_NON_JTA_DATASOURCE, ds);
+ }
+ createEntityManagerFactory(props);
+ }
}
http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/d2f7ae9e/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DSFTracker.java
----------------------------------------------------------------------
diff --git a/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DSFTracker.java b/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DSFTracker.java
index 4f714a0..404bd77 100644
--- a/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DSFTracker.java
+++ b/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DSFTracker.java
@@ -19,16 +19,14 @@
package org.apache.aries.jpa.container.impl;
import java.sql.SQLException;
+import java.util.Map;
import java.util.Properties;
-import javax.persistence.spi.PersistenceProvider;
-import javax.persistence.spi.PersistenceUnitTransactionType;
import javax.sql.DataSource;
import org.apache.aries.jpa.container.parser.impl.PersistenceUnit;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Filter;
-import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.jdbc.DataSourceFactory;
@@ -36,34 +34,34 @@ import org.osgi.util.tracker.ServiceTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class DSFTracker extends ServiceTracker<DataSourceFactory, ManagedEMF>{
- private static final String JDBC_DRIVER = "javax.persistence.jdbc.driver";
- private static final String JDBC_URL = "javax.persistence.jdbc.url";
- private static final String JDBC_USER = "javax.persistence.jdbc.user";
- private static final String JDBC_PASSWORD = "javax.persistence.jdbc.password"; // NOSONAR
+public class DSFTracker extends ServiceTracker<DataSourceFactory, DataSourceFactory>{
+ static final String JDBC_DRIVER = "javax.persistence.jdbc.driver";
+ static final String JDBC_URL = "javax.persistence.jdbc.url";
+ static final String JDBC_USER = "javax.persistence.jdbc.user";
+ static final String JDBC_PASSWORD = "javax.persistence.jdbc.password"; // NOSONAR
private static final Logger LOGGER = LoggerFactory.getLogger(DSFTracker.class);
- private PersistenceProvider provider;
- private PersistenceUnit punit;
-
- public DSFTracker(BundleContext context, PersistenceProvider provider, PersistenceUnit punit) {
- super(context, createFilter(context, punit), null);
- this.provider = provider;
- this.punit = punit;
+ private final AriesEntityManagerFactoryBuilder builder;
+ private final String driverClass;
+
+ public DSFTracker(BundleContext context, AriesEntityManagerFactoryBuilder builder,
+ String driverClass) {
+ super(context, createFilter(context, driverClass, builder.getPUName()), null);
+ this.builder = builder;
+ this.driverClass = driverClass;
}
- static Filter createFilter(BundleContext context, PersistenceUnit punit) {
- String driverName = getDriverName(punit);
- if (driverName == null) {
+ static Filter createFilter(BundleContext context, String driverClass, String puName) {
+ if (driverClass == null) {
throw new IllegalArgumentException("No javax.persistence.jdbc.driver supplied in persistence.xml");
}
String filter = String.format("(&(objectClass=%s)(%s=%s))",
DataSourceFactory.class.getName(),
DataSourceFactory.OSGI_JDBC_DRIVER_CLASS,
- driverName);
- LOGGER.info("Tracking DataSourceFactory for punit " + punit.getPersistenceUnitName() + " with filter " + filter);
+ driverClass);
+ LOGGER.info("Tracking DataSourceFactory for punit " + puName + " with filter " + filter);
try {
return context.createFilter(filter);
} catch (InvalidSyntaxException e) {
@@ -72,53 +70,49 @@ public class DSFTracker extends ServiceTracker<DataSourceFactory, ManagedEMF>{
}
public static String getDriverName(PersistenceUnit punit) {
- return (String)punit.getProperties().get(JDBC_DRIVER);
+ return (String)punit.getProperties().getProperty(JDBC_DRIVER);
}
@Override
- public ManagedEMF addingService(ServiceReference<DataSourceFactory> reference) {
- LOGGER.info("Found DataSourceFactory for " + punit.getPersistenceUnitName() + " "
- + getDriverName(punit));
+ public DataSourceFactory addingService(ServiceReference<DataSourceFactory> reference) {
+ LOGGER.info("Found DataSourceFactory for " + builder.getPUName() + " of type "
+ + driverClass);
try {
- DataSourceFactory dsf = context.getService(reference);
- DataSource ds = createDataSource(dsf);
- if (punit.getTransactionType() == PersistenceUnitTransactionType.JTA) {
- punit.setJtaDataSource(ds);
- } else {
- punit.setNonJtaDataSource(ds);
- }
- BundleContext containerContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
- return new ManagedEMF(containerContext, punit.getBundle(), provider, punit);
+ DataSourceFactory dsf = super.addingService(reference);
+
+ if(dsf != null)
+ builder.foundDSF(dsf);
+ return dsf;
} catch (Exception e) {
- LOGGER.error("Error creating DataSource for punit " + punit.getPersistenceUnitName(), e);
+ LOGGER.error("Error creating DataSource for punit " + builder.getPUName(), e);
return null;
}
}
- private DataSource createDataSource(DataSourceFactory dsf) {
+ static DataSource createDataSource(DataSourceFactory dsf, Map<String, Object> punitProps, String punitName) {
try {
Properties props = new Properties();
- put(props, DataSourceFactory.JDBC_URL, punit, JDBC_URL);
- put(props, DataSourceFactory.JDBC_USER, punit, JDBC_USER);
- put(props, DataSourceFactory.JDBC_PASSWORD, punit, JDBC_PASSWORD);
+ put(props, DataSourceFactory.JDBC_URL, punitProps, JDBC_URL);
+ put(props, DataSourceFactory.JDBC_USER, punitProps, JDBC_USER);
+ put(props, DataSourceFactory.JDBC_PASSWORD, punitProps, JDBC_PASSWORD);
return dsf.createDataSource(props);
} catch (SQLException e) {
- String msg = "Error creating DataSource for persistence unit " + punit + "." + e.getMessage();
+ String msg = "Error creating DataSource for persistence unit " + punitName + ". " + e.getMessage();
throw new RuntimeException(msg, e); // NOSONAR
}
}
- private static void put(Properties props, String destKey, PersistenceUnit punit, String sourceKey) {
- Object value = punit.getProperties().get(sourceKey);
+ private static void put(Properties props, String destKey, Map<String, Object> punitProps, String sourceKey) {
+ Object value = punitProps.get(sourceKey);
if (value != null) {
- props.put(destKey, value);
+ props.setProperty(destKey, String.valueOf(value));
}
}
@Override
- public void removedService(ServiceReference<DataSourceFactory> reference, ManagedEMF managedEMF) {
- LOGGER.info("Lost DataSourceFactory for " + punit.getPersistenceUnitName() + " " + getDriverName(punit));
- managedEMF.close();
- super.removedService(reference, managedEMF);
+ public void removedService(ServiceReference<DataSourceFactory> reference, DataSourceFactory dsf) {
+ LOGGER.info("Lost DataSourceFactory for " + builder.getPUName() + " of type " + driverClass);
+ builder.lostDSF(dsf, getService());
+ super.removedService(reference, dsf);
}
}
http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/d2f7ae9e/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DataSourceTracker.java
----------------------------------------------------------------------
diff --git a/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DataSourceTracker.java b/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DataSourceTracker.java
index 907dc48..9d826f8 100644
--- a/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DataSourceTracker.java
+++ b/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/DataSourceTracker.java
@@ -20,36 +20,34 @@ package org.apache.aries.jpa.container.impl;
import static javax.persistence.spi.PersistenceUnitTransactionType.JTA;
-import javax.persistence.spi.PersistenceProvider;
-import javax.persistence.spi.PersistenceUnitTransactionType;
import javax.sql.DataSource;
import org.apache.aries.jpa.container.parser.impl.PersistenceUnit;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Filter;
-import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class DataSourceTracker extends ServiceTracker<DataSource, ManagedEMF>{
+public class DataSourceTracker extends ServiceTracker<DataSource, DataSource>{
private static final Logger LOGGER = LoggerFactory.getLogger(DataSourceTracker.class);
- private PersistenceProvider provider;
- private PersistenceUnit punit;
-
static final String DS_PREFIX = "osgi:service/javax.sql.DataSource";
- public DataSourceTracker(BundleContext context, PersistenceProvider provider, PersistenceUnit punit) {
- super(context, createFilter(context, punit), null);
- this.provider = provider;
- this.punit = punit;
+ private final AriesEntityManagerFactoryBuilder builder;
+
+ private final String dsName;
+
+ public DataSourceTracker(BundleContext context, AriesEntityManagerFactoryBuilder builder,
+ String dsName) {
+ super(context, createFilter(context, dsName, builder.getPUName()), null);
+ this.builder = builder;
+ this.dsName = dsName;
}
- static Filter createFilter(BundleContext context, PersistenceUnit punit) {
- String dsName = getDsName(punit);
+ static Filter createFilter(BundleContext context, String dsName, String puName) {
if (dsName == null) {
throw new IllegalArgumentException("No DataSource supplied in persistence.xml");
}
@@ -57,7 +55,7 @@ public class DataSourceTracker extends ServiceTracker<DataSource, ManagedEMF>{
String filter = String.format("(&(objectClass=%s)%s)",
DataSource.class.getName(),
subFilter);
- LOGGER.info("Tracking DataSource for punit " + punit.getPersistenceUnitName() + " with filter " + filter);
+ LOGGER.info("Tracking DataSource for punit " + puName + " with filter " + filter);
try {
return context.createFilter(filter);
} catch (InvalidSyntaxException e) {
@@ -75,29 +73,27 @@ public class DataSourceTracker extends ServiceTracker<DataSource, ManagedEMF>{
}
}
- private static String getDsName(PersistenceUnit punit) {
+ static String getDsName(PersistenceUnit punit) {
return punit.getTransactionType() == JTA ? punit.getJtaDataSourceName() : punit.getNonJtaDataSourceName();
}
@Override
- public ManagedEMF addingService(ServiceReference<DataSource> reference) {
- LOGGER.info("Found DataSource for " + punit.getPersistenceUnitName() + " " + getDsName(punit));
- DataSource ds = context.getService(reference);
- if (punit.getTransactionType() == PersistenceUnitTransactionType.JTA) {
- punit.setJtaDataSource(ds);
- } else {
- punit.setNonJtaDataSource(ds);
+ public DataSource addingService(ServiceReference<DataSource> reference) {
+ LOGGER.info("Found DataSource for " + builder.getPUName() + " " + dsName);
+ DataSource ds = super.addingService(reference);
+
+ if(ds != null) {
+ builder.foundDS(ds);
}
- BundleContext containerContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
- return new ManagedEMF(containerContext, punit.getBundle(), provider, punit);
+ return ds;
}
@Override
- public void removedService(ServiceReference<DataSource> reference, ManagedEMF managedEMF) {
- LOGGER.info("Lost DataSource for " + punit.getPersistenceUnitName() + " " + getDsName(punit));
- managedEMF.close();
- super.removedService(reference, managedEMF);
+ public void removedService(ServiceReference<DataSource> reference, DataSource ds) {
+ LOGGER.info("Lost DataSource for " + builder.getPUName() + " " + dsName);
+ builder.lostDS(ds, getService());
+ super.removedService(reference, ds);
}
}
http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/d2f7ae9e/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/ManagedEMF.java
----------------------------------------------------------------------
diff --git a/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/ManagedEMF.java b/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/ManagedEMF.java
index 8e9bb54..825cc8d 100644
--- a/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/ManagedEMF.java
+++ b/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/ManagedEMF.java
@@ -18,138 +18,51 @@
*/
package org.apache.aries.jpa.container.impl;
-import static org.osgi.service.jpa.EntityManagerFactoryBuilder.JPA_UNIT_NAME;
-import static org.osgi.service.jpa.EntityManagerFactoryBuilder.JPA_UNIT_PROVIDER;
-import static org.osgi.service.jpa.EntityManagerFactoryBuilder.JPA_UNIT_VERSION;
-
-import java.io.Closeable;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
-import java.util.Hashtable;
import java.util.Map;
-import javax.persistence.EntityManagerFactory;
-import javax.persistence.spi.PersistenceProvider;
-import javax.persistence.spi.PersistenceUnitInfo;
-import javax.persistence.spi.PersistenceUnitTransactionType;
-
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * Creates an EntityManagerFactory(EMF) for a persistence unit and publishes it as a service.
- * Custom properties can be configured by supplying a config admin configuriation named like
- * the JPA_CONFIGURATION_PREFIX.persistence unit name.
+ * Creates an EntityManagerFactory(EMF) for a persistence unit and publishes it
+ * as a service. Custom properties can be configured by supplying a config admin
+ * configuriation named like the JPA_CONFIGURATION_PREFIX.persistence unit name.
*/
-public class ManagedEMF implements Closeable, ManagedService {
- private static final Logger LOGGER = LoggerFactory.getLogger(ManagedEMF.class);
- private static final String JPA_CONFIGURATION_PREFIX = "org.apache.aries.jpa.";
-
- private EntityManagerFactory emf;
- private ServiceRegistration<EntityManagerFactory> reg;
- private PersistenceProvider provider;
- private PersistenceUnitInfo persistenceUnit;
- private Bundle bundle;
- private ServiceRegistration<?> configReg;
-
- private boolean closed;
-
- public ManagedEMF(BundleContext containerContext, Bundle bundle, PersistenceProvider provider, PersistenceUnitInfo persistenceUnit) {
- this.provider = provider;
- this.persistenceUnit = persistenceUnit;
- this.bundle = bundle;
- registerManagedService(containerContext, persistenceUnit);
- closed = false;
- }
-
- private void registerManagedService(BundleContext containerContext, PersistenceUnitInfo persistenceUnit) {
- Dictionary<String, Object> configuration = new Hashtable<String, Object>(); // NOSONAR
- configuration.put(Constants.SERVICE_PID,
- JPA_CONFIGURATION_PREFIX + persistenceUnit.getPersistenceUnitName());
- configReg = containerContext.registerService(ManagedService.class.getName(), this, configuration);
- }
-
- public void closeEMF() {
- if (reg != null) {
- try {
- reg.unregister();
- } catch (Exception e) {
- LOGGER.debug("Exception on unregister", e);
- }
- }
- if (emf != null && emf.isOpen()) {
- try {
- emf.close();
- } catch (Exception e) {
- LOGGER.warn("Error closing EntityManagerFactory for " + persistenceUnit.getPersistenceUnitName(), e);
- }
- }
- reg = null;
- emf = null;
- }
-
- @Override
- public void close() {
- closed = true;
- closeEMF();
- if (configReg != null) {
- configReg.unregister();
- }
- }
+public class ManagedEMF implements ManagedService {
- @Override
- public void updated(Dictionary<String, ?> properties) throws ConfigurationException {
- if (closed) {
- return;
- }
- if (emf != null) {
- closeEMF();
- }
- if (bundle.getState() == Bundle.UNINSTALLED || bundle.getState() == Bundle.INSTALLED || bundle.getState() == Bundle.STOPPING) {
- // Not sure why but during the TCK tests updated sometimes was called
- // for uninstalled bundles
- return;
- }
- Map<String, Object> overrides = (properties != null) ? asMap(properties) : null;
- LOGGER.info("Registering EntityManagerFactory for persistence unit " + persistenceUnit.getPersistenceUnitName());
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Using properties override " + overrides);
- }
- createAndPublishEMF(overrides);
- }
+ private static final Logger LOGGER = LoggerFactory.getLogger(ManagedEMF.class);
- private void createAndPublishEMF(Map<String, Object> overrides) {
- emf = provider.createContainerEntityManagerFactory(persistenceUnit, overrides);
- Dictionary<String, String> props = createProperties(persistenceUnit, bundle);
- BundleContext uctx = bundle.getBundleContext();
- reg = uctx.registerService(EntityManagerFactory.class, emf, props);
- }
+ private final AriesEntityManagerFactoryBuilder builder;
+
+ private final String pUnitName;
- public static Dictionary<String, String> createProperties(PersistenceUnitInfo persistenceUnit, Bundle puBundle) {
- Dictionary<String, String> props = new Hashtable<String, String>(); // NOSONAR
- props.put(JPA_UNIT_NAME, persistenceUnit.getPersistenceUnitName());
- if (persistenceUnit.getPersistenceProviderClassName() != null) {
- props.put(JPA_UNIT_PROVIDER, persistenceUnit.getPersistenceProviderClassName());
- }
- props.put(JPA_UNIT_VERSION, puBundle.getVersion().toString());
- return props;
- }
+ public ManagedEMF(AriesEntityManagerFactoryBuilder builder, String name) {
+ this.builder = builder;
+ this.pUnitName = name;
+ }
- private Map<String, Object> asMap(Dictionary<String, ?> dict) {
- Map<String, Object> map = new HashMap<String, Object>(); // NOSONAR
- map.put(PersistenceUnitTransactionType.class.getName(), persistenceUnit.getTransactionType());
- for (Enumeration<String> e = dict.keys(); e.hasMoreElements();) {
- String key = e.nextElement();
- map.put(key, dict.get(key));
- }
- return map;
- }
+ @Override
+ public void updated(Dictionary<String, ?> properties) throws ConfigurationException {
+ Map<String, Object> overrides = (properties != null) ? asMap(properties) : null;
+ LOGGER.info("Configuration received for persistence unit {}", pUnitName);
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Using properties override {}", overrides);
+ }
+
+ builder.createEntityManagerFactory(overrides);
+ }
+ private Map<String, Object> asMap(Dictionary<String, ?> dict) {
+ Map<String, Object> map = new HashMap<String, Object>(); // NOSONAR
+ for (Enumeration<String> e = dict.keys(); e.hasMoreElements();) {
+ String key = e.nextElement();
+ map.put(key, dict.get(key));
+ }
+ return map;
+ }
}
http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/d2f7ae9e/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceProviderTracker.java
----------------------------------------------------------------------
diff --git a/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceProviderTracker.java b/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceProviderTracker.java
index 67d46e2..ac7e96d 100644
--- a/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceProviderTracker.java
+++ b/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceProviderTracker.java
@@ -85,10 +85,9 @@ public class PersistenceProviderTracker extends ServiceTracker<PersistenceProvid
createAndCloseDummyEMF(provider);
- stored.dsTracker = createDataSourceTracker(provider);
- EntityManagerFactoryBuilder emfBuilder = new AriesEntityManagerFactoryBuilder(provider, punit);
- Dictionary<String, ?> props = ManagedEMF.createProperties(punit, punit.getBundle());
- stored.reg = context.registerService(EntityManagerFactoryBuilder.class, emfBuilder , props);
+ stored.builder = new AriesEntityManagerFactoryBuilder(context, provider, punit);
+ Dictionary<String, ?> props = AriesEntityManagerFactoryBuilder.createBuilderProperties(punit, punit.getBundle());
+ stored.reg = context.registerService(EntityManagerFactoryBuilder.class, stored.builder , props);
return stored;
}
@@ -112,46 +111,17 @@ public class PersistenceProviderTracker extends ServiceTracker<PersistenceProvid
punit.setNonJtaDataSource(null);
}
- private ServiceTracker<?, ?> createDataSourceTracker(PersistenceProvider provider) {
- if (usesDataSource()) {
- if (!usesDataSourceService()) {
- LOGGER.warn("Persistence unit " + punit.getPersistenceUnitName() + " refers to a non OSGi service DataSource");
- return null;
- }
- DataSourceTracker dsTracker = new DataSourceTracker(context, provider, punit);
- dsTracker.open();
- return dsTracker;
- } else if (usesDSF()) {
- DSFTracker dsfTracker = new DSFTracker(context, provider, punit);
- dsfTracker.open();
- return dsfTracker;
- } else {
- LOGGER.debug("Persistence unit " + punit.getPersistenceUnitName() + " does not refer a DataSource. "
- +"It can only be used with EntityManagerFactoryBuilder.");
- return null;
- }
- }
-
- private boolean usesDataSource() {
- return punit.getJtaDataSourceName() != null || punit.getNonJtaDataSourceName() != null;
- }
-
- private boolean usesDSF() {
- return DSFTracker.getDriverName(punit) != null;
- }
-
- private boolean usesDataSourceService() {
- return punit.getJtaDataSourceName() != null && punit.getJtaDataSourceName().startsWith(DataSourceTracker.DS_PREFIX)
- || punit.getNonJtaDataSourceName() != null && punit.getNonJtaDataSourceName().startsWith(DataSourceTracker.DS_PREFIX);
- }
-
@Override
public void removedService(ServiceReference<PersistenceProvider> reference, StoredPerProvider stored) {
LOGGER.info("Lost provider for " + punit.getPersistenceUnitName() + " " + punit.getPersistenceProviderClassName());
- if (stored.dsTracker != null) {
- stored.dsTracker.close();
+ try {
+ stored.reg.unregister();
+ } catch (Exception e) {
+ LOGGER.debug("An exception occurred unregistering a persistence unit {}", stored.builder.getPUName());
+ }
+ if (stored.builder != null) {
+ stored.builder.close();
}
- stored.reg.unregister();
super.removedService(reference, stored);
}
}
http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/d2f7ae9e/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/StoredPerProvider.java
----------------------------------------------------------------------
diff --git a/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/StoredPerProvider.java b/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/StoredPerProvider.java
index e190688..b55556f 100644
--- a/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/StoredPerProvider.java
+++ b/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/StoredPerProvider.java
@@ -20,9 +20,8 @@ package org.apache.aries.jpa.container.impl;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.jpa.EntityManagerFactoryBuilder;
-import org.osgi.util.tracker.ServiceTracker;
public class StoredPerProvider {
- ServiceTracker<?, ?> dsTracker;
+ AriesEntityManagerFactoryBuilder builder;
ServiceRegistration<EntityManagerFactoryBuilder> reg;
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/d2f7ae9e/jpa-container/src/test/java/org/apache/aries/jpa/container/impl/DataSourceTrackerTest.java
----------------------------------------------------------------------
diff --git a/jpa-container/src/test/java/org/apache/aries/jpa/container/impl/DataSourceTrackerTest.java b/jpa-container/src/test/java/org/apache/aries/jpa/container/impl/DataSourceTrackerTest.java
index fda0407..88f3f35 100644
--- a/jpa-container/src/test/java/org/apache/aries/jpa/container/impl/DataSourceTrackerTest.java
+++ b/jpa-container/src/test/java/org/apache/aries/jpa/container/impl/DataSourceTrackerTest.java
@@ -21,12 +21,7 @@ package org.apache.aries.jpa.container.impl;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import javax.persistence.spi.PersistenceUnitTransactionType;
-
-import org.apache.aries.jpa.container.impl.DataSourceTracker;
-import org.apache.aries.jpa.container.parser.impl.PersistenceUnit;
import org.junit.Test;
import org.mockito.Mockito;
import org.osgi.framework.BundleContext;
@@ -36,24 +31,18 @@ public class DataSourceTrackerTest {
@Test
public void testCreateFilterFull() throws InvalidSyntaxException {
- PersistenceUnit punit = mock(PersistenceUnit.class);
- when(punit.getJtaDataSourceName()).thenReturn("osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=tasklist)");
- when(punit.getTransactionType()).thenReturn(PersistenceUnitTransactionType.JTA);
BundleContext context = mock(BundleContext.class);
- DataSourceTracker.createFilter(context, punit);
+ DataSourceTracker.createFilter(context, "osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=tasklist)", "test");
verify(context, atLeastOnce()).createFilter(Mockito.eq("(&(objectClass=javax.sql.DataSource)(osgi.jndi.service.name=tasklist))"));
}
@Test
public void testCreateFilterSimple() throws InvalidSyntaxException {
- PersistenceUnit punit = mock(PersistenceUnit.class);
- when(punit.getJtaDataSourceName()).thenReturn("tasklist");
- when(punit.getTransactionType()).thenReturn(PersistenceUnitTransactionType.JTA);
BundleContext context = mock(BundleContext.class);
- DataSourceTracker.createFilter(context, punit);
+ DataSourceTracker.createFilter(context, "tasklist", "test");
verify(context, atLeastOnce()).createFilter(Mockito.eq("(&(objectClass=javax.sql.DataSource)(osgi.jndi.service.name=tasklist))"));
}
http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/d2f7ae9e/jpa-container/src/test/java/org/apache/aries/jpa/container/impl/ManagedEMFTest.java
----------------------------------------------------------------------
diff --git a/jpa-container/src/test/java/org/apache/aries/jpa/container/impl/ManagedEMFTest.java b/jpa-container/src/test/java/org/apache/aries/jpa/container/impl/ManagedEMFTest.java
new file mode 100644
index 0000000..2d6d375
--- /dev/null
+++ b/jpa-container/src/test/java/org/apache/aries/jpa/container/impl/ManagedEMFTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.jpa.container.impl;
+
+import static org.mockito.Mockito.verify;
+
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.cm.ConfigurationException;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ManagedEMFTest {
+
+ @Mock
+ AriesEntityManagerFactoryBuilder builder;
+
+ @Test
+ public void testEmfWithoutProps() throws InvalidSyntaxException, ConfigurationException {
+ ManagedEMF emf = new ManagedEMF(builder, "test");
+ emf.updated(null);
+ verify(builder).createEntityManagerFactory(null);
+ }
+
+ @Test
+ public void testEmfWithProps() throws InvalidSyntaxException, ConfigurationException {
+ ManagedEMF emf = new ManagedEMF(builder, "test");
+
+ Dictionary<String, Object> props = new Hashtable<String, Object>();
+ props.put("hibernate.hbm2ddl.auto", "create-drop");
+ emf.updated(props);
+
+ verify(builder).createEntityManagerFactory(Collections.<String, Object>singletonMap(
+ "hibernate.hbm2ddl.auto", "create-drop"));
+ }
+}
http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/d2f7ae9e/jpa-container/src/test/java/org/apache/aries/jpa/container/impl/PropsConfigurationTest.java
----------------------------------------------------------------------
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 8758016..20cd2b9 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
@@ -18,89 +18,409 @@
*/
package org.apache.aries.jpa.container.impl;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.mock;
+import static java.util.Collections.singletonMap;
+import static javax.persistence.spi.PersistenceUnitTransactionType.JTA;
+import static javax.persistence.spi.PersistenceUnitTransactionType.RESOURCE_LOCAL;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+import static org.mockito.AdditionalMatchers.and;
+import static org.mockito.AdditionalMatchers.not;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyMap;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+import static org.osgi.framework.Constants.SERVICE_PID;
+import static org.osgi.service.jpa.EntityManagerFactoryBuilder.JPA_UNIT_NAME;
import java.util.Dictionary;
+import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
+import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.persistence.spi.PersistenceProvider;
import javax.persistence.spi.PersistenceUnitInfo;
import javax.persistence.spi.PersistenceUnitTransactionType;
+import javax.sql.DataSource;
+import org.apache.aries.jpa.container.parser.impl.PersistenceUnit;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.Version;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
+import org.osgi.service.jdbc.DataSourceFactory;
+@RunWith(MockitoJUnitRunner.class)
public class PropsConfigurationTest {
- @SuppressWarnings({
- "unchecked", "rawtypes"
- })
+ private static final String JDBC_PASSWORD = "123456";
+
+ private static final String JDBC_USER = "bob";
+
+ private static final String JDBC_URL = "jdbc:h2:foo";
+
+ @Mock
+ PersistenceUnit punit;
+
+ @Mock
+ ServiceRegistration<ManagedService> msReg;
+
+ @Mock
+ PersistenceProvider provider;
+
+ @Mock
+ BundleContext containerContext, punitContext;
+
+ @Mock
+ Bundle punitBundle;
+
+ @Mock
+ EntityManagerFactory emf;
+
+ @Mock
+ ServiceRegistration<EntityManagerFactory> emfReg;
+
+ Properties punitProperties = new Properties();
+
+ @Mock
+ ServiceReference<DataSourceFactory> dsfRef;
+
+ @Mock
+ ServiceReference<DataSource> dsRef;
+
+ @Mock
+ DataSourceFactory dsf;
+
+ @Mock
+ DataSource ds;
+
+ @SuppressWarnings("unchecked")
+ @Before
+ public void setup() throws Exception {
+
+ when(punit.getPersistenceUnitName()).thenReturn("test-props");
+ when(punit.getPersistenceProviderClassName())
+ .thenReturn("org.eclipse.persistence.jpa.PersistenceProvider");
+ when(punit.getTransactionType()).thenReturn(PersistenceUnitTransactionType.JTA);
+ when(punit.getBundle()).thenReturn(punitBundle);
+ when(punit.getProperties()).thenReturn(punitProperties);
+
+ when(punitBundle.getBundleContext()).thenReturn(punitContext);
+ when(punitBundle.getVersion()).thenReturn(Version.parseVersion("1.2.3"));
+
+ when(containerContext.registerService(eq(ManagedService.class),
+ any(ManagedService.class), any(Dictionary.class))).thenReturn(msReg);
+ when(containerContext.getService(dsfRef)).thenReturn(dsf);
+ when(containerContext.getService(dsRef)).thenReturn(ds);
+ when(containerContext.createFilter(Mockito.anyString()))
+ .thenAnswer(new Answer<Filter>() {
+ @Override
+ public Filter answer(InvocationOnMock i) throws Throwable {
+ return FrameworkUtil.createFilter(i.getArguments()[0].toString());
+ }
+ });
+
+ when(punitContext.registerService(eq(EntityManagerFactory.class), eq(emf),
+ any(Dictionary.class))).thenReturn(emfReg);
+
+ when(emf.isOpen()).thenReturn(true);
+
+
+ Properties jdbcProps = new Properties();
+ jdbcProps.setProperty("url", JDBC_URL);
+ jdbcProps.setProperty("user", JDBC_USER);
+ jdbcProps.setProperty("password", JDBC_PASSWORD);
+
+ when(dsf.createDataSource(jdbcProps)).thenReturn(ds);
+
+ }
+
+ @Test
+ public void testRegistersManagedEMF() throws InvalidSyntaxException, ConfigurationException {
+
+ AriesEntityManagerFactoryBuilder emfb = new AriesEntityManagerFactoryBuilder(
+ containerContext, provider, punit);
+
+ verify(containerContext).registerService(eq(ManagedService.class),
+ any(ManagedService.class), argThat(servicePropsMatcher(
+ SERVICE_PID, "org.apache.aries.jpa.test-props")));
+
+ // No EMF created as incomplete
+ verifyZeroInteractions(msReg, provider);
+
+ emfb.close();
+ verify(msReg).unregister();
+ }
+
+ private BaseMatcher<Dictionary<String, Object>> servicePropsMatcher(final String key, final Object value) {
+ return new BaseMatcher<Dictionary<String, Object>>() {
+
+ Object props;
+ @SuppressWarnings("unchecked")
+ @Override
+ public boolean matches(Object arg0) {
+ props = arg0;
+ return value.equals(((Dictionary<String, Object>) props).get(key));
+ }
+
+ @Override
+ public void describeTo(Description arg0) {
+ arg0.appendText("Service Properties did not contain " + key +
+ "=" + value + ". Props were " + props);
+ }
+ };
+ }
+
@Test
- public void testEmfWithoutProps() throws InvalidSyntaxException, ConfigurationException {
- PersistenceUnitInfo punit = mock(PersistenceUnitInfo.class);
- when(punit.getPersistenceUnitName()).thenReturn("test-props");
- when(punit.getPersistenceProviderClassName())
- .thenReturn("org.eclipse.persistence.jpa.PersistenceProvider");
- when(punit.getTransactionType()).thenReturn(PersistenceUnitTransactionType.JTA);
- BundleContext context = mock(BundleContext.class);
- ServiceRegistration reg = mock(ServiceRegistration.class);
- when(context.registerService(Mockito.eq(ManagedService.class.getName()), Mockito.any(), Mockito.any(Dictionary.class)))
- .thenReturn(reg);
- Bundle bundle = mock(Bundle.class);
- when(bundle.getBundleContext()).thenReturn(context);
- when(bundle.getVersion()).thenReturn(new Version("4.3.1"));
- PersistenceProvider provider = mock(PersistenceProvider.class);
-
- ManagedEMF emf = new ManagedEMF(context, bundle, provider, punit);
- emf.updated(null);
- emf.close();
- verify(provider, atLeastOnce()).createContainerEntityManagerFactory(Mockito.eq(punit),
- Mockito.eq((Map)null));
- verify(context, atLeastOnce()).registerService(Mockito.eq(EntityManagerFactory.class),
- Mockito.any(EntityManagerFactory.class),
- Mockito.any(Dictionary.class));
+ public void testIncompleteEmfWithoutProps() throws InvalidSyntaxException, ConfigurationException {
+
+ when(provider.createContainerEntityManagerFactory(eq(punit),
+ eq(singletonMap(PersistenceUnitTransactionType.class.getName(), JTA))))
+ .thenReturn(emf);
+
+ AriesEntityManagerFactoryBuilder emfb = new AriesEntityManagerFactoryBuilder(
+ containerContext, provider, punit);
+
+ try {
+ emfb.createEntityManagerFactory(null);
+ fail("Should throw an exception as incomplete");
+ } catch (IllegalArgumentException iae) {
+ // Expected
+ }
+
+
+ // No EMF created as incomplete
+ verifyZeroInteractions(emf, emfReg, provider);
+
+ emfb.close();
+
+ verifyZeroInteractions(emf, emfReg, provider);
}
- @SuppressWarnings({
- "unchecked", "rawtypes"
- })
@Test
- public void testEmfWithProps() throws InvalidSyntaxException, ConfigurationException {
- PersistenceUnitInfo punit = mock(PersistenceUnitInfo.class);
- when(punit.getPersistenceUnitName()).thenReturn("test-props");
- when(punit.getPersistenceProviderClassName())
- .thenReturn("org.eclipse.persistence.jpa.PersistenceProvider");
- when(punit.getTransactionType()).thenReturn(PersistenceUnitTransactionType.JTA);
- BundleContext context = mock(BundleContext.class);
- ServiceRegistration reg = mock(ServiceRegistration.class);
- when(context.registerService(Mockito.eq(ManagedService.class.getName()), Mockito.any(), Mockito.any(Dictionary.class)))
- .thenReturn(reg);
- Bundle bundle = mock(Bundle.class);
- when(bundle.getBundleContext()).thenReturn(context);
- when(bundle.getVersion()).thenReturn(new Version("4.3.1"));
- PersistenceProvider provider = mock(PersistenceProvider.class);
- Dictionary<String, Object> props = new Hashtable<String, Object>();
+ public void testIncompleteEmfWithDSGetsPassed() 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);
+
+
+ verify(punit).setNonJtaDataSource(ds);
+ verify(punitContext).registerService(eq(EntityManagerFactory.class),
+ eq(emf), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")));
+
+ emfb.close();
+
+ verify(emfReg).unregister();
+ verify(emf).close();
+ }
+
+ @Test
+ public void testIncompleteEmfWithPropsGetsPassed() throws InvalidSyntaxException, ConfigurationException {
+
+ Map<String, Object> providerProps = new HashMap<String, Object>();
+ providerProps.put(PersistenceUnitTransactionType.class.getName(), JTA);
+ providerProps.put("hibernate.hbm2ddl.auto", "create-drop");
+
+ when(provider.createContainerEntityManagerFactory(eq(punit),
+ eq(providerProps))).thenReturn(emf);
+
+ Map<String, Object> props = new Hashtable<String, Object>();
props.put("hibernate.hbm2ddl.auto", "create-drop");
- ManagedEMF mEMF = new ManagedEMF(context, bundle, provider, punit);
- mEMF.updated(null);
- mEMF.close();
-
- verify(provider, atLeastOnce()).createContainerEntityManagerFactory(Mockito.eq(punit),
- Mockito.anyMap());
- verify(context, atLeastOnce()).registerService(Mockito.eq(EntityManagerFactory.class),
- Mockito.any(EntityManagerFactory.class),
- Mockito.any(Dictionary.class));
+ props.put("javax.persistence.dataSource", ds);
+
+ AriesEntityManagerFactoryBuilder emfb = new AriesEntityManagerFactoryBuilder(
+ containerContext, provider, punit);
+ emfb.createEntityManagerFactory(props);
+
+
+ verify(punitContext).registerService(eq(EntityManagerFactory.class),
+ eq(emf), and(argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")),
+ argThat(servicePropsMatcher("hibernate.hbm2ddl.auto", "create-drop"))));
+
+ emfb.close();
+ verify(emfReg).unregister();
+ verify(emf).close();
+ }
+
+ @Test
+ public void testPUWithDriverGetsCreatedAutomatically() throws InvalidSyntaxException, ConfigurationException {
+
+ punitProperties.setProperty("javax.persistence.jdbc.driver", "org.h2.Driver");
+ punitProperties.setProperty("javax.persistence.jdbc.url", JDBC_URL);
+ punitProperties.setProperty("javax.persistence.jdbc.user", JDBC_USER);
+ punitProperties.setProperty("javax.persistence.jdbc.password", JDBC_PASSWORD);
+
+ when(containerContext.getServiceReferences((String) null,
+ "(&(objectClass=org.osgi.service.jdbc.DataSourceFactory)(osgi.jdbc.driver.class=org.h2.Driver))"))
+ .thenReturn(new ServiceReference<?>[] {dsfRef});
+
+
+ when(provider.createContainerEntityManagerFactory(eq(punit),
+ any(Map.class))).thenReturn(emf);
+
+ AriesEntityManagerFactoryBuilder emfb = new AriesEntityManagerFactoryBuilder(
+ containerContext, provider, punit);
+
+ verify(punit).setJtaDataSource(ds);
+ verify(punitContext).registerService(eq(EntityManagerFactory.class),
+ eq(emf), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")));
+
+ emfb.close();
+ verify(emfReg).unregister();
+ verify(emf).close();
+ }
+
+ @Test
+ public void testPUWithDriverEMFBReturnsExisting() throws InvalidSyntaxException, ConfigurationException {
+
+ punitProperties.setProperty("javax.persistence.jdbc.driver", "org.h2.Driver");
+ punitProperties.setProperty("javax.persistence.jdbc.url", JDBC_URL);
+ punitProperties.setProperty("javax.persistence.jdbc.user", JDBC_USER);
+ punitProperties.setProperty("javax.persistence.jdbc.password", JDBC_PASSWORD);
+
+ when(containerContext.getServiceReferences((String) null,
+ "(&(objectClass=org.osgi.service.jdbc.DataSourceFactory)(osgi.jdbc.driver.class=org.h2.Driver))"))
+ .thenReturn(new ServiceReference<?>[] {dsfRef});
+
+
+ when(provider.createContainerEntityManagerFactory(eq(punit),
+ any(Map.class))).thenReturn(emf);
+
+ AriesEntityManagerFactoryBuilder emfb = new AriesEntityManagerFactoryBuilder(
+ containerContext, provider, punit);
+
+ verify(punit).setJtaDataSource(ds);
+ verify(punitContext).registerService(eq(EntityManagerFactory.class),
+ eq(emf), 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)))));
+
+ assertSame(emf, emfb.createEntityManagerFactory(null));
+
+ assertSame(emf, emfb.createEntityManagerFactory(new HashMap<String, Object>()));
+
+ verify(provider, Mockito.times(1)).createContainerEntityManagerFactory(
+ any(PersistenceUnitInfo.class), anyMap());
+
+ emfb.close();
+ verify(emfReg).unregister();
+ verify(emf).close();
+ }
+
+ @Test
+ public void testLateBindingDriver() throws InvalidSyntaxException, ConfigurationException {
+
+
+ when(containerContext.getServiceReferences((String) null,
+ "(&(objectClass=org.osgi.service.jdbc.DataSourceFactory)(osgi.jdbc.driver.class=org.h2.Driver))"))
+ .thenReturn(new ServiceReference<?>[] {dsfRef});
+
+
+ when(provider.createContainerEntityManagerFactory(eq(punit),
+ any(Map.class))).thenReturn(emf);
+
+ AriesEntityManagerFactoryBuilder emfb = new AriesEntityManagerFactoryBuilder(
+ containerContext, provider, punit);
+
+ verifyZeroInteractions(provider);
+
+ Map<String, Object> config = new HashMap<String, Object>();
+ config.put("javax.persistence.jdbc.driver", "org.h2.Driver");
+ config.put("javax.persistence.jdbc.url", JDBC_URL);
+ config.put("javax.persistence.jdbc.user", JDBC_USER);
+ config.put("javax.persistence.jdbc.password", JDBC_PASSWORD);
+
+ emfb.createEntityManagerFactory(config);
+
+ verify(punit).setJtaDataSource(ds);
+ verify(punitContext).registerService(eq(EntityManagerFactory.class),
+ eq(emf), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")));
+
+
+ try {
+ config.put("javax.persistence.jdbc.driver", "org.apache.derby.client.ClientDriver");
+ emfb.createEntityManagerFactory(config);
+ fail("Must throw an IllegalArgumentException on rebind");
+ } catch (IllegalArgumentException ise) {
+ // Expected
+ }
+
+ emfb.close();
+ }
+
+ @Test
+ public void testPUWithJtaDSGetsCreatedAutomatically() throws InvalidSyntaxException, ConfigurationException {
+
+ when(containerContext.getServiceReferences((String) null,
+ "(&(objectClass=javax.sql.DataSource)(osgi.jndi.service.name=testds))"))
+ .thenReturn(new ServiceReference<?>[] {dsRef});
+
+ when(punit.getJtaDataSourceName()).thenReturn(
+ "osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=testds)");
+
+ when(provider.createContainerEntityManagerFactory(eq(punit),
+ any(Map.class))).thenReturn(emf);
+
+ AriesEntityManagerFactoryBuilder emfb = new AriesEntityManagerFactoryBuilder(
+ containerContext, provider, punit);
+
+ verify(punit).setJtaDataSource(ds);
+ verify(punitContext).registerService(eq(EntityManagerFactory.class),
+ eq(emf), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")));
+
+ emfb.close();
+ }
+
+ @Test
+ public void testPUWithNonJtaDSGetsCreatedAutomatically() throws InvalidSyntaxException, ConfigurationException {
+
+ when(containerContext.getServiceReferences((String) null,
+ "(&(objectClass=javax.sql.DataSource)(osgi.jndi.service.name=testds))"))
+ .thenReturn(new ServiceReference<?>[] {dsRef});
+
+ when(punit.getTransactionType()).thenReturn(RESOURCE_LOCAL);
+
+ when(punit.getNonJtaDataSourceName()).thenReturn(
+ "osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=testds)");
+
+ when(provider.createContainerEntityManagerFactory(eq(punit),
+ any(Map.class))).thenReturn(emf);
+
+ AriesEntityManagerFactoryBuilder emfb = new AriesEntityManagerFactoryBuilder(
+ containerContext, provider, punit);
+
+ verify(punit).setNonJtaDataSource(ds);
+ verify(punitContext).registerService(eq(EntityManagerFactory.class),
+ eq(emf), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")));
+
+ emfb.close();
}
}