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();
     }
 }