aries-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From timothyjw...@apache.org
Subject svn commit: r1163939 - in /aries/trunk/jpa: jpa-api/ jpa-api/src/main/java/org/apache/aries/jpa/container/ jpa-container-itest/ jpa-container-itest/src/test/java/org/apache/aries/jpa/advanced/features/itest/ jpa-container-itest/src/test/java/org/apache...
Date Thu, 01 Sep 2011 08:27:15 GMT
Author: timothyjward
Date: Thu Sep  1 08:27:14 2011
New Revision: 1163939

URL: http://svn.apache.org/viewvc?rev=1163939&view=rev
Log:
ARIES-736: Support the OSGi JDBC service for obtaining datasources and obey the OSGi JPA Service lifecycle rules 

Added:
    aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerDataSourceFactoryTest.java
    aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/DataSourceFactoryDataSource.java
    aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/JndiDataSource.java
    aries/trunk/jpa/jpa-container/src/test/resources/file25/
    aries/trunk/jpa/jpa-container/src/test/resources/file25/META-INF/
    aries/trunk/jpa/jpa-container/src/test/resources/file25/META-INF/persistence.xml
Modified:
    aries/trunk/jpa/jpa-api/pom.xml
    aries/trunk/jpa/jpa-api/src/main/java/org/apache/aries/jpa/container/ManagedPersistenceUnitInfo.java
    aries/trunk/jpa/jpa-api/src/main/java/org/apache/aries/jpa/container/PersistenceUnitConstants.java
    aries/trunk/jpa/jpa-container-itest/pom.xml
    aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/advanced/features/itest/JPAWeavingAndAnnotationScanningTest.java
    aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerTest.java
    aries/trunk/jpa/jpa-container-testbundle/src/main/resources/META-INF/persistence.xml
    aries/trunk/jpa/jpa-container/pom.xml
    aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/EntityManagerFactoryManager.java
    aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/DelayedLookupDataSource.java
    aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/ManagedPersistenceUnitInfoImpl.java
    aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/PersistenceUnitInfoImpl.java
    aries/trunk/jpa/jpa-container/src/main/resources/org/apache/aries/jpa/container/nls/jpaContainerMessages.properties
    aries/trunk/jpa/jpa-container/src/test/java/org/apache/aries/jpa/container/PersistenceBundleLifecycleTest.java

Modified: aries/trunk/jpa/jpa-api/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-api/pom.xml?rev=1163939&r1=1163938&r2=1163939&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-api/pom.xml (original)
+++ aries/trunk/jpa/jpa-api/pom.xml Thu Sep  1 08:27:14 2011
@@ -48,7 +48,7 @@
         <aries.osgi.import>
              javax.persistence;version="[1.0.0,2.1.0)",
              javax.persistence.spi;version="[1.0.0,2.1.0)",
-             org.osgi.framework;version="[1.5.0,2.0.0)",
+             org.osgi.framework;version="[1.5.0,2.0.0)"
         </aries.osgi.import>
         <aries.osgi.private.pkg />
     </properties>

Modified: aries/trunk/jpa/jpa-api/src/main/java/org/apache/aries/jpa/container/ManagedPersistenceUnitInfo.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-api/src/main/java/org/apache/aries/jpa/container/ManagedPersistenceUnitInfo.java?rev=1163939&r1=1163938&r2=1163939&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-api/src/main/java/org/apache/aries/jpa/container/ManagedPersistenceUnitInfo.java (original)
+++ aries/trunk/jpa/jpa-api/src/main/java/org/apache/aries/jpa/container/ManagedPersistenceUnitInfo.java Thu Sep  1 08:27:14 2011
@@ -51,4 +51,17 @@ public interface ManagedPersistenceUnitI
    */
   public Map<String, Object> getContainerProperties();
   
+  /**
+   * Called to indicate that this persistence unit has been registered in the OSGi
+   * service registry. Note that because this method is called after the service
+   * is registered other threads and listeners may have already accessed the 
+   * persistence unit service.
+   */
+  public void registered();
+  
+  /**
+   * Called to indicate that this persistence unit has been unregistered from the OSGi
+   * service registry. 
+   */
+  public void unregistered();
 }

Modified: aries/trunk/jpa/jpa-api/src/main/java/org/apache/aries/jpa/container/PersistenceUnitConstants.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-api/src/main/java/org/apache/aries/jpa/container/PersistenceUnitConstants.java?rev=1163939&r1=1163938&r2=1163939&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-api/src/main/java/org/apache/aries/jpa/container/PersistenceUnitConstants.java (original)
+++ aries/trunk/jpa/jpa-api/src/main/java/org/apache/aries/jpa/container/PersistenceUnitConstants.java Thu Sep  1 08:27:14 2011
@@ -36,4 +36,15 @@ public interface PersistenceUnitConstant
    *  This allows clients to filter for empty string persistence unit names.
    */
   public static final String EMPTY_PERSISTENCE_UNIT_NAME = "org.apache.aries.jpa.default.unit.name";
+  
+  /**
+   * This property determines whether the Aries JPA container should monitor for DataSourceFactories and only
+   * register the EMF when the DataSource is available
+   */
+  public static final String USE_DATA_SOURCE_FACTORY = "org.apache.aries.jpa.use.data.source.factory";
+  
+  /**
+   * This property name is used to store the JDBC driver class name when using DataSourceFactory integration
+   */
+  public static final String DATA_SOURCE_FACTORY_CLASS_NAME = "org.apache.aries.jpa.data.source.factory.class";
 }

Modified: aries/trunk/jpa/jpa-container-itest/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container-itest/pom.xml?rev=1163939&r1=1163938&r2=1163939&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container-itest/pom.xml (original)
+++ aries/trunk/jpa/jpa-container-itest/pom.xml Thu Sep  1 08:27:14 2011
@@ -48,6 +48,11 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.enterprise</artifactId>
+            <version>4.2.0</version>
+        </dependency>
+        <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <scope>provided</scope>

Modified: aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/advanced/features/itest/JPAWeavingAndAnnotationScanningTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/advanced/features/itest/JPAWeavingAndAnnotationScanningTest.java?rev=1163939&r1=1163938&r2=1163939&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/advanced/features/itest/JPAWeavingAndAnnotationScanningTest.java (original)
+++ aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/advanced/features/itest/JPAWeavingAndAnnotationScanningTest.java Thu Sep  1 08:27:14 2011
@@ -18,6 +18,7 @@ package org.apache.aries.jpa.advanced.fe
 import static org.junit.Assert.assertEquals;
 import static org.ops4j.pax.exam.CoreOptions.equinox;
 import static org.apache.aries.itest.ExtraOptions.*;
+import static org.ops4j.pax.exam.container.def.PaxRunnerOptions.vmOption;
 
 import javax.persistence.EntityManager;
 import javax.persistence.EntityManagerFactory;

Added: aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerDataSourceFactoryTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerDataSourceFactoryTest.java?rev=1163939&view=auto
==============================================================================
--- aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerDataSourceFactoryTest.java (added)
+++ aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerDataSourceFactoryTest.java Thu Sep  1 08:27:14 2011
@@ -0,0 +1,163 @@
+/*  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 WARRANTIES OR 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.itest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.ops4j.pax.exam.CoreOptions.equinox;
+import static org.apache.aries.itest.ExtraOptions.*;
+import static org.ops4j.pax.exam.container.def.PaxRunnerOptions.vmOption;
+
+import java.sql.Driver;
+import java.sql.SQLException;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.sql.ConnectionPoolDataSource;
+import javax.sql.DataSource;
+import javax.sql.XADataSource;
+
+import org.apache.aries.itest.AbstractIntegrationTest;
+import org.apache.aries.jpa.container.PersistenceUnitConstants;
+import org.apache.aries.jpa.container.itest.entities.Car;
+import org.apache.derby.jdbc.EmbeddedDataSource;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.container.def.PaxRunnerOptions;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.jdbc.DataSourceFactory;
+
+@RunWith(JUnit4TestRunner.class)
+public class JPAContainerDataSourceFactoryTest extends AbstractIntegrationTest {
+
+  @Test
+  public void testDataSourceFactoryLifecycle() throws Exception {
+    //Wait for startup
+    context().getService(EntityManagerFactory.class, "(&(osgi.unit.name=test-unit)(" + PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT + "=true))");
+    
+    //Now go
+    ServiceReference[] refs = context().getServiceReferences(
+        EntityManagerFactory.class.getName(), "(&(osgi.unit.name=dsf-test-unit)(" + PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT + "=true))");
+    
+    assertNull(refs);
+    
+    Hashtable<String, Object> props = new Hashtable();
+    props.put(DataSourceFactory.OSGI_JDBC_DRIVER_CLASS, "org.apache.derby.jdbc.EmbeddedDriver");
+    
+    ServiceRegistration reg = context().registerService(DataSourceFactory.class.getName(), 
+        new DerbyDataSourceFactory(), props);
+    
+    
+    EntityManagerFactory emf = context().getService(EntityManagerFactory.class, 
+        "(&(osgi.unit.name=dsf-test-unit)(" + PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT + "=true))");
+    
+    
+    EntityManager em = emf.createEntityManager();
+    
+    em.getTransaction().begin();
+    
+    Car c = new Car();
+    c.setNumberPlate("123456");
+    c.setColour("blue");
+    em.persist(c);
+    
+    em.getTransaction().commit();
+    
+    em.close();
+    
+    em = emf.createEntityManager();
+    
+    assertEquals("blue", em.find(Car.class, "123456").getColour());
+    
+    reg.unregister();
+    
+    refs = context().getServiceReferences(
+        EntityManagerFactory.class.getName(), "(&(osgi.unit.name=dsf-test-unit)(" + PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT + "=true))");
+    
+    assertNull(refs);
+  }
+  
+  private static class DerbyDataSourceFactory implements DataSourceFactory {
+
+    public DataSource createDataSource(Properties props) throws SQLException {
+      EmbeddedDataSource ds = new EmbeddedDataSource();
+      ds.setDatabaseName("memory:TEST");
+      ds.setCreateDatabase("create");
+      return ds;
+    }
+
+    public ConnectionPoolDataSource createConnectionPoolDataSource(
+        Properties props) throws SQLException {
+      // TODO Auto-generated method stub
+      return null;
+    }
+
+    public XADataSource createXADataSource(Properties props)
+        throws SQLException {
+      // TODO Auto-generated method stub
+      return null;
+    }
+
+    public Driver createDriver(Properties props) throws SQLException {
+      // TODO Auto-generated method stub
+      return null;
+    }
+    
+  }
+  
+  @org.ops4j.pax.exam.junit.Configuration
+  public static Option[] configuration() {
+    return testOptions(
+        transactionBootDelegation(),
+        paxLogging("DEBUG"),
+
+        // Bundles
+        mavenBundle("commons-lang", "commons-lang"),
+        mavenBundle("commons-collections", "commons-collections"),
+        mavenBundle("commons-pool", "commons-pool"),
+        mavenBundle("org.apache.aries", "org.apache.aries.util"),
+        mavenBundle("org.apache.aries.blueprint", "org.apache.aries.blueprint"),
+        mavenBundle("asm", "asm-all"),
+        mavenBundle("org.apache.aries.proxy", "org.apache.aries.proxy"),
+        mavenBundle("org.apache.aries.jndi", "org.apache.aries.jndi.api"),
+        mavenBundle("org.apache.aries.jndi", "org.apache.aries.jndi.core"),
+        mavenBundle("org.apache.aries.jndi", "org.apache.aries.jndi.url"),
+        mavenBundle("org.apache.aries.jpa", "org.apache.aries.jpa.api"),
+        mavenBundle("org.apache.aries.jpa", "org.apache.aries.jpa.container"),
+        mavenBundle("org.apache.aries.transaction", "org.apache.aries.transaction.manager" ),
+        mavenBundle("org.apache.aries.transaction", "org.apache.aries.transaction.wrappers" ),
+        mavenBundle("org.apache.derby", "derby"),
+        mavenBundle("org.apache.geronimo.specs", "geronimo-jta_1.1_spec"),
+        mavenBundle("org.apache.geronimo.specs", "geronimo-jpa_2.0_spec"),
+        mavenBundle("org.apache.openjpa", "openjpa"),
+        mavenBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.serp"),
+        mavenBundle("org.osgi", "org.osgi.compendium"),
+        mavenBundle("org.osgi", "org.osgi.enterprise"),
+//        vmOption ("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5006"),
+        //waitForFrameworkStartup(),
+        
+        mavenBundle("org.apache.aries.jpa", "org.apache.aries.jpa.container.itest.bundle"),
+        
+        PaxRunnerOptions.rawPaxRunnerOption("config", "classpath:ss-runner.properties"),
+        equinox().version("3.7.0.v20110613"));
+  }
+
+}

Modified: aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerTest.java?rev=1163939&r1=1163938&r2=1163939&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerTest.java (original)
+++ aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerTest.java Thu Sep  1 08:27:14 2011
@@ -82,10 +82,6 @@ public class JPAContainerTest extends Ab
 
         //vmOption ("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5006"),
         //waitForFrameworkStartup(),
-       
-//        mavenBundle("org.eclipse.persistence", "org.eclipse.persistence.jpa"),
-//        mavenBundle("org.eclipse.persistence", "org.eclipse.persistence.core"),
-//        mavenBundle("org.eclipse.persistence", "org.eclipse.persistence.asm"),
         
         mavenBundle("org.apache.aries.jpa", "org.apache.aries.jpa.container.itest.bundle"),
         

Modified: aries/trunk/jpa/jpa-container-testbundle/src/main/resources/META-INF/persistence.xml
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container-testbundle/src/main/resources/META-INF/persistence.xml?rev=1163939&r1=1163938&r2=1163939&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container-testbundle/src/main/resources/META-INF/persistence.xml (original)
+++ aries/trunk/jpa/jpa-container-testbundle/src/main/resources/META-INF/persistence.xml Thu Sep  1 08:27:14 2011
@@ -46,4 +46,18 @@
      <property name="openjpa.jdbc.DBDictionary" value="derby"/>
     </properties>
   </persistence-unit>
+  
+  <persistence-unit name="dsf-test-unit" transaction-type="RESOURCE_LOCAL">
+    <description>Test persistence unit for the JPA Container DataSourceFactory iTests</description>
+    <class>org.apache.aries.jpa.container.itest.entities.Car</class>
+    <exclude-unlisted-classes>true</exclude-unlisted-classes>
+    <properties>
+     <!-- These properties are creating the database on the fly. We are using them to avoid the tests having
+          to create a database  -->
+      <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver"/>
+      <property name="javax.persistence.jdbc.url" value="jdbc:derby:memory:TEST;create=true"/>
+     <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
+     <property name="openjpa.jdbc.DBDictionary" value="derby"/>
+    </properties>
+  </persistence-unit>
 </persistence>

Modified: aries/trunk/jpa/jpa-container/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/pom.xml?rev=1163939&r1=1163938&r2=1163939&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container/pom.xml (original)
+++ aries/trunk/jpa/jpa-container/pom.xml Thu Sep  1 08:27:14 2011
@@ -53,6 +53,7 @@
             org.osgi.framework;version="[1.5,2)",
             org.osgi.framework.hooks.weaving;version="[1,1.1)";resolution:=optional,
             org.osgi.framework.wiring;version="[1,2)";resolution:=optional,
+            org.osgi.service.jdbc;version="[1,2)";resolution:=optional,
             *
         </aries.osgi.import>
       <aries.osgi.activator>
@@ -149,6 +150,13 @@
             <artifactId>junit</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+        	<groupId>org.osgi</groupId>
+        	<artifactId>org.osgi.enterprise</artifactId>
+        	<version>4.2.0</version>
+        	<type>jar</type>
+        	<scope>compile</scope>
+        </dependency>
     </dependencies>
 
 </project>

Modified: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/EntityManagerFactoryManager.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/EntityManagerFactoryManager.java?rev=1163939&r1=1163938&r2=1163939&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/EntityManagerFactoryManager.java (original)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/EntityManagerFactoryManager.java Thu Sep  1 08:27:14 2011
@@ -20,6 +20,7 @@ package org.apache.aries.jpa.container.i
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Hashtable;
@@ -41,13 +42,15 @@ import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 /**
  * This class manages the lifecycle of Persistence Units and their associated
  * {@link EntityManagerFactory} objects.
  */
-public class EntityManagerFactoryManager {
+public class EntityManagerFactoryManager implements ServiceTrackerCustomizer {
 
   /**
    * A callback for a named persistence units
@@ -76,8 +79,8 @@ public class EntityManagerFactoryManager
   private final Bundle bundle;
   /** The {@link PersistenceProvider} to use */
   private ServiceReference provider;
-  /** The persistence units to manage */
-  private Collection<? extends ManagedPersistenceUnitInfo> persistenceUnits;
+  /** The named persistence units to manage */
+  private Map<String, ? extends ManagedPersistenceUnitInfo> persistenceUnits;
   /** The original parsed data */
   private Collection<ParsedPersistenceUnit> parsedData;
   /** A Map of created {@link EntityManagerFactory}s */
@@ -86,6 +89,12 @@ public class EntityManagerFactoryManager
   private ConcurrentMap<String, ServiceRegistration> registrations = null;
   /** Quiesce this Manager */
   private boolean quiesce = false;
+  
+  private volatile ServiceTracker tracker; 
+  
+  /** DataSourceFactories in use by persistence units in this bundle - class name key to collection of unit values */
+  private final ConcurrentMap<String, Collection<String>> dataSourceFactories = 
+         new ConcurrentHashMap<String, Collection<String>>();
 
   /** Logger */
   private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container");
@@ -108,10 +117,22 @@ public class EntityManagerFactoryManager
     containerContext = containerCtx;
     bundle = b;
     provider = ref;
-    persistenceUnits = infos;
+    persistenceUnits = getInfoMap(infos);
     parsedData = parsedUnits;
   }
 
+  private Map<String, ? extends ManagedPersistenceUnitInfo> getInfoMap(
+      Collection<? extends ManagedPersistenceUnitInfo> infos) {
+    Map<String, ManagedPersistenceUnitInfo> map = Collections.synchronizedMap(
+        new HashMap<String, ManagedPersistenceUnitInfo>());
+    if (infos != null) {
+      for(ManagedPersistenceUnitInfo info : infos) {
+        map.put(info.getPersistenceUnitInfo().getPersistenceUnitName(), info);
+      }
+    }
+    return map;
+  }
+
   /**
    * Notify the {@link EntityManagerFactoryManager} that a provider is being
    * removed from the service registry.
@@ -156,14 +177,22 @@ public class EntityManagerFactoryManager
         //Starting and active both require EMFs to be registered
       case Bundle.STARTING :
       case Bundle.ACTIVE :
+        if(tracker == null) {
+          tracker = new ServiceTracker(bundle.getBundleContext(), 
+              "org.osgi.service.jdbc.DataSourceFactory", this);
+          tracker.open();
+        }
         registerEntityManagerFactories();
         break;
         //Stopping means the EMFs should
       case Bundle.STOPPING :
         //If we're stopping we no longer need to be quiescing
         quiesce = false;
+        if(tracker != null) {
+          tracker.close();
+          tracker = null;
+        }
         unregisterEntityManagerFactories();
-        
         break;
       case Bundle.INSTALLED :
         //Destroy everything
@@ -180,12 +209,21 @@ public class EntityManagerFactoryManager
       for(Entry<String, ServiceRegistration> entry : registrations.entrySet()) {
         AriesFrameworkUtil.safeUnregisterService(entry.getValue());
         emfs.get(entry.getKey()).clearQuiesce();
+        persistenceUnits.get(entry.getKey()).unregistered();
       }
       // remember to set registrations to be null
       registrations = null;
     }
   }
 
+  private void unregisterEntityManagerFactory(String unit) {
+    if(registrations != null) {
+      AriesFrameworkUtil.safeUnregisterService(registrations.remove(unit));
+      emfs.get(unit).clearQuiesce();
+      persistenceUnits.get(unit).unregistered();
+    }
+  }
+
   /**
    * Register {@link EntityManagerFactory} services
    * 
@@ -194,12 +232,15 @@ public class EntityManagerFactoryManager
    */
   private void registerEntityManagerFactories() throws InvalidPersistenceUnitException {
     //Only register if there is a provider and we are not
-    //already registered
-    if(provider != null && registrations == null && !quiesce) {
+    //quiescing
+    if(registrations == null) {
+      registrations = new ConcurrentHashMap<String, ServiceRegistration>();
+    }
+    
+    if(provider != null && !quiesce) {
       //Make sure the EntityManagerFactories are instantiated
       createEntityManagerFactories();
       
-      registrations = new ConcurrentHashMap<String, ServiceRegistration>();
       String providerName = (String) provider.getProperty("javax.persistence.provider");
       if(providerName == null) {
         _logger.warn( NLS.MESSAGES.getMessage("no.provider.specified", 
@@ -209,17 +250,23 @@ public class EntityManagerFactoryManager
       //Register each EMF
       for(Entry<String, ? extends EntityManagerFactory> entry : emfs.entrySet())
       {
+        
         Hashtable<String,Object> props = new Hashtable<String, Object>();
         String unitName = entry.getKey();
-          
+        
+        if(registrations.containsKey(unitName) || !!!availableDataSourceFactory(unitName))
+          continue;
+        
         props.put(PersistenceUnitConstants.OSGI_UNIT_NAME, unitName);
         if(providerName != null)
           props.put(PersistenceUnitConstants.OSGI_UNIT_PROVIDER, providerName);
-          props.put(PersistenceUnitConstants.OSGI_UNIT_VERSION, provider.getBundle().getVersion());
-          props.put(PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT, Boolean.TRUE);
-          props.put(PersistenceUnitConstants.EMPTY_PERSISTENCE_UNIT_NAME, "".equals(unitName));
+        
+        props.put(PersistenceUnitConstants.OSGI_UNIT_VERSION, bundle.getVersion());
+        props.put(PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT, Boolean.TRUE);
+        props.put(PersistenceUnitConstants.EMPTY_PERSISTENCE_UNIT_NAME, "".equals(unitName));
         try {
           registrations.put(unitName, bundle.getBundleContext().registerService(EntityManagerFactory.class.getCanonicalName(), entry.getValue(), props));
+          persistenceUnits.get(unitName).registered();
         } catch (Exception e) {
           _logger.error(NLS.MESSAGES.getMessage("cannot.register.persistence.unit", unitName, bundle.getSymbolicName() + '/' + bundle.getVersion()));
           throw new InvalidPersistenceUnitException(e);
@@ -228,6 +275,34 @@ public class EntityManagerFactoryManager
     }
   }
 
+  private boolean availableDataSourceFactory(String unitName) {
+    ManagedPersistenceUnitInfo mpui = persistenceUnits.get(unitName);
+        
+    String driver = (String) mpui.getPersistenceUnitInfo().getProperties().
+    get(PersistenceUnitConstants.DATA_SOURCE_FACTORY_CLASS_NAME);
+    
+    //True if the property is not "true" and the jdbc driver is set
+    if(Boolean.parseBoolean((String)mpui.getContainerProperties().
+        get(PersistenceUnitConstants.USE_DATA_SOURCE_FACTORY)) &&
+        driver != null) {
+      
+      if(dataSourceFactories.containsKey(driver)) {
+        dataSourceFactories.get(driver).add(unitName);
+        if(_logger.isDebugEnabled())
+          _logger.debug(NLS.MESSAGES.getMessage("datasourcefactory.found", unitName, bundle.getSymbolicName(),
+              bundle.getVersion(), driver));
+        return true;
+      }
+      if(_logger.isDebugEnabled())
+        _logger.debug(NLS.MESSAGES.getMessage("datasourcefactory.not.found", unitName, bundle.getSymbolicName(),
+            bundle.getVersion(), driver));
+      return false;
+    } else {
+      //We aren't checking (thanks to the property or a null jdbc driver name)
+      return true;
+    }
+  }
+
   /**
    * Create {@link EntityManagerFactory} services for this peristence unit
    * throws InvalidPersistenceUnitException if this {@link EntityManagerFactory} is no longer
@@ -248,12 +323,12 @@ public class EntityManagerFactoryManager
             throw new InvalidPersistenceUnitException();
           }
 
-          for(ManagedPersistenceUnitInfo info : persistenceUnits){
-            PersistenceUnitInfo pUnitInfo = info.getPersistenceUnitInfo();
-        
-            emfs.put(pUnitInfo.getPersistenceUnitName(), new CountingEntityManagerFactory(
+          for(Entry<String, ? extends ManagedPersistenceUnitInfo> entry : 
+               persistenceUnits.entrySet()){
+            ManagedPersistenceUnitInfo mpui = entry.getValue();
+            emfs.put(entry.getKey(), new CountingEntityManagerFactory(
                 providerService.createContainerEntityManagerFactory(
-                    pUnitInfo, info.getContainerProperties()), pUnitInfo.getPersistenceUnitName()));
+                    mpui.getPersistenceUnitInfo(), mpui.getContainerProperties()), entry.getKey()));
           }
         } finally {
           //Remember to unget the provider
@@ -275,7 +350,7 @@ public class EntityManagerFactoryManager
   public synchronized void manage(ServiceReference ref,
       Collection<? extends ManagedPersistenceUnitInfo> infos)  throws IllegalStateException{
     provider = ref;
-    persistenceUnits = infos;
+    persistenceUnits = getInfoMap(infos);
   }
   
   /**
@@ -292,7 +367,7 @@ public class EntityManagerFactoryManager
       Collection<? extends ManagedPersistenceUnitInfo> infos)  throws IllegalStateException{
     parsedData = parsedUnits;
     provider = ref;
-    persistenceUnits = infos;
+    persistenceUnits = getInfoMap(infos);
   }
 
   /**
@@ -305,6 +380,10 @@ public class EntityManagerFactoryManager
     
     provider = null;
     persistenceUnits = null;
+    if(tracker != null) {
+      tracker.close();
+      tracker = null;
+    }
   }
 
   /**
@@ -361,4 +440,76 @@ public class EntityManagerFactoryManager
     }
   }
 
+  @Override
+  public StringBuffer addingService(ServiceReference reference) {
+    //Use String.valueOf to save us from nulls
+    StringBuffer sb = new StringBuffer(String.valueOf(reference.getProperty("osgi.jdbc.driver.class")));
+    
+    //Only notify of a potential change if a new data source class is available
+    if(dataSourceFactories.putIfAbsent(sb.toString(), new ArrayList<String>()) == null) {
+      if(_logger.isDebugEnabled())
+        _logger.debug(NLS.MESSAGES.getMessage("new.datasourcefactory.available", sb.toString(), 
+            bundle.getSymbolicName(), bundle.getVersion()));
+      try {
+        bundleStateChange();
+      } catch (InvalidPersistenceUnitException e) {
+        //Not much we can do here unfortunately
+        _logger.warn(NLS.MESSAGES.getMessage("new.datasourcefactory.error", sb.toString(), 
+          bundle.getSymbolicName(), bundle.getVersion()), e);
+      }
+    }
+    return sb;
+  }
+
+  @Override
+  public void modifiedService(ServiceReference reference, Object service) {
+    //Updates only matter if they change the value of the driver class
+    if(!!!service.toString().equals(reference.getProperty("osgi.jdbc.driver.class"))) {
+      
+      if(_logger.isDebugEnabled())
+        _logger.debug(NLS.MESSAGES.getMessage("changed.datasourcefactory.available", service.toString(), 
+            reference.getProperty("osgi.jdbc.driver.class"), bundle.getSymbolicName(), bundle.getVersion()));
+      
+      //Remove the service
+      removedService(reference, service);
+      //Clear the old driver class
+      StringBuffer sb = (StringBuffer) service;
+      sb.delete(0, sb.length());
+      //add the new one
+      sb.append(addingService(reference));
+    }
+  }
+
+  @Override
+  public void removedService(ServiceReference reference, Object service) {
+    
+    if(_logger.isDebugEnabled())
+      _logger.debug(NLS.MESSAGES.getMessage("datasourcefactory.unavailable", service.toString(), 
+          bundle.getSymbolicName(), bundle.getVersion()));
+    
+    Object[] objects = tracker.getServices();
+
+    boolean gone = true;
+    if(objects != null) {
+      for(Object o : objects) {
+        if(service.equals(o)) {
+          gone = false;
+          break;
+        }
+      }
+    }
+    if(gone) {
+      Collection<String> units = dataSourceFactories.remove(service.toString());
+      if(units != null) {
+        synchronized (this) {
+          if(_logger.isInfoEnabled())
+            _logger.info(NLS.MESSAGES.getMessage("in.use.datasourcefactory.unavailable", service.toString(), 
+                bundle.getSymbolicName(), bundle.getVersion(), units));
+          for(String unit : units) {
+            unregisterEntityManagerFactory(unit);
+          }
+        }
+      } 
+    }
+  }
 }

Added: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/DataSourceFactoryDataSource.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/DataSourceFactoryDataSource.java?rev=1163939&view=auto
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/DataSourceFactoryDataSource.java (added)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/DataSourceFactoryDataSource.java Thu Sep  1 08:27:14 2011
@@ -0,0 +1,121 @@
+/*
+ * 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.unit.impl;
+
+import java.sql.SQLException;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.sql.DataSource;
+
+import org.apache.aries.jpa.container.impl.NLS;
+import org.apache.aries.util.tracker.SingleServiceTracker;
+import org.apache.aries.util.tracker.SingleServiceTracker.SingleServiceListener;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.jdbc.DataSourceFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DataSourceFactoryDataSource extends DelayedLookupDataSource implements SingleServiceListener {
+  /** Logger */
+  private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container");
+  
+  private AtomicReference<DataSource> ds = new AtomicReference<DataSource>();
+  
+  private final String driverName;
+  private final Bundle persistenceBundle;
+  private final Properties props;
+  
+  private final AtomicReference<SingleServiceTracker<DataSourceFactory>> trackerRef =
+    new AtomicReference<SingleServiceTracker<DataSourceFactory>>();
+  
+  public DataSourceFactoryDataSource(Bundle bundle, String driverName, String dbURL, 
+      String dbUserName, String dbPassword) {
+    this.persistenceBundle = bundle;
+    this.driverName = driverName;
+    props = new Properties();
+    if(dbURL != null)
+      props.setProperty(DataSourceFactory.JDBC_URL, dbURL);
+    if(dbUserName != null)
+      props.setProperty(DataSourceFactory.JDBC_USER, dbUserName);
+    if(dbPassword != null)
+      props.setProperty(DataSourceFactory.JDBC_PASSWORD, dbPassword);
+  }
+
+  @Override
+  protected DataSource getDs() {
+    if(ds.get() == null) {
+      SingleServiceTracker<DataSourceFactory> tracker = trackerRef.get();
+      
+      if(tracker == null) {
+        try {
+          tracker = new SingleServiceTracker<DataSourceFactory>(
+              persistenceBundle.getBundleContext(), DataSourceFactory.class, "(" +
+              DataSourceFactory.OSGI_JDBC_DRIVER_CLASS + "=" + driverName + ")", this);
+        } catch (InvalidSyntaxException ise) {
+          //This should never happen
+          throw new RuntimeException(ise);
+        }
+        if(trackerRef.compareAndSet(null, tracker))
+          tracker.open();
+        else 
+          tracker = trackerRef.get(); 
+      } 
+      
+      DataSourceFactory dsf = tracker.getService();
+      if(dsf != null) {
+        try {
+          ds.compareAndSet(null, dsf.createDataSource(props));
+        } catch (SQLException e) {
+          String message = NLS.MESSAGES.getMessage("datasourcefactory.sql.exception", driverName, props, 
+              persistenceBundle.getSymbolicName(), persistenceBundle.getVersion());
+          _logger.error(message, e);
+          throw new RuntimeException(message, e);
+        }
+      } else {
+        _logger.error(NLS.MESSAGES.getMessage("no.datasource.factory", driverName, props, 
+            persistenceBundle.getSymbolicName(), persistenceBundle.getVersion()));
+      }
+    }
+    return ds.get();
+  }
+
+  public void closeTrackers() {
+    SingleServiceTracker<DataSourceFactory> tracker = trackerRef.getAndSet(null);
+    if(tracker != null) {
+      tracker.close();
+    }
+  }
+
+  @Override
+  public void serviceFound() {
+    //No op
+  }
+
+  @Override
+  public void serviceLost() {
+    ds.set(null);
+  }
+
+  @Override
+  public void serviceReplaced() {
+    ds.set(null);
+  }
+}

Modified: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/DelayedLookupDataSource.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/DelayedLookupDataSource.java?rev=1163939&r1=1163938&r2=1163939&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/DelayedLookupDataSource.java (original)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/DelayedLookupDataSource.java Thu Sep  1 08:27:14 2011
@@ -21,54 +21,13 @@ package org.apache.aries.jpa.container.u
 import java.io.PrintWriter;
 import java.sql.Connection;
 import java.sql.SQLException;
-import java.util.Hashtable;
 
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
 import javax.sql.DataSource;
 
-import org.apache.aries.jpa.container.impl.NLS;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class DelayedLookupDataSource implements DataSource {
-
-  /** Logger */
-  private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container");
-  
-  private DataSource ds = null;
-  
-  private DataSource getDs() {
-    if(ds == null) {
-      try {
-        
-        Hashtable<String, Object> props = new Hashtable<String, Object>();
-        
-        BundleContext bCtx = persistenceBundle.getBundleContext();
-        if(bCtx == null)
-          throw new IllegalStateException(NLS.MESSAGES.getMessage("persistence.bundle.not.active", persistenceBundle.getSymbolicName(), persistenceBundle.getVersion()));
-        props.put("osgi.service.jndi.bundleContext", bCtx);
-        InitialContext ctx = new InitialContext(props);
-        ds = (DataSource) ctx.lookup(jndiName);
-      } catch (NamingException e) {
-        String message = NLS.MESSAGES.getMessage("no.data.source.found", jndiName, persistenceBundle.getSymbolicName(), persistenceBundle.getVersion());
-        _logger.error(message, e);
-        throw new RuntimeException(message, e);
-      }
-    }
-    return ds;
-  }
-
-  private final String jndiName;
-  private final Bundle persistenceBundle;
-  
-  public DelayedLookupDataSource (String jndi, Bundle persistenceBundle) {
-    jndiName = jndi;
-    this.persistenceBundle = persistenceBundle;
-  }
-  
+public abstract class DelayedLookupDataSource implements DataSource {
+
+  protected abstract DataSource getDs();
+
   public Connection getConnection() throws SQLException {
     return getDs().getConnection();
   }

Added: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/JndiDataSource.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/JndiDataSource.java?rev=1163939&view=auto
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/JndiDataSource.java (added)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/JndiDataSource.java Thu Sep  1 08:27:14 2011
@@ -0,0 +1,69 @@
+/*
+ * 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.unit.impl;
+
+import java.util.Hashtable;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.sql.DataSource;
+
+import org.apache.aries.jpa.container.impl.NLS;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JndiDataSource extends DelayedLookupDataSource {
+  /** Logger */
+  private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container");
+  
+  private AtomicReference<DataSource> ds = new AtomicReference<DataSource>();
+  
+  private final String jndiName;
+  private final Bundle persistenceBundle;
+  
+  public JndiDataSource (String jndi, Bundle persistenceBundle) {
+    jndiName = jndi;
+    this.persistenceBundle = persistenceBundle;
+  }
+  
+  @Override
+  protected DataSource getDs() {
+    if(ds.get() == null) {
+      try {
+        Hashtable<String, Object> props = new Hashtable<String, Object>();
+        
+        BundleContext bCtx = persistenceBundle.getBundleContext();
+        if(bCtx == null)
+          throw new IllegalStateException(NLS.MESSAGES.getMessage("persistence.bundle.not.active", persistenceBundle.getSymbolicName(), persistenceBundle.getVersion()));
+        props.put("osgi.service.jndi.bundleContext", bCtx);
+        InitialContext ctx = new InitialContext(props);
+        ds.compareAndSet(null, (DataSource) ctx.lookup(jndiName));
+      } catch (NamingException e) {
+        String message = NLS.MESSAGES.getMessage("no.data.source.found", jndiName, persistenceBundle.getSymbolicName(), persistenceBundle.getVersion());
+        _logger.error(message, e);
+        throw new RuntimeException(message, e);
+      }
+    }
+    return ds.get();
+  }
+
+}

Modified: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/ManagedPersistenceUnitInfoImpl.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/ManagedPersistenceUnitInfoImpl.java?rev=1163939&r1=1163938&r2=1163939&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/ManagedPersistenceUnitInfoImpl.java (original)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/ManagedPersistenceUnitInfoImpl.java Thu Sep  1 08:27:14 2011
@@ -18,29 +18,53 @@
  */
 package org.apache.aries.jpa.container.unit.impl;
 
-import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map;
 
 import javax.persistence.spi.PersistenceUnitInfo;
 
 import org.apache.aries.jpa.container.ManagedPersistenceUnitInfo;
+import org.apache.aries.jpa.container.PersistenceUnitConstants;
+import org.apache.aries.jpa.container.impl.NLS;
 import org.apache.aries.jpa.container.parsing.ParsedPersistenceUnit;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class ManagedPersistenceUnitInfoImpl implements
     ManagedPersistenceUnitInfo {
-
+  /** Logger */
+  private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container");
+  
+  private static final Boolean useDataSourceFactory;
+  
+  static {
+    boolean b;
+    try {
+      Class.forName("org.osgi.service.jdbc.DataSourceFactory", false, 
+          ManagedPersistenceUnitInfoImpl.class.getClassLoader());
+      b = true;
+    } catch (ClassNotFoundException cnfe) {
+      if(_logger.isInfoEnabled())
+        _logger.info(NLS.MESSAGES.getMessage("no.datasourcefactory.integration"));
+      b = false;
+    }
+    useDataSourceFactory = b;
+  }
+  
   private final PersistenceUnitInfoImpl info;
   
   public ManagedPersistenceUnitInfoImpl(Bundle persistenceBundle,
       ParsedPersistenceUnit unit,
       ServiceReference providerRef) {
-    info = new PersistenceUnitInfoImpl(persistenceBundle, unit, providerRef);
+    info = new PersistenceUnitInfoImpl(persistenceBundle, unit, providerRef, useDataSourceFactory);
   }
 
   public Map<String, Object> getContainerProperties() {
-    return Collections.emptyMap();
+    Map<String, Object> props = new HashMap<String, Object>();
+    props.put(PersistenceUnitConstants.USE_DATA_SOURCE_FACTORY, useDataSourceFactory.toString());
+    return props;
   }
 
   public PersistenceUnitInfo getPersistenceUnitInfo() {
@@ -50,4 +74,14 @@ public class ManagedPersistenceUnitInfoI
   public void destroy() {
     info.clearUp();
   }
+
+  @Override
+  public void registered() {
+   //No op, our PersistenceUnitInfoImpl is lazy
+  }
+
+  @Override
+  public void unregistered() {
+    info.unregistered();
+  }
 }

Modified: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/PersistenceUnitInfoImpl.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/PersistenceUnitInfoImpl.java?rev=1163939&r1=1163938&r2=1163939&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/PersistenceUnitInfoImpl.java (original)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/PersistenceUnitInfoImpl.java Thu Sep  1 08:27:14 2011
@@ -32,6 +32,7 @@ import javax.persistence.spi.Persistence
 import javax.persistence.spi.PersistenceUnitTransactionType;
 import javax.sql.DataSource;
 
+import org.apache.aries.jpa.container.PersistenceUnitConstants;
 import org.apache.aries.jpa.container.annotation.impl.AnnotationScanner;
 import org.apache.aries.jpa.container.annotation.impl.AnnotationScannerFactory;
 import org.apache.aries.jpa.container.impl.NLS;
@@ -52,19 +53,33 @@ public class PersistenceUnitInfoImpl imp
   
   private final ServiceReference providerRef;
   
+  private final Boolean useDataSourceFactory;
+  
   private ClassTransformer transformer;
   
+  private final AtomicReference<DataSourceFactoryDataSource> jtaDSFDS = 
+    new AtomicReference<DataSourceFactoryDataSource>();
+  
+  private final AtomicReference<DataSourceFactoryDataSource> nonJtaDSFDS = 
+    new AtomicReference<DataSourceFactoryDataSource>();
+  
   // initialize it lazily because we create a PersistenceUnitInfoImpl when the bundle is INSTALLED state
   private final AtomicReference<ClassLoader> cl = new AtomicReference<ClassLoader>();
   
   /** Logger */
   private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container");
   
-  public PersistenceUnitInfoImpl (Bundle b, ParsedPersistenceUnit parsedData, final ServiceReference providerRef)
+  public PersistenceUnitInfoImpl (Bundle b, ParsedPersistenceUnit parsedData, 
+      final ServiceReference providerRef, Boolean globalUsedatasourcefactory)
   {
     bundle = b;
     unit = parsedData;
     this.providerRef = providerRef;
+    //Local override for global DataSourceFactory usage
+    Boolean localUseDataSourceFactory = Boolean.parseBoolean(getInternalProperties().getProperty(
+        PersistenceUnitConstants.USE_DATA_SOURCE_FACTORY, "true"));
+    
+    this.useDataSourceFactory = globalUsedatasourcefactory && localUseDataSourceFactory;
   }
   
   public synchronized void addTransformer(ClassTransformer arg0) {
@@ -114,7 +129,24 @@ public class PersistenceUnitInfoImpl imp
     String jndiString = (String) unit.getPersistenceXmlMetadata().get(ParsedPersistenceUnit.JTA_DATASOURCE);
     DataSource toReturn = null;
     if(jndiString != null) {
-      toReturn = new DelayedLookupDataSource(jndiString, bundle);
+      toReturn = new JndiDataSource(jndiString, bundle);
+    } else if(useDataSourceFactory) {
+      toReturn = jtaDSFDS.get();
+      if(toReturn == null) {
+        Properties props = getInternalProperties();
+        String driverName = props.getProperty("javax.persistence.jdbc.driver");
+        if(driverName != null) {
+          if(_logger.isDebugEnabled())
+            _logger.debug(NLS.MESSAGES.getMessage("using.datasource.factory", getPersistenceUnitName(),
+                bundle.getSymbolicName(), bundle.getVersion()));
+          
+          jtaDSFDS.compareAndSet(null, new DataSourceFactoryDataSource(bundle, driverName,
+              props.getProperty("javax.persistence.jdbc.url"), 
+              props.getProperty("javax.persistence.jdbc.user"), 
+              props.getProperty("javax.persistence.jdbc.password")));
+          toReturn = jtaDSFDS.get();
+        }
+      }
     }
     return toReturn;
   }
@@ -152,7 +184,24 @@ public class PersistenceUnitInfoImpl imp
     String jndiString = (String) unit.getPersistenceXmlMetadata().get(ParsedPersistenceUnit.NON_JTA_DATASOURCE);
     DataSource toReturn = null;
     if(jndiString != null) {
-      toReturn = new DelayedLookupDataSource(jndiString, bundle);
+      toReturn = new JndiDataSource(jndiString, bundle);
+    } else if(useDataSourceFactory) {
+      toReturn = nonJtaDSFDS.get();
+      if(toReturn == null) {
+        Properties props = getInternalProperties();
+        String driverName = props.getProperty("javax.persistence.jdbc.driver");
+        if(driverName != null) {
+          if(_logger.isDebugEnabled())
+            _logger.debug(NLS.MESSAGES.getMessage("using.datasource.factory", getPersistenceUnitName(),
+                bundle.getSymbolicName(), bundle.getVersion()));
+          
+          nonJtaDSFDS.compareAndSet(null, new DataSourceFactoryDataSource(bundle, driverName,
+              props.getProperty("javax.persistence.jdbc.url"), 
+              props.getProperty("javax.persistence.jdbc.user"), 
+              props.getProperty("javax.persistence.jdbc.password")));
+          toReturn = nonJtaDSFDS.get();
+        }
+      }
     }
     return toReturn;
   }
@@ -173,9 +222,22 @@ public class PersistenceUnitInfoImpl imp
     return (String) unit.getPersistenceXmlMetadata().get(ParsedPersistenceUnit.SCHEMA_VERSION);
   }
 
-  public Properties getProperties() {
+  private Properties getInternalProperties() {
     return (Properties) unit.getPersistenceXmlMetadata().get(ParsedPersistenceUnit.PROPERTIES);
   }
+  
+  public Properties getProperties() {
+    Properties p = new Properties();
+    p.putAll(getInternalProperties());
+    
+    String jdbcClass = p.getProperty("javax.persistence.jdbc.driver");
+    if(useDataSourceFactory && jdbcClass != null) {
+      p.setProperty(PersistenceUnitConstants.DATA_SOURCE_FACTORY_CLASS_NAME, 
+          jdbcClass);
+      p.remove("javax.persistence.jdbc.driver");
+    }
+    return p;
+  }
 
   public SharedCacheMode getSharedCacheMode() {
     String s = (String) unit.getPersistenceXmlMetadata().get(ParsedPersistenceUnit.SHARED_CACHE_MODE);
@@ -214,4 +276,16 @@ public class PersistenceUnitInfoImpl imp
     }
   }
   
+  public void unregistered() {
+    DataSourceFactoryDataSource dsfds = jtaDSFDS.get();
+    if(dsfds != null) {
+      dsfds.closeTrackers();
+    }
+    
+    dsfds = nonJtaDSFDS.get();
+    if(dsfds != null) {
+      dsfds.closeTrackers();
+    }
+  }
+  
 }
\ No newline at end of file

Modified: aries/trunk/jpa/jpa-container/src/main/resources/org/apache/aries/jpa/container/nls/jpaContainerMessages.properties
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/resources/org/apache/aries/jpa/container/nls/jpaContainerMessages.properties?rev=1163939&r1=1163938&r2=1163939&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/resources/org/apache/aries/jpa/container/nls/jpaContainerMessages.properties (original)
+++ aries/trunk/jpa/jpa-container/src/main/resources/org/apache/aries/jpa/container/nls/jpaContainerMessages.properties Thu Sep  1 08:27:14 2011
@@ -141,5 +141,49 @@ jpa.weaving.failure=There was an error a
 jpa.weaving.transformer.not.registered=The transformer {0} cannot be unregistered because it has not been registered.
 jpa.weaving.null.transformer=The delegate transformer must not be null.
 jpa.weaving.null.provider=The persistence provider must not be null.
-
-
+# {0} The new JDBC class name that is available.
+# {1} The symbolic name of the persistence bundle.
+# {2} The version of the persistence bundle.
+new.datasourcefactory.available=A DataSourceFactory service for {0} is now available for use by persistence bundle {1}/{2}.
+# {0} The new JDBC class name that is available.
+# {1} The symbolic name of the persistence bundle.
+# {2} The version of the persistence bundle.
+new.datasourcefactory.error=There was an error updating the persistence units in bundle {1}/{2} when a DataSourceFactory service for {0} became available.
+# {0} The old JDBC class name that is no longer available.
+# {1} The new JDBC class name that is becoming available.
+# {2} The symbolic name of the persistence bundle.
+# {3} The version of the persistence bundle.
+changed.datasourcefactory.available=A DataSourceFactory service for {0} was modified so that it now provides DataSources for {1}. This may affect the running persistence bundle {2}/{3}.
+# {0} The JDBC class name that is no longer available.
+# {1} The symbolic name of the persistence bundle.
+# {2} The version of the persistence bundle.
+# {3} The persistence units that will be unregistered
+in.use.datasourcefactory.unavailable=No DataSourceFactory services for {0} are available from persistence bundle {1}/{2}. The persistence units {3} will now be unregistered.
+# {0} The JDBC class name that going away.
+# {1} The symbolic name of the persistence bundle.
+# {2} The version of the persistence bundle.
+datasourcefactory.unavailable=A DataSourceFactory service for {0} has been unregistered and is no longer available for use by persistence bundle {1}/{2}.
+# {0} The name of the persistence unit.
+# {1} The symbolic name of the persistence bundle.
+# {2} The version of the persistence bundle.
+# {3} The name of the JDBC driver class
+datasourcefactory.found=The persistence unit {0} in bundle {1}/{2} will now be registered and use JDBC driver {3}.
+# {0} The name of the persistence unit.
+# {1} The symbolic name of the persistence bundle.
+# {2} The version of the persistence bundle.
+# {3} The name of the JDBC driver class
+datasourcefactory.not.found=The persistence unit {0} in bundle {1}/{2} cannot be registered because no DataSourceFactory service for JDBC driver {3} exists.
+# {0} The datasourcefactory class
+# {1} The datasource creation properties
+# {2} The bundle symbolic name.
+# {3} The bundle version.
+datasourcefactory.sql.exception=The DataSourceFactory {0} threw an exception when creating a datasource with the properties {1}. This datasource was required by bundle {2}/{3}.
+no.datasourcefactory.integration=The org.osgi.service.jdbc package is unavailable. As a result the Aries JPA container will not offer any DataSourceFactory integration.
+# {0} The name of the persistence unit.
+# {1} The symbolic name of the persistence bundle.
+# {2} The version of the persistence bundle.
+using.datasource.factory=The persistence unit {0} in bundle {1}/{2} will use a DataSourceFactory service when creating its database connections.
+# {0} The datasourcefactory class
+# {1} The bundle symbolic name.
+# {2} The bundle version.
+no.datasource.factory=No DataSourceFactory service is available for the JDBC driver class {0}. Persistence bundle {1}/{2} is trying to create that DataSource and cannot. One or more persistence units will be unusable until this DataSourceFactory is available.
\ No newline at end of file

Modified: aries/trunk/jpa/jpa-container/src/test/java/org/apache/aries/jpa/container/PersistenceBundleLifecycleTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/test/java/org/apache/aries/jpa/container/PersistenceBundleLifecycleTest.java?rev=1163939&r1=1163938&r2=1163939&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container/src/test/java/org/apache/aries/jpa/container/PersistenceBundleLifecycleTest.java (original)
+++ aries/trunk/jpa/jpa-container/src/test/java/org/apache/aries/jpa/container/PersistenceBundleLifecycleTest.java Thu Sep  1 08:27:14 2011
@@ -68,6 +68,7 @@ import org.osgi.framework.InvalidSyntaxE
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.framework.Version;
+import org.osgi.service.jdbc.DataSourceFactory;
 
 public class PersistenceBundleLifecycleTest
 {
@@ -1207,6 +1208,61 @@ public class PersistenceBundleLifecycleT
     BundleContextMock.assertNoServiceExists(EntityManagerFactory.class.getName());
   }
   
+  @Test
+  public void testDataSourceFactoryLifecycle() throws Exception
+  {
+    //Basic startup
+    BundleContext extenderContext = preExistingBundleSetup();
+    
+    Hashtable<String,String> hash1 = new Hashtable<String, String>();
+    hash1.put("javax.persistence.provider", "no.such.Provider");
+    ServiceRegistration reg = persistenceBundle.getBundleContext().registerService(new String[] {PersistenceProvider.class.getName()} ,
+        pp, hash1 );
+    ServiceReference ref = reg.getReference();
+
+    setupPersistenceBundle("file25", "");
+    
+    mgr.start(extenderContext);
+    
+    //Check the persistence.xml was looked for
+    Skeleton.getSkeleton(persistenceBundle).assertCalled(new MethodCall(Bundle.class, "getEntry", "META-INF/persistence.xml"));
+    //Check we didn't use getResource()
+    Skeleton.getSkeleton(persistenceBundle).assertNotCalled(new MethodCall(Bundle.class, "getResource", String.class));
+    
+    //We should create them all, but then wait for the DataSourceFactory services
+    testSuccessfulCreationEvent(ref, extenderContext, 3);
+    testSuccessfulRegistrationEvent(ref, extenderContext, 0);
+    
+    //Register the DSF for alpha and it should appear
+    hash1 = new Hashtable<String, String>();
+    hash1.put(DataSourceFactory.OSGI_JDBC_DRIVER_CLASS, "alpha.db.class");
+    reg = persistenceBundle.getBundleContext().registerService(new String[] {DataSourceFactory.class.getName()} ,
+        Skeleton.newMock(DataSourceFactory.class), hash1 );
+    
+    testSuccessfulRegistrationEvent(ref, extenderContext, 1, "alpha");
+    
+    //Register the other DSF
+    hash1 = new Hashtable<String, String>();
+    hash1.put(DataSourceFactory.OSGI_JDBC_DRIVER_CLASS, "shared.db.class");
+    persistenceBundle.getBundleContext().registerService(new String[] {DataSourceFactory.class.getName()} ,
+        Skeleton.newMock(DataSourceFactory.class), hash1 );
+    
+    testSuccessfulRegistrationEvent(ref, extenderContext, 3, "alpha", "bravo", "charlie");
+    
+    
+    //Unregister the service for alpha and it should go away again!
+    reg.unregister();
+    
+    ServiceReference[] emfs = extenderContext.getServiceReferences(EntityManagerFactory.class.getName(), null);
+    assertEquals("Too many services registered", 2, emfs.length);
+    
+    assertNotNull(extenderContext.getServiceReferences(
+        EntityManagerFactory.class.getName(), "(osgi.unit.name=bravo)"));
+    assertNotNull(extenderContext.getServiceReferences(
+        EntityManagerFactory.class.getName(), "(osgi.unit.name=charlie)"));
+  }
+  
+  
   private void setupPersistenceBundle21() throws Exception {
     persistenceBundle.getHeaders().put("Meta-Persistence", "OSGI-INF/found.xml, jarfile.jar!/jar.xml,persistence/another.xml, does-not-exist.xml");
     
@@ -1379,8 +1435,12 @@ public class PersistenceBundleLifecycleT
   {
     Skeleton.getSkeleton(persistenceBundleContext).assertCalledExactNumberOfTimes(new MethodCall(BundleContext.class, "registerService", EntityManagerFactory.class.getName(), EntityManagerFactory.class, Dictionary.class), numberOfPersistenceUnits);
     
-    if(numberOfPersistenceUnits != 0)
-      BundleContextMock.assertServiceExists(EntityManagerFactory.class.getName());
+    if(numberOfPersistenceUnits == 0) {
+      BundleContextMock.assertNoServiceExists(EntityManagerFactory.class.getName());
+      return;
+    }
+      
+    BundleContextMock.assertServiceExists(EntityManagerFactory.class.getName());
     
     ServiceReference[] emfs = extenderContext.getServiceReferences(EntityManagerFactory.class.getName(), null);
     

Added: aries/trunk/jpa/jpa-container/src/test/resources/file25/META-INF/persistence.xml
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/test/resources/file25/META-INF/persistence.xml?rev=1163939&view=auto
==============================================================================
--- aries/trunk/jpa/jpa-container/src/test/resources/file25/META-INF/persistence.xml (added)
+++ aries/trunk/jpa/jpa-container/src/test/resources/file25/META-INF/persistence.xml Thu Sep  1 08:27:14 2011
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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 WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+<persistence xmlns="http://java.sun.com/xml/ns/persistence"
+   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+   xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
+   version="1.0">
+
+  <persistence-unit name="alpha">
+    <properties>
+      <property name="javax.persistence.jdbc.driver" value="alpha.db.class"/>
+      <property name="javax.persistence.jdbc.url" value="jdbc:alpha:url"/>
+      <property name="javax.persistence.jdbc.user" value="alan"/>
+      <property name="javax.persistence.jdbc.password" value="4l4n"/>
+    </properties>
+  </persistence-unit>
+  
+  <persistence-unit name="bravo" transaction-type="JTA">
+    <properties>
+      <property name="javax.persistence.jdbc.driver" value="shared.db.class"/>
+      <property name="javax.persistence.jdbc.url" value="jdbc:bravo:url"/>
+      <property name="javax.persistence.jdbc.user" value="bob"/>
+      <property name="javax.persistence.jdbc.password" value="B0B"/>
+    </properties>
+  </persistence-unit>
+  
+  <persistence-unit name="charlie" transaction-type="JTA">
+    <properties>
+      <property name="javax.persistence.jdbc.driver" value="shared.db.class"/>
+      <property name="javax.persistence.jdbc.url" value="jdbc:charlie:url"/>
+      <property name="javax.persistence.jdbc.user" value="craig"/>
+      <property name="javax.persistence.jdbc.password" value="cr416"/>
+    </properties>
+  </persistence-unit>
+  
+</persistence>



Mime
View raw message