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 2010/01/14 17:55:19 UTC

svn commit: r899298 - /incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/

Author: timothyjward
Date: Thu Jan 14 16:55:18 2010
New Revision: 899298

URL: http://svn.apache.org/viewvc?rev=899298&view=rev
Log:
ARIES-79: Create and manage EntityManagerFactory services for persistence units

Modified:
    incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/EntityManagerFactoryManager.java
    incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/InvalidPersistenceUnitException.java
    incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/InvalidRangeCombination.java
    incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleHelper.java
    incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleManager.java

Modified: incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/EntityManagerFactoryManager.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/EntityManagerFactoryManager.java?rev=899298&r1=899297&r2=899298&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/EntityManagerFactoryManager.java (original)
+++ incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/EntityManagerFactoryManager.java Thu Jan 14 16:55:18 2010
@@ -34,19 +34,23 @@
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
-
+/**
+ * This class manages the lifecycle of Persistence Units and their associated
+ * {@link EntityManagerFactory} objects.
+ */
 public class EntityManagerFactoryManager {
 
+  /** The container's {@link BundleContext} */
   private final BundleContext containerContext;
-  
+  /** The persistence bundle */
   private final Bundle bundle;
-  
+  /** The {@link PersistenceProvider} to use */
   private ServiceReference provider;
-  
+  /** The persistence units to manage */
   private Collection<ManagedPersistenceUnitInfo> persistenceUnits;
-  
+  /** A Map of created {@link EntityManagerFactory}s */
   private Map<String, EntityManagerFactory> emfs = null;
-  
+  /** The {@link ServiceRegistration} objects for the {@link EntityManagerFactory}s */
   private Collection<ServiceRegistration> registrations = null;
 
   /**
@@ -69,6 +73,18 @@
     persistenceUnits = infos;
   }
 
+  /**
+   * Notify the {@link EntityManagerFactoryManager} that a provider is being
+   * removed from the service registry.
+   * 
+   * If the provider is used by this {@link EntityManagerFactoryManager} then
+   * the manager should destroy the dependent persistence units.
+   * 
+   * <b>This method should only be called when not holding any locks</b>
+   * 
+   * @param ref  The provider service reference
+   * @return true if the the provider is being used by this manager
+   */
   public synchronized boolean providerRemoved(ServiceReference ref) {
     
     boolean toReturn = ref == provider;
@@ -79,6 +95,15 @@
     return toReturn;
   }
 
+  /**
+   * Notify the {@link EntityManagerFactoryManager} that the bundle it is
+   * managing has changed state
+   * 
+   * <b>This method should only be called when not holding any locks</b>
+   * 
+   * @throws InvalidPersistenceUnitException if the manager is no longer valid and
+   *                                         should be destroyed
+   */
   public synchronized void bundleStateChange() throws InvalidPersistenceUnitException {
     
     switch(bundle.getState()) {
@@ -89,19 +114,26 @@
         //Create the EMF objects if necessary
         createEntityManagerFactories();
         break;
+        //Starting and active both require EMFs to be registered
       case Bundle.STARTING :
       case Bundle.ACTIVE :
         registerEntityManagerFactories();
         break;
+        //Stopping means the EMFs should
       case Bundle.STOPPING :
         unregisterEntityManagerFactories();
         break;
       case Bundle.INSTALLED :
+        //Destroy everything
         destroyEntityManagerFactories();
     }
   }
 
+  /**
+   * Unregister all {@link EntityManagerFactory} services
+   */
   private void unregisterEntityManagerFactories() {
+    //If we have registrations then unregister them
     if(registrations != null) {
       for(ServiceRegistration reg : registrations) {
         try {
@@ -110,14 +142,23 @@
           //TODO log this
         }
       }
+      // remember to set registrations to be null
       registrations = null;
     }
   }
 
+  /**
+   * Register {@link EntityManagerFactory} services
+   * 
+   * @throws InvalidPersistenceUnitException if this {@link EntityManagerFactory} is no longer
+   *  valid and should be destroyed
+   */
   private void registerEntityManagerFactories() throws InvalidPersistenceUnitException {
+    //Only register if there is a provider and we are not
+    //already registered
     if(provider != null && registrations == null) {
-      if(emfs == null)
-        createEntityManagerFactories();
+      //Make sure the EntityManagerFactories are instantiated
+      createEntityManagerFactories();
       
       registrations = new ArrayList<ServiceRegistration>();
       String providerName = (String) provider.getProperty("javax.persistence.provider");
@@ -125,6 +166,7 @@
         //TODO log this
         throw new InvalidPersistenceUnitException();
       }
+      //Register each EMF
       for(Entry<String, EntityManagerFactory> entry : emfs.entrySet())
       {
         Properties props = new Properties();
@@ -148,12 +190,19 @@
     }
   }
 
+  /**
+   * Create {@link EntityManagerFactory} services for this peristence unit
+   * throws InvalidPersistenceUnitException if this {@link EntityManagerFactory} is no longer
+   *  valid and should be destroyed
+   */
   private void createEntityManagerFactories() throws InvalidPersistenceUnitException {
+    //Only try if we have a provider and EMFs
     if(provider != null) {
       if(emfs == null) {
         try {
           emfs = new HashMap<String, EntityManagerFactory>();
         
+          //Get hold of the provider
           PersistenceProvider providerService = (PersistenceProvider) containerContext.getService(provider);
 
           if(providerService == null) throw new InvalidPersistenceUnitException();
@@ -166,6 +215,7 @@
                     pUnitInfo, info.getContainerProperties()));
           }
         } finally {
+          //Remember to unget the provider
           containerContext.ungetService(provider);
         }
       }
@@ -199,6 +249,9 @@
     persistenceUnits = null;
   }
 
+  /**
+   * S
+   */
   private void destroyEntityManagerFactories() {
     if(registrations != null)
       unregisterEntityManagerFactories();

Modified: incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/InvalidPersistenceUnitException.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/InvalidPersistenceUnitException.java?rev=899298&r1=899297&r2=899298&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/InvalidPersistenceUnitException.java (original)
+++ incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/InvalidPersistenceUnitException.java Thu Jan 14 16:55:18 2010
@@ -18,14 +18,22 @@
  */
 package org.apache.aries.jpa.container.impl;
 
+/**
+ * This exception is thrown if an {@link EntityManagerFactoryManager} has
+ * entered an invalid state and needs to be destroyed
+ */
 public class InvalidPersistenceUnitException extends Exception {
 
+  /**
+   * For serialization
+   */
+  private static final long serialVersionUID = 6523462131213055375L;
+
   public InvalidPersistenceUnitException(Exception e) {
     super(e);
   }
 
   public InvalidPersistenceUnitException() {
-    // TODO Auto-generated constructor stub
   }
 
 }

Modified: incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/InvalidRangeCombination.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/InvalidRangeCombination.java?rev=899298&r1=899297&r2=899298&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/InvalidRangeCombination.java (original)
+++ incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/InvalidRangeCombination.java Thu Jan 14 16:55:18 2010
@@ -19,9 +19,17 @@
 package org.apache.aries.jpa.container.impl;
 
 import org.osgi.framework.Version;
-
+/**
+ * This exception is thrown when a persistence descriptor contains
+ * an set of version ranges with no common overlap
+ */
 public class InvalidRangeCombination extends Exception {
 
+  /**
+   * For Serialization
+   */
+  private static final long serialVersionUID = 3631484834936016561L;
+
   public InvalidRangeCombination(Version minVersion, boolean minExclusive,
       Version maxVersion, boolean maxExclusive) {
     // TODO Auto-generated constructor stub

Modified: incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleHelper.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleHelper.java?rev=899298&r1=899297&r2=899298&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleHelper.java (original)
+++ incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleHelper.java Thu Jan 14 16:55:18 2010
@@ -40,6 +40,7 @@
 {
   /** The persistence xml location */
   public static final String PERSISTENCE_XML = "META-INF/persistence.xml";
+  /** The Meta-Persistence header */
   public static final String PERSISTENCE_UNIT_HEADER = "Meta-Persistence";
 
   /**
@@ -49,7 +50,7 @@
    * 
    * Note that getEntry is used to ensure we do not alter the state of the bundle
    * 
-   * @param bundle
+   * @param bundle The bundle to search
    * @return
    */
   public static Collection<PersistenceDescriptor> findPersistenceXmlFiles(Bundle bundle)
@@ -57,7 +58,8 @@
     //The files we have found
     Collection<PersistenceDescriptor> persistenceXmlFiles = new ArrayList<PersistenceDescriptor>();
     
-    //Always search the default location
+    //Always search the default location, and use a set so we don't search the same
+    //location twice!
     Collection<String> locations = new HashSet<String>();
     locations.add(PERSISTENCE_XML);
     
@@ -65,18 +67,20 @@
     
     if(header != null) {
       //Split apart the header to get the individual entries
-      List<String> headerLocations = Arrays.asList(header.split(","));
-      locations.addAll(headerLocations);
-    
+      for(String s : header.split(","))
+        locations.add(s.trim());
     
+      //Find the file and add it to our list
       try {
         for(String location : locations) {
-          InputStream file = locateFile(bundle, location.trim());
+          InputStream file = locateFile(bundle, location);
           if(file != null)
             persistenceXmlFiles.add(new PersistenceDescriptorImpl(location, file));
           }
       } catch (Exception e) {
           //TODO log
+        //If we get an exception, then go through closing all of our streams.
+        //It is better to fail completely than half succeed.
         for (PersistenceDescriptor desc : persistenceXmlFiles) {
           try {
             desc.getInputStream().close();
@@ -97,46 +101,42 @@
    * @param bundle
    * @param persistenceXmlFiles
    * @param jarLocation
+   * @throws IOException 
    */
-  private static InputStream locateFile(Bundle bundle, String location)
+  private static InputStream locateFile(Bundle bundle, String location) throws IOException
   {
+    //There is nothing for an empty location
     InputStream is = null;
     if(location == "") {
       return null;
     }
-      
-    int bangIndex = location.indexOf('!');
     
+    //If there is a '!' then we have to look in a jar
+    int bangIndex = location.indexOf('!');
+    //No '!', getEntry will do
     if(bangIndex == -1) {
       URL url = bundle.getEntry(location);
       
-      if(url != null) {
-        try {
-          is = url.openStream();
-        } catch (IOException e) {
-          // TODO log this
-          e.printStackTrace();
-        }
-      }
+      if(url != null) 
+        is = url.openStream();
+      
     } else {
+      //There was a '!', find the jar
       URL url = bundle.getEntry(location.substring(0, bangIndex));
       
       if(url != null) {
+        //Remember to trim off the "!/"
         String toLocate = location.substring(bangIndex + 2);
+      
+        JarInputStream jis = new JarInputStream(url.openStream());
+        JarEntry entry = jis.getNextJarEntry();
         
-        try {
-          JarInputStream jis = new JarInputStream(url.openStream());
-          JarEntry entry = jis.getNextJarEntry();
-          
-          while(entry != null) {
-            if(entry.getName().equals(toLocate)) {
-              is = jis;
-              break;
-            }
-            entry = jis.getNextJarEntry();
+        while(entry != null) {
+          if(entry.getName().equals(toLocate)) {
+            is = jis;
+            break;
           }
-        } catch (IOException ioe) {
-          //TODO log this
+          entry = jis.getNextJarEntry();
         }
       }
     }

Modified: incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleManager.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleManager.java?rev=899298&r1=899297&r2=899298&view=diff
==============================================================================
--- incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleManager.java (original)
+++ incubator/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleManager.java Thu Jan 14 16:55:18 2010
@@ -65,7 +65,10 @@
    * synchronized on {@code this}.
    */
   private final Map<Bundle, EntityManagerFactoryManager> bundleToManagerMap = new HashMap<Bundle, EntityManagerFactoryManager>();
-  /** The PersistenceProviders.  */
+  /** 
+   * The PersistenceProviders. The Set should only ever be accessed when
+   * synchronized on {@code this}. Use a Set for constant access and add times.
+   */
   private Set<ServiceReference> persistenceProviders = new HashSet<ServiceReference>();
   /** Plug-point for persistence unit providers */
   private ManagedPersistenceUnitInfoFactory persistenceUnitFactory; 
@@ -86,7 +89,8 @@
   
   @Override
   public void open() {
-    String className = (String) config.get(ManagedPersistenceUnitInfoFactory.DEFAULT_PU_INFO_FACTORY_KEY);
+    //Create the pluggable ManagedPersistenceUnitInfoFactory
+    String className = config.getProperty(ManagedPersistenceUnitInfoFactory.DEFAULT_PU_INFO_FACTORY_KEY);
     Class<? extends ManagedPersistenceUnitInfoFactory> clazz = null;
     
     if(className != null) {
@@ -136,7 +140,6 @@
 
   public Object addingBundle(Bundle bundle, BundleEvent event) 
   {
-    
     if(bundle.getState() == Bundle.ACTIVE) {
       //TODO LOG WARNING HERE
     }
@@ -145,82 +148,54 @@
     return mgr;
   }
 
-  private EntityManagerFactoryManager setupManager(Bundle bundle,
-    EntityManagerFactoryManager mgr) {
-  Collection <PersistenceDescriptor> persistenceXmls = PersistenceBundleHelper.findPersistenceXmlFiles(bundle);
-
-    //If we have no persistence units then our job is done
-    if (!!!persistenceXmls.isEmpty()) {
-      Collection<ParsedPersistenceUnit> pUnits = new ArrayList<ParsedPersistenceUnit>();
-      
-      for(PersistenceDescriptor descriptor : persistenceXmls) {
-        try {
-          pUnits.addAll(PersistenceDescriptorParser.parse(bundle, descriptor));
-        } catch (PersistenceDescriptorParserException e) {
-          // TODO Auto-generated catch block
-          e.printStackTrace();
-        }
-      }
-      
-      if(!!!pUnits.isEmpty()) {
-        ServiceReference ref = getProviderServiceReference(pUnits);
-        if(ref != null) {  
-          Collection<ManagedPersistenceUnitInfo> infos = persistenceUnitFactory.
-              createManagedPersistenceUnitMetadata(ctx, bundle, ref, pUnits);
-          if(mgr != null)
-            mgr.manage(ref, infos);
-          else {
-            synchronized (this) {
-              if(persistenceProviders.contains(ref)) {
-                  mgr = new EntityManagerFactoryManager(ctx, bundle, ref, infos);
-                  bundleToManagerMap.put(bundle, mgr);
-              }
-            }
-          }
-        }
-        if(mgr != null) {
-          try {
-            mgr.bundleStateChange();
-          } catch (InvalidPersistenceUnitException e) {
-            // TODO Log this error
-            mgr.destroy();
-            persistenceUnitFactory.destroyPersistenceBundle(bundle);
-          }
-        }
-      }
-    }
-    return mgr;
-  }
-  
+  /**
+   * A provider is being added, add it to our Set
+   * @param ref
+   */
   public synchronized void addingProvider(ServiceReference ref)
   {
     persistenceProviders.add(ref);
   }
   
+  /**
+   * A provider is being removed, remove it from the set, and notify all
+   * managers that it has been removed
+   * @param ref
+   */
   public void removingProvider(ServiceReference ref)
   {
+    //We may get a null reference if the ref-list is empty to start with
+    if(ref == null)
+      return;
     Map<Bundle, EntityManagerFactoryManager> mgrs;
     synchronized (this) {
       persistenceProviders.remove(ref);
       mgrs = new HashMap<Bundle, EntityManagerFactoryManager>(bundleToManagerMap);
     }
+    //If the entry is removed then make sure we notify the persistenceUnitFactory
     for(Entry<Bundle, EntityManagerFactoryManager> entry : mgrs.entrySet()) {
       if(entry.getValue().providerRemoved(ref))
         persistenceUnitFactory.destroyPersistenceBundle(entry.getKey());
     }
   }
   
+  /**
+   * Add config properties, making sure to read in the properties file
+   * and override the supplied properties
+   * @param props
+   */
   public void setConfig(Properties props) {
-    config = props;
+    config = new Properties(props);
     URL u = ctx.getBundle().getResource(ManagedPersistenceUnitInfoFactory.ARIES_JPA_CONTAINER_PROPERTIES);
     
-    if(u != null)
+    if(u != null) {
       try {
         config.load(u.openStream());
       } catch (IOException e) {
         // TODO Log this error
         e.printStackTrace();
       }
+    }
   }
      
 //      //If we can't find a provider then bomb out
@@ -272,7 +247,8 @@
   public void modifiedBundle(Bundle bundle, BundleEvent event, Object object) {
 
     EntityManagerFactoryManager mgr = (EntityManagerFactoryManager) object;
-    
+    //If the bundle was updated we need to destroy it and re-initialize
+    //the EntityManagerFactoryManager
     if(event != null && event.getType() == BundleEvent.UPDATED) {
       mgr.destroy();
       persistenceUnitFactory.destroyPersistenceBundle(bundle);
@@ -291,13 +267,72 @@
     EntityManagerFactoryManager mgr = (EntityManagerFactoryManager) object;   
     mgr.destroy();
     persistenceUnitFactory.destroyPersistenceBundle(bundle);
-    
+    //Remember to tidy up the map
     synchronized (this) {
       bundleToManagerMap.remove(bundle);
     }
   }
   
-
+  /**
+   * Set up an {@link EntityManagerFactoryManager} for the supplied bundle
+   * 
+   * @param bundle The bundle
+   * @param mgr The previously existing {@link EntityManagerFactoryManager} or {@code null} if none existed
+   * @return The manager to use, or null if no persistence units can be managed for this bundle
+   */
+  private EntityManagerFactoryManager setupManager(Bundle bundle,
+      EntityManagerFactoryManager mgr) {
+    //Find Persistence descriptors
+    Collection <PersistenceDescriptor> persistenceXmls = PersistenceBundleHelper.findPersistenceXmlFiles(bundle);
+
+      //If we have no persistence units then our job is done
+      if (!!!persistenceXmls.isEmpty()) {
+        Collection<ParsedPersistenceUnit> pUnits = new ArrayList<ParsedPersistenceUnit>();
+        
+        //Parse each descriptor
+        for(PersistenceDescriptor descriptor : persistenceXmls) {
+          try {
+            pUnits.addAll(PersistenceDescriptorParser.parse(bundle, descriptor));
+          } catch (PersistenceDescriptorParserException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+          }
+        }
+        
+        //If we have any persistence units then find a provider to use
+        if(!!!pUnits.isEmpty()) {
+          ServiceReference ref = getProviderServiceReference(pUnits);
+          //If we found a provider then create the ManagedPersistenceUnitInfo objects
+          if(ref != null) {  
+            Collection<ManagedPersistenceUnitInfo> infos = persistenceUnitFactory.
+                createManagedPersistenceUnitMetadata(ctx, bundle, ref, pUnits);
+            //Either update the existing manager or create a new one
+            if(mgr != null)
+              mgr.manage(ref, infos);
+            else {
+              synchronized (this) {
+                if(persistenceProviders.contains(ref)) {
+                    mgr = new EntityManagerFactoryManager(ctx, bundle, ref, infos);
+                    bundleToManagerMap.put(bundle, mgr);
+                }
+              }
+            }
+          }
+          //If we have a manager then prod it to get it into the right state
+          if(mgr != null) {
+            try {
+              mgr.bundleStateChange();
+            } catch (InvalidPersistenceUnitException e) {
+              // TODO Log this error
+              mgr.destroy();
+              persistenceUnitFactory.destroyPersistenceBundle(bundle);
+            }
+          }
+        }
+      }
+      return mgr;
+    }
+  
   /**
    * Get a persistence provider from the service registry described by the
    * persistence units defined
@@ -357,6 +392,12 @@
     }
   }
  
+  /**
+   * Turn a Collection of version ranges into a single range including common overlap
+   * @param versionRanges
+   * @return
+   * @throws InvalidRangeCombination
+   */
   private VersionRange combineVersionRanges(List<VersionRange> versionRanges) throws InvalidRangeCombination {
 
     Version minVersion = new Version(0,0,0);
@@ -401,6 +442,7 @@
       throw new InvalidRangeCombination(minVersion, minExclusive, maxVersion, maxExclusive);
     }
     
+    //Turn the Versions into a version range string
     StringBuilder rangeString = new StringBuilder();
     rangeString.append(minVersion);
     
@@ -410,7 +452,7 @@
       rangeString.append(maxVersion);
       rangeString.append(maxExclusive ? ")" : "]");
     }
-    
+    //Turn that string back into a VersionRange
     return ManifestHeaderProcessor.parseVersionRange(rangeString.toString());
   }
 
@@ -439,13 +481,13 @@
         }
         
         if(!!!refs.isEmpty()) {
-          //Sort the list in DESCENDING ORDER
-          
+          //Return the "best" provider, i.e. the highest version
           return Collections.max(refs, new ProviderServiceComparator());
         } else {
           //TODO no matching providers for matching criteria
         }
       } else {
+        //Return the "best" provider, i.e. the service OSGi would pick
         return (ServiceReference) Collections.max(persistenceProviders);
       }
     } else {
@@ -454,6 +496,9 @@
     return null;
   }
   
+  /**
+   * Sort the providers so that the highest version, highest ranked service is at the top
+   */
   private static class ProviderServiceComparator implements Comparator<ServiceReference> {
     public int compare(ServiceReference object1, ServiceReference object2)
     {