aries-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From z..@apache.org
Subject svn commit: r1075099 [5/7] - in /aries/tags/jpa-0.1-incubating: ./ jpa-api/ jpa-api/src/ jpa-api/src/main/ jpa-api/src/main/java/ jpa-api/src/main/java/org/ jpa-api/src/main/java/org/apache/ jpa-api/src/main/java/org/apache/aries/ jpa-api/src/main/java...
Date Sun, 27 Feb 2011 18:08:17 GMT
Added: aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleHelper.java
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleHelper.java?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleHelper.java (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleHelper.java Sun Feb 27 18:08:10 2011
@@ -0,0 +1,167 @@
+/*
+ * 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.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+
+import org.apache.aries.jpa.container.parsing.PersistenceDescriptor;
+import org.osgi.framework.Bundle;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This helper can be used to locate persistence.xml files in a bundle
+ */
+public class PersistenceBundleHelper
+{
+  /** Logger */
+  private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container");
+  
+  /** 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";
+  /** The Web-ContextPath header (as defined in the web application bundle spec) */
+  public static final String WEB_CONTEXT_PATH_HEADER = "Web-ContextPath";
+
+  /**
+   * This method locates persistence descriptor files based on a combination of
+   * the default location "META-INF/persistence.xml" and the Meta-Persistence
+   * header.
+   * 
+   * Note that getEntry is used to ensure we do not alter the state of the bundle
+   * Note also that web application bundles will never return persistence descriptors
+   * 
+   * @param bundle The bundle to search
+   * @return
+   */
+  public static Collection<PersistenceDescriptor> findPersistenceXmlFiles(Bundle bundle)
+  {    
+    String header = (String) bundle.getHeaders().get(PERSISTENCE_UNIT_HEADER);
+    if (header == null) {
+      return Collections.emptySet();
+    }
+      
+    // Do not scan WABs
+    if (bundle.getHeaders().get(WEB_CONTEXT_PATH_HEADER) != null) {
+      _logger.warn("The bundle " + bundle.getSymbolicName() + " specifies both the " + 
+                  PERSISTENCE_UNIT_HEADER + " and the " + WEB_CONTEXT_PATH_HEADER + " header. WABs that use JPA " +
+                  "are not supported as part of the OSGi JPA specification. No persistence descriptors will be processed" +
+                  "for this bundle.");
+      return Collections.emptySet();
+    }
+    
+    //The files we have found
+    Collection<PersistenceDescriptor> persistenceXmlFiles = new ArrayList<PersistenceDescriptor>();
+    
+    //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);
+          
+    //Split apart the header to get the individual entries
+    for (String s : header.split(",")) {
+      locations.add(s.trim());
+    }
+    
+    //Find the file and add it to our list
+    for (String location : locations) {
+      try {
+          InputStream file = locateFile(bundle, location);
+          if (file != null) {
+            persistenceXmlFiles.add(new PersistenceDescriptorImpl(location, file));
+          }
+      } catch (Exception e) {
+          _logger.error("There was an exception while locating the persistence descriptor at location "
+              + location + " in bundle " + bundle.getSymbolicName() + "_" + bundle.getVersion()
+          		+ ". No persistence descriptors will be processed for this bundle.", e);
+        //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();
+          } catch (IOException ioe) {
+            //We don't care about this exception, so swallow it
+          }
+        }
+        persistenceXmlFiles = Collections.emptySet();
+        //Exit the for loop
+        break;
+      }     
+    }
+   return persistenceXmlFiles;
+ }
+
+  /**
+   * Locate a persistence descriptor file in a bundle
+   * based on a String name.
+   * 
+   * @param bundle
+   * @param persistenceXmlFiles
+   * @param jarLocation
+   * @throws IOException 
+   */
+  private static InputStream locateFile(Bundle bundle, String location) throws IOException
+  {
+    //There is nothing for an empty location
+    InputStream is = null;
+    if("".equals(location)) {
+      return null;
+    }
+    
+    //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) 
+        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();
+        
+        while(entry != null) {
+          if(entry.getName().equals(toLocate)) {
+            is = jis;
+            break;
+          }
+          entry = jis.getNextJarEntry();
+        }
+      }
+    }
+    return is;
+  }
+}

Added: aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleManager.java
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleManager.java?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleManager.java (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleManager.java Sun Feb 27 18:08:10 2011
@@ -0,0 +1,583 @@
+/*
+ * 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 java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import org.apache.aries.jpa.container.ManagedPersistenceUnitInfo;
+import org.apache.aries.jpa.container.ManagedPersistenceUnitInfoFactory;
+import org.apache.aries.jpa.container.parsing.ParsedPersistenceUnit;
+import org.apache.aries.jpa.container.parsing.PersistenceDescriptor;
+import org.apache.aries.jpa.container.parsing.PersistenceDescriptorParser;
+import org.apache.aries.jpa.container.parsing.PersistenceDescriptorParserException;
+import org.apache.aries.jpa.container.unit.impl.ManagedPersistenceUnitInfoFactoryImpl;
+import org.apache.aries.util.VersionRange;
+import org.apache.aries.util.tracker.MultiBundleTracker;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class locates, parses and manages persistence units defined in OSGi bundles.
+ */
+public class PersistenceBundleManager extends MultiBundleTracker
+{
+  /** Logger */
+  private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container");
+  
+  /** The bundle context for this bundle */
+  private BundleContext ctx = null;
+  /** 
+   * A map of providers to persistence bundles this is used to guarantee that 
+   * when a provider service is removed we can access all of the bundles that
+   * might possibly be using it. The map should only ever be accessed when
+   * synchronized on {@code this}.
+   */
+  private final Map<Bundle, EntityManagerFactoryManager> bundleToManagerMap = new HashMap<Bundle, EntityManagerFactoryManager>();
+  /** 
+   * 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>();
+  /** 
+   * Managers that do not have a suitable provider yet
+   * should only ever be accessed when synchronized on {@code this} 
+   * Use a set so we don't have to be careful about adding multiple times!
+   */
+  private Collection<EntityManagerFactoryManager> managersAwaitingProviders = new ArrayList<EntityManagerFactoryManager>();
+  /** Plug-point for persistence unit providers */
+  private ManagedPersistenceUnitInfoFactory persistenceUnitFactory; 
+  /** Parser for persistence descriptors */
+  private PersistenceDescriptorParser parser;
+  /** Configuration for this extender */
+  private Properties config;
+
+  /**
+   * Create the extender. Note that it will not start tracking 
+   * until the {@code open()} method is called
+   * @param ctx The extender bundle's context
+   */
+  public PersistenceBundleManager(BundleContext ctx) 
+  {
+	  super(ctx, Bundle.INSTALLED | Bundle.RESOLVED | Bundle.STARTING |
+			  Bundle.ACTIVE | Bundle.STOPPING);
+    this.ctx = ctx;
+  }
+
+  /**
+   * Provide a parser implementation
+   * @param parser
+   */
+  public void setParser(PersistenceDescriptorParser descriptorParser) {
+    parser = descriptorParser;
+  }
+
+  
+  @SuppressWarnings("unchecked")
+  @Override
+  public void open() {
+    //Create the pluggable ManagedPersistenceUnitInfoFactory
+    String className = config.getProperty(ManagedPersistenceUnitInfoFactory.DEFAULT_PU_INFO_FACTORY_KEY);
+    
+    if(className != null) {
+      try {
+        Class<? extends ManagedPersistenceUnitInfoFactory> clazz = ctx.getBundle().loadClass(className);
+        persistenceUnitFactory = clazz.newInstance();
+      } catch (Exception e) {
+        _logger.error("There was a problem creating the custom ManagedPersistenceUnitInfoFactory " + className 
+            + ". The default ManagedPersistenceUnitInfo factory will be used instead", e);
+      }
+    }
+    
+    if(persistenceUnitFactory == null)
+      persistenceUnitFactory = new ManagedPersistenceUnitInfoFactoryImpl();
+    
+    super.open();
+  }
+  
+  public Object addingBundle(Bundle bundle, BundleEvent event) 
+  {
+    EntityManagerFactoryManager mgr = setupManager(bundle, null, true);
+    return mgr;
+  }
+
+  /**
+   * A provider is being added, add it to our Set
+   * @param ref
+   */
+  public void addingProvider(ServiceReference ref)
+  {
+    Map<EntityManagerFactoryManager, ServiceReference> managersToManage = new HashMap<EntityManagerFactoryManager, ServiceReference>();
+    synchronized (this) {
+      if(_logger.isDebugEnabled())
+        _logger.debug("Adding a provider: {}", new Object[] {ref});
+      
+      persistenceProviders.add(ref);
+    
+      Iterator<EntityManagerFactoryManager> it = managersAwaitingProviders.iterator();
+      while(it.hasNext()) {
+        EntityManagerFactoryManager mgr = it.next();
+        ServiceReference reference = getProviderServiceReference(mgr.getParsedPersistenceUnits());
+        if(ref != null) {
+          managersToManage.put(mgr, reference);
+          it.remove();
+        }
+      }
+    }
+    
+    for(Entry<EntityManagerFactoryManager, ServiceReference> entry 
+        : managersToManage.entrySet()) {
+      EntityManagerFactoryManager mgr = entry.getKey();
+      ServiceReference reference = entry.getValue();
+      Collection<ManagedPersistenceUnitInfo> infos = null;
+      try {
+         infos = persistenceUnitFactory.createManagedPersistenceUnitMetadata(
+             ctx, mgr.getBundle(), reference, mgr.getParsedPersistenceUnits());
+      
+        mgr.manage(reference, infos);
+        mgr.bundleStateChange();
+      } catch (Exception e) {
+        if(e instanceof InvalidPersistenceUnitException) {
+          logInvalidPersistenceUnitException(mgr.getBundle(), (InvalidPersistenceUnitException)e);
+        } else {
+          _logger.warn("An error occured whilst trying to manage persistence units for bundle " 
+              + mgr.getBundle().getSymbolicName() + "_" + mgr.getBundle().getVersion(), e);
+        }
+        mgr.destroy();
+        if(infos != null)
+          persistenceUnitFactory.destroyPersistenceBundle(mgr.getBundle());
+        
+        //Something better may have come along while we weren't synchronized
+        setupManager(mgr.getBundle(), mgr, false);
+      }
+    }
+  }
+  
+  /**
+   * 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;
+    
+    if(_logger.isDebugEnabled())
+      _logger.debug("Removing a provider: {}", new Object[] {ref});
+    
+    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()) {
+      EntityManagerFactoryManager mgr = entry.getValue();
+      if(mgr.providerRemoved(ref)) {
+        Bundle bundle = entry.getKey();
+        persistenceUnitFactory.destroyPersistenceBundle(bundle);
+        //Allow the manager to re-initialize with a new provider
+        //No change to the units
+        setupManager(bundle, mgr, false);
+      }
+    }
+  }
+  
+  /**
+   * Add config properties, making sure to read in the properties file
+   * and override the supplied properties
+   * @param props
+   */
+  public void setConfig(Properties props) {
+    config = new Properties(props);
+    URL u = ctx.getBundle().getResource(ManagedPersistenceUnitInfoFactory.ARIES_JPA_CONTAINER_PROPERTIES);
+    
+    if(u != null) {
+      if(_logger.isInfoEnabled())
+        _logger.info("A {} file was found. The default properties {} will be overridden.",
+            new Object[] {ManagedPersistenceUnitInfoFactory.ARIES_JPA_CONTAINER_PROPERTIES, config});
+      try {
+        config.load(u.openStream());
+      } catch (IOException e) {
+        _logger.error("There was an error reading from " 
+            + ManagedPersistenceUnitInfoFactory.ARIES_JPA_CONTAINER_PROPERTIES, e);
+      }
+    } else {
+      if(_logger.isInfoEnabled())
+        _logger.info("No {} file was found. The default properties {} will be used.",
+            new Object[] {ManagedPersistenceUnitInfoFactory.ARIES_JPA_CONTAINER_PROPERTIES, config});
+    }
+  }
+
+  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);
+      //Don't add to the managersAwaitingProviders, the setupManager will do it
+      setupManager(bundle, mgr, true);
+    } else {
+      try {
+        boolean reassign;
+        synchronized (this) {
+          reassign = managersAwaitingProviders.contains(mgr);
+        }
+        if(reassign) {
+          setupManager(bundle, mgr, false);
+        } else {
+          mgr.bundleStateChange();
+        }
+      } catch (InvalidPersistenceUnitException e) {
+        logInvalidPersistenceUnitException(bundle, e);
+        mgr.destroy();
+        persistenceUnitFactory.destroyPersistenceBundle(bundle);
+        
+        //Try re-initializing the manager immediately, this wasn't an
+        //update so the units don't need to be re-parsed
+        setupManager(bundle, mgr, false);
+      }
+    }
+  }
+
+  public void removedBundle(Bundle bundle, BundleEvent event, Object object) {
+    EntityManagerFactoryManager mgr = (EntityManagerFactoryManager) object;   
+    mgr.destroy();
+    persistenceUnitFactory.destroyPersistenceBundle(bundle);
+    //Remember to tidy up the map
+    synchronized (this) {
+      bundleToManagerMap.remove(bundle);
+    }
+  }
+  
+  private Collection<ParsedPersistenceUnit> parseBundle(Bundle b) {
+    
+    Collection<ParsedPersistenceUnit> pUnits = new ArrayList<ParsedPersistenceUnit>();
+    
+    Collection <PersistenceDescriptor> persistenceXmls = PersistenceBundleHelper.findPersistenceXmlFiles(b);
+
+    //If we have no persistence units then our job is done
+    if (!!!persistenceXmls.isEmpty()) {
+      
+      if(_logger.isDebugEnabled())
+        _logger.debug("Located Persistence descriptors: {} in bundle {}", new Object[] {persistenceXmls, b.getSymbolicName() + "_" + b.getVersion()});
+      
+      if(b.getState() == Bundle.ACTIVE) {
+        _logger.warn("The bundle {} is already active, it may not be possible to create managed persistence units for it.", 
+            new Object[] {b.getSymbolicName() + "_" + b.getVersion()});
+      }
+      
+      
+      
+      //Parse each descriptor
+      for(PersistenceDescriptor descriptor : persistenceXmls) {
+        try {
+          pUnits.addAll(parser.parse(b, descriptor));
+        } catch (PersistenceDescriptorParserException e) {
+          _logger.error("There was an error while parsing the persistence descriptor " 
+              + descriptor.getLocation() + " in bundle " + b.getSymbolicName() 
+              + "_" + b.getVersion() + ". No persistence units will be managed for this bundle", e);
+        }
+      }
+    }
+    return pUnits;
+  }
+  /**
+   * 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, boolean reParse) {
+
+    
+    Collection<ParsedPersistenceUnit> pUnits = 
+        (mgr == null ||reParse) ? parseBundle(bundle) : mgr.getParsedPersistenceUnits();
+ 
+      
+      //If we have any persistence units then find a provider to use
+      if(!!!pUnits.isEmpty()) {
+        
+        if(_logger.isDebugEnabled())
+          _logger.debug("Located Persistence units: {}", new Object[] {pUnits});
+        
+        ServiceReference ref = getProviderServiceReference(pUnits);
+        //If we found a provider then create the ManagedPersistenceUnitInfo objects
+        Collection<ManagedPersistenceUnitInfo> infos = null;
+        if(ref != null) {  
+          infos = persistenceUnitFactory.
+              createManagedPersistenceUnitMetadata(ctx, bundle, ref, pUnits);
+        }
+        //Either update the existing manager or create a new one
+        if(mgr != null)
+          mgr.manage(pUnits, ref, infos);
+        else 
+          mgr = new EntityManagerFactoryManager(ctx, bundle, pUnits, ref, infos);
+          
+        //Register the manager (this may re-add, but who cares)
+        synchronized (this) {
+          bundleToManagerMap.put(bundle, mgr);
+          //If the provider is gone then we need to wait
+          if(ref == null) {
+            managersAwaitingProviders.add(mgr);
+          }
+        }
+          
+        //prod the manager to get it into the right state
+        try {
+          mgr.bundleStateChange();
+        } catch (InvalidPersistenceUnitException e) {
+          logInvalidPersistenceUnitException(bundle, e);
+          mgr.destroy();
+          if(infos != null)
+            persistenceUnitFactory.destroyPersistenceBundle(bundle);
+          //Put the manager into the list of managers waiting for a new
+          //provider, one that might work!
+          synchronized (this) {
+            managersAwaitingProviders.add(mgr);
+          }
+        }
+      }
+      return mgr;
+    }
+  
+  /**
+   * Get a persistence provider from the service registry described by the
+   * persistence units defined
+   * @param parsedPersistenceUnits
+   * @return A service reference or null if no suitable reference is available
+   */
+  private synchronized ServiceReference getProviderServiceReference(Collection<ParsedPersistenceUnit> parsedPersistenceUnits)
+  {
+    Set<String> ppClassNames = new HashSet<String>();
+    List<VersionRange> versionRanges = new ArrayList<VersionRange>();
+    //Fill the set of class names and version Filters
+    for(ParsedPersistenceUnit unit : parsedPersistenceUnits)
+    {
+      Map<String, Object> metadata = unit.getPersistenceXmlMetadata();
+      String provider = (String) metadata.get(ParsedPersistenceUnit.PROVIDER_CLASSNAME);
+      //get providers specified in the persistence units
+      if(provider != null && !!!provider.equals(""))
+      {
+        ppClassNames.add(provider);
+        
+        Properties props = (Properties) metadata.get(ParsedPersistenceUnit.PROPERTIES);
+        
+        if(props != null && props.containsKey(ParsedPersistenceUnit.JPA_PROVIDER_VERSION)) {
+         
+          String versionRangeString = props.getProperty(ParsedPersistenceUnit.JPA_PROVIDER_VERSION, "0.0.0");
+          try {
+            versionRanges.add(VersionRange.parseVersionRange(versionRangeString));
+          } catch (IllegalArgumentException e) {
+            _logger.warn("There was an error parsing the version range string {} for persistence unit {}. It will be ignored."
+                , new Object[] {versionRangeString, metadata.get(ParsedPersistenceUnit.UNIT_NAME)});
+          }
+        }
+      }
+    }
+    //If we have too many provider class names or incompatible version ranges specified then blow up
+    
+    VersionRange range = null;
+    if(!!!versionRanges.isEmpty()) {
+      try {
+        range = combineVersionRanges(versionRanges);
+      } catch (InvalidRangeCombination e) {
+        Bundle bundle = parsedPersistenceUnits.iterator().next().getDefiningBundle();
+        _logger.error("The bundle " + bundle.getSymbolicName() 
+            + "_" + bundle.getVersion() + " specified an invalid combination of provider version ranges",  e);
+        return null;
+      }
+    }
+    
+    if(ppClassNames.size() > 1)
+    {
+      Bundle bundle = parsedPersistenceUnits.iterator().next().getDefiningBundle();
+      _logger.error("The bundle " + bundle.getSymbolicName() 
+          + "_" + bundle.getVersion() + " specified more than one persistence provider: {}. "
+          + "This is not supported, so no persistence units will be created for this bundle.",
+          new Object[] {ppClassNames});
+      return null;
+    } else {
+      //Get the best provider for the given filters
+      String provider = (ppClassNames.isEmpty()) ?
+          persistenceUnitFactory.getDefaultProviderClassName() : ppClassNames.iterator().next();
+          return getBestProvider(provider, range);
+    }
+  }
+ 
+  /**
+   * 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);
+    Version maxVersion = null;
+    boolean minExclusive = false;
+    boolean maxExclusive = false;
+    
+    for(VersionRange range : versionRanges) {
+      int minComparison = minVersion.compareTo(range.getMinimumVersion());
+      //If minVersion is smaller then we have a new, larger, minimum
+      if(minComparison < 0) {
+        minVersion = range.getMinimumVersion();
+        minExclusive = range.isMinimumExclusive();
+      }
+      //Only update if it is the same version but more restrictive
+      else if(minComparison == 0 && range.isMaximumExclusive())
+        minExclusive = true;
+    
+      if(range.isMaximumUnbounded())
+        continue;
+      else if (maxVersion == null) {
+        maxVersion = range.getMaximumVersion();
+        maxExclusive = range.isMaximumExclusive();
+      } else {
+        int maxComparison = maxVersion.compareTo(range.getMaximumVersion());
+        
+        //We have a new, lower maximum
+        if(maxComparison > 0) {
+          maxVersion = range.getMaximumVersion();
+          maxExclusive = range.isMaximumExclusive();
+          //If the maximum is the same then make sure we set the exclusivity properly
+        } else if (maxComparison == 0 && range.isMaximumExclusive())
+          maxExclusive = true;
+      }
+    }
+    
+    //Now check that we have valid values
+    int check = (maxVersion == null) ? -1 : minVersion.compareTo(maxVersion);
+    //If min is greater than max, or min is equal to max and one of the exclusive
+    //flags is set then we have a problem!
+    if(check > 0 || (check == 0 && (minExclusive || maxExclusive))) {
+      throw new InvalidRangeCombination(minVersion, minExclusive, maxVersion, maxExclusive);
+    }
+    
+    //Turn the Versions into a version range string
+    StringBuilder rangeString = new StringBuilder();
+    rangeString.append(minVersion);
+    
+    if(maxVersion != null) {
+      rangeString.insert(0, minExclusive ? "(" : "[");
+      rangeString.append(",");
+      rangeString.append(maxVersion);
+      rangeString.append(maxExclusive ? ")" : "]");
+    }
+    //Turn that string back into a VersionRange
+    return VersionRange.parseVersionRange(rangeString.toString());
+  }
+
+  /**
+   * Locate the best provider for the given criteria
+   * @param providerClass
+   * @param matchingCriteria
+   * @return
+   */
+  @SuppressWarnings("unchecked")
+  private synchronized ServiceReference getBestProvider(String providerClass, VersionRange matchingCriteria)
+  {
+    if(!!!persistenceProviders.isEmpty()) {
+      if((providerClass != null && !!!"".equals(providerClass))
+          || matchingCriteria != null) {
+        List<ServiceReference> refs = new ArrayList<ServiceReference>();
+        for(ServiceReference reference : persistenceProviders) {
+          
+          if(providerClass != null && !!!providerClass.equals(
+              reference.getProperty("javax.persistence.provider")))
+            continue;
+            
+          if(matchingCriteria == null || matchingCriteria.
+              matches(reference.getBundle().getVersion()))
+            refs.add(reference);
+        }
+        
+        if(!!!refs.isEmpty()) {
+          //Return the "best" provider, i.e. the highest version
+          return Collections.max(refs, new ProviderServiceComparator());
+        } else {
+          _logger.warn("There are no suitable providers for the provider class name {} and version range {}.",
+              new Object[] {providerClass, matchingCriteria});
+        }
+      } else {
+        //Return the "best" provider, i.e. the service OSGi would pick
+        return (ServiceReference) Collections.max(persistenceProviders);
+      }
+    } else {
+      _logger.warn("There are no providers available.");
+    }
+    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)
+    {
+      Version v1 = object1.getBundle().getVersion();
+      Version v2 = object2.getBundle().getVersion();
+      int res = v1.compareTo(v2);
+      if (res == 0) {
+        Integer rank1 = (Integer) object1.getProperty(Constants.SERVICE_RANKING);
+        Integer rank2 = (Integer) object2.getProperty(Constants.SERVICE_RANKING);
+        if (rank1 != null && rank2 != null)
+          res = rank1.compareTo(rank2);
+      }
+      return res;
+    }
+  }
+  
+  /**
+   * Log a warning to indicate that the Persistence units state will be destroyed
+   * @param bundle
+   * @param e
+   */
+  private void logInvalidPersistenceUnitException(Bundle bundle,
+      InvalidPersistenceUnitException e) {
+    _logger.warn("The persistence units for bundle " + bundle.getSymbolicName() + "_" + bundle.getVersion()
+        + " became invalid and will be destroyed.", e);
+  }
+}

Added: aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceDescriptorImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceDescriptorImpl.java?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceDescriptorImpl.java (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceDescriptorImpl.java Sun Feb 27 18:08:10 2011
@@ -0,0 +1,70 @@
+/*
+ * 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 java.io.InputStream;
+
+import org.apache.aries.jpa.container.parsing.PersistenceDescriptor;
+
+/**
+ * Stores the location of a persistence descriptor and
+ * a stream to its contents. Note that there is only one
+ * copy of the InputStream, only one thread should try to
+ * read from it, and it can only be closed once. 
+ */
+public class PersistenceDescriptorImpl implements PersistenceDescriptor {
+
+  /** The location of the persistence descriptor */
+  private final String location;
+  /** The wrapped InputStream */ 
+  private final InputStream inputStream;
+
+  /**
+   * Create a PersistenceDescriptor wrapping the location and InputStream
+   * @param location
+   * @param inputStream
+   */
+  public PersistenceDescriptorImpl(String location, InputStream inputStream) {
+    this.location = location;
+    this.inputStream = inputStream;
+  }
+
+  /* (non-Javadoc)
+   * @see org.apache.aries.jpa.container.impl.PersistenceDescriptor#getLocation()
+   */
+  public String getLocation() {
+    return location;
+  }
+
+  /* (non-Javadoc)
+   * @see org.apache.aries.jpa.container.impl.PersistenceDescriptor#getInputStream()
+   */
+  public InputStream getInputStream() {
+    return inputStream;
+  }
+  
+  public String toString()
+  {
+    if(location != null)
+      return location;
+    else 
+      return super.toString();
+  }
+  
+}

Added: aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/parsing/impl/EarlyParserReturn.java
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/parsing/impl/EarlyParserReturn.java?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/parsing/impl/EarlyParserReturn.java (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/parsing/impl/EarlyParserReturn.java Sun Feb 27 18:08:10 2011
@@ -0,0 +1,62 @@
+/*
+ * 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.parsing.impl;
+
+import javax.xml.validation.Schema;
+
+import org.xml.sax.SAXException;
+
+/**
+ * A convenience mechanism for finding the version of the schema to validate with
+ */
+public class EarlyParserReturn extends SAXException
+{
+  /** This class is serializable */
+  private static final long serialVersionUID = 6173561765417524327L;
+  /** The schema to use */
+  private final Schema schema;
+  /** The value of the version attribute in the xml */
+  private final String jpaVersion;
+
+  /**
+   * @return The schema that was used in the xml document
+   */
+  public Schema getSchema()
+  {
+    return schema;
+  }
+  
+  /**
+   * @return The version of the JPA schema used
+   */
+  public String getVersion()
+  {
+    return jpaVersion;
+  }
+
+  /**
+   * @param s  The schema used
+   * @param version The version of the schema used
+   */
+  public EarlyParserReturn(Schema s, String version)
+  {
+    schema = s;
+    jpaVersion = version;
+  }
+}

Added: aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/parsing/impl/JPAHandler.java
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/parsing/impl/JPAHandler.java?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/parsing/impl/JPAHandler.java (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/parsing/impl/JPAHandler.java Sun Feb 27 18:08:10 2011
@@ -0,0 +1,131 @@
+/*
+ * 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.parsing.impl;
+
+import java.util.Collection;
+import java.util.Stack;
+
+import org.osgi.framework.Bundle;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ *  This code is responsible for parsing the persistence.xml into PersistenceUnits
+ */
+public class JPAHandler extends DefaultHandler
+{
+  /** The Persistence Units that we have parsed */
+  private final Stack<PersistenceUnitImpl> persistenceUnits = new Stack<PersistenceUnitImpl>();
+  /** The name of the current element */
+  private String elementName;
+  /** The version of the persistence.xml file */
+  private final String jpaVersion;
+  /** A StringBuilder for caching the information from getCharacters */
+  private StringBuilder builder = new StringBuilder();
+  /** The bundle that contains this persistence descriptor */
+  private Bundle bundle;
+  
+  /**
+   * Create a new JPA Handler for the given peristence.xml
+   * @param data
+   * @param version  the version of the JPA schema used in the xml
+   */
+  public JPAHandler(Bundle b, String version){
+    bundle = b;
+    jpaVersion = version;
+  }
+  
+  /**
+   * Collect up the characters, as element's characters may be split across multiple
+   * calls. Isn't SAX lovely...
+   */
+  @Override
+  public void characters(char[] ch, int start, int length) throws SAXException
+  {
+    builder.append(ch, start, length);
+  }
+
+  @Override
+  public void startElement(String uri, String localName, String name, Attributes attributes)
+      throws SAXException
+  {
+    //Do this setting first as we use it later.
+    elementName = (localName == null || "".equals(localName))? name : localName;
+
+    if("persistence-unit".equals(elementName)) {
+      persistenceUnits.push(new PersistenceUnitImpl(bundle, attributes.getValue("name"), attributes.getValue("transaction-type"), jpaVersion));
+    } else if("exclude-unlisted-classes".equals(elementName))
+      persistenceUnits.peek().setExcludeUnlisted(true);
+    else if("property".equals(elementName))
+      persistenceUnits.peek().addProperty(attributes.getValue("name"), attributes.getValue("value"));
+    
+  }
+  
+
+  @Override
+  public void endElement(String uri, String localName, String name) throws SAXException
+  {
+    String s = builder.toString().trim();
+    //This step is VERY important, otherwise we pollute subsequent
+    //elements
+    builder = new StringBuilder();
+    
+    if("".equals(s)) return;
+    
+    PersistenceUnitImpl pu = persistenceUnits.peek();
+    
+    if("provider".equals(elementName))
+      pu.setProviderClassName(s);
+    else if("jta-data-source".equals(elementName))
+      pu.setJtaDataSource(s);
+    else if("non-jta-data-source".equals(elementName))
+      pu.setNonJtaDataSource(s);
+    else if("mapping-file".equals(elementName))
+      pu.addMappingFileName(s);
+    else if("jar-file".equals(elementName)) {
+      pu.addJarFileName(s);
+    } else if("class".equals(elementName))
+      pu.addClassName(s);
+    else if("exclude-unlisted-classes".equals(elementName))
+      pu.setExcludeUnlisted(Boolean.parseBoolean(s));
+    else if ("2.0".equals(jpaVersion) && "shared-cache-mode".equals(elementName))
+      pu.setSharedCacheMode(s);
+    else if ("2.0".equals(jpaVersion) && "validation-mode".equals(elementName))
+      pu.setValidationMode(s);
+  }
+
+  @Override
+  public void error(SAXParseException spe) throws SAXException
+  {
+    // We throw this exception to be caught further up and logged
+    // as an error there
+    throw spe;
+  }
+
+  /**
+   * @return The collection of persistence units that we have parsed
+   */
+  public Collection<PersistenceUnitImpl> getPersistenceUnits()
+  {
+    return persistenceUnits;
+  }
+
+}

Added: aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/parsing/impl/PersistenceDescriptorParserImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/parsing/impl/PersistenceDescriptorParserImpl.java?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/parsing/impl/PersistenceDescriptorParserImpl.java (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/parsing/impl/PersistenceDescriptorParserImpl.java Sun Feb 27 18:08:10 2011
@@ -0,0 +1,115 @@
+/*
+ * 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.parsing.impl;
+
+import java.io.BufferedInputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.validation.Schema;
+
+import org.apache.aries.jpa.container.parsing.ParsedPersistenceUnit;
+import org.apache.aries.jpa.container.parsing.PersistenceDescriptor;
+import org.apache.aries.jpa.container.parsing.PersistenceDescriptorParser;
+import org.apache.aries.jpa.container.parsing.PersistenceDescriptorParserException;
+import org.osgi.framework.Bundle;
+
+/**
+ * This class may be used to parse JPA persistence descriptors. The parser validates
+ * using the relevant version of the persistence schema as defined by the xml file. 
+ */
+public class PersistenceDescriptorParserImpl implements PersistenceDescriptorParser {
+
+  /**
+   * This class is used internally to prevent the first pass parse from
+   * closing the InputStream when it exits.
+   */
+  private static class UnclosableInputStream extends FilterInputStream {
+
+    public UnclosableInputStream(InputStream in) {
+      super(in);
+    }
+
+    @Override
+    public void close() throws IOException {
+      //No op, don't close the parent.
+    }
+  }
+  
+  /* (non-Javadoc)
+   * @see org.apache.aries.jpa.container.parsing.impl.PersistenceDescriptorParser#parse(org.osgi.framework.Bundle, org.apache.aries.jpa.container.parsing.PersistenceDescriptor)
+   */
+  public Collection<ParsedPersistenceUnit> parse(Bundle b, PersistenceDescriptor descriptor) throws PersistenceDescriptorParserException {
+    Collection<ParsedPersistenceUnit> persistenceUnits = new ArrayList<ParsedPersistenceUnit>();
+    SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+    BufferedInputStream is = null;
+    boolean schemaFound = false;
+    try {
+      //Buffer the InputStream so we can mark it, though we'll be in 
+      //trouble if we have to read more than 8192 characters before finding
+      //the schema!
+      is = new BufferedInputStream(descriptor.getInputStream(), 8192);
+      is.mark(8192);
+      SAXParser parser = parserFactory.newSAXParser();
+      try{
+        parser.parse(new UnclosableInputStream(is), new SchemaLocatingHandler());
+      } catch (EarlyParserReturn epr) {
+        //This is not really an exception, but a way to work out which
+        //version of the persistence schema to use in validation
+        Schema s = epr.getSchema();
+        
+        if(s != null) {
+          schemaFound = true;
+          parserFactory.setSchema(s);
+          parserFactory.setNamespaceAware(true);
+          parser = parserFactory.newSAXParser();
+         
+          //Get back to the beginning of the stream
+          is.reset();
+          
+          JPAHandler handler = new JPAHandler(b, epr.getVersion());
+          parser.parse(is, handler);
+          persistenceUnits.addAll(handler.getPersistenceUnits());
+        } 
+      }
+    } catch (Exception e) {
+      throw new PersistenceDescriptorParserException("There was an error parsing " + descriptor.getLocation() 
+          + " in bundle " + b.getSymbolicName() + "_" + b.getVersion(), e);
+    } finally {
+      if(is != null) try {
+        is.close();
+      } catch (IOException e) {
+        //No logging necessary, just consume
+      }
+    }
+    if(!!!schemaFound) {
+    throw new PersistenceDescriptorParserException("No Schema could be located for the" +
+        "persistence descriptor " + descriptor.getLocation() 
+        + " in bundle " + b.getSymbolicName() + "_" + b.getVersion());
+    }
+    return persistenceUnits;
+  }
+
+}

Added: aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/parsing/impl/PersistenceUnitImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/parsing/impl/PersistenceUnitImpl.java?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/parsing/impl/PersistenceUnitImpl.java (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/parsing/impl/PersistenceUnitImpl.java Sun Feb 27 18:08:10 2011
@@ -0,0 +1,208 @@
+/*
+ * 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.parsing.impl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.aries.jpa.container.parsing.ParsedPersistenceUnit;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * An implementation of PersistenceUnit for parsed persistence unit metadata
+ *
+ */
+@SuppressWarnings("unchecked")
+public class PersistenceUnitImpl implements ParsedPersistenceUnit
+{
+  /** A map to hold the metadata from the xml */
+  private final Map<String,Object> metadata = new HashMap<String, Object>();
+  /** The bundle defining this persistence unit */
+  private final Bundle bundle;
+
+  /**
+   * The Service Reference for the provider to which this persistence
+   * unit is tied
+   */
+  private ServiceReference provider;
+
+  
+  /**
+   * Create a new persistence unit with the given name, transaction type, location and
+   * defining bundle
+   * 
+   * @param name         may be null
+   * @param transactionType  may be null
+   * @param location
+   * @param version    The version of the JPA schema used in persistence.xml
+   */
+  public PersistenceUnitImpl(Bundle b, String name, String transactionType, String version)
+  {
+    this.bundle = b;
+    metadata.put(SCHEMA_VERSION, version);
+
+    if (name == null)
+      name = "";
+      
+    metadata.put(UNIT_NAME, name);
+    if (transactionType != null) metadata.put(TRANSACTION_TYPE, transactionType);
+
+  }
+  
+  
+  public Bundle getDefiningBundle()
+  {
+    return bundle;
+  }
+
+  public Map<String, Object> getPersistenceXmlMetadata()
+  {
+    Map<String, Object> data = new HashMap<String, Object>(metadata);
+    if(data.containsKey(MAPPING_FILES))
+      data.put(MAPPING_FILES, ((ArrayList) metadata.get(MAPPING_FILES)).clone());
+    if(data.containsKey(JAR_FILES))
+    data.put(JAR_FILES, ((ArrayList) metadata.get(JAR_FILES)).clone());
+    if(data.containsKey(MANAGED_CLASSES))
+    data.put(MANAGED_CLASSES, ((ArrayList) metadata.get(MANAGED_CLASSES)).clone());
+    if(data.containsKey(PROPERTIES))
+    data.put(PROPERTIES, ((Properties)metadata.get(PROPERTIES)).clone());
+    
+    return data;
+  }
+
+  /**
+   * @param provider
+   */
+  public void setProviderClassName(String provider)
+  {
+    metadata.put(PROVIDER_CLASSNAME, provider);
+  }
+
+  /**
+   * @param jtaDataSource
+   */
+  public void setJtaDataSource(String jtaDataSource)
+  {
+    metadata.put(JTA_DATASOURCE, jtaDataSource);
+  }
+
+  /**
+   * @param nonJtaDataSource
+   */
+  public void setNonJtaDataSource(String nonJtaDataSource)
+  {
+    metadata.put(NON_JTA_DATASOURCE, nonJtaDataSource);
+  }
+
+  /**
+   * @param mappingFileName
+   */
+  public void addMappingFileName(String mappingFileName)
+  {
+    List<String> files = (List<String>) metadata.get(MAPPING_FILES);
+    if(files == null) {
+      files = new ArrayList<String>();
+      metadata.put(MAPPING_FILES, files);
+    }
+    files.add(mappingFileName);
+  }
+
+  /**
+   * @param jarFile
+   */
+  public void addJarFileName(String jarFile)
+  {
+    List<String> jars = (List<String>) metadata.get(JAR_FILES);
+    if(jars == null) {
+      jars = new ArrayList<String>();
+      metadata.put(JAR_FILES, jars);
+    }
+      
+    jars.add(jarFile);
+  }
+
+  /**
+   * @param className
+   */
+  public void addClassName(String className)
+  {
+    List<String> classes = (List<String>) metadata.get(MANAGED_CLASSES);
+    if(classes == null) {
+      classes = new ArrayList<String>();
+      metadata.put(MANAGED_CLASSES, classes);
+    }
+    classes.add(className);
+  }
+
+  /**
+   * @param exclude
+   */
+  public void setExcludeUnlisted(boolean exclude)
+  {
+    metadata.put(EXCLUDE_UNLISTED_CLASSES, exclude);
+  }
+
+  /**
+   * @param name
+   * @param value
+   */
+  public void addProperty(String name, String value)
+  {
+    Properties props = (Properties) metadata.get(PROPERTIES);
+    if(props == null) {
+      props = new Properties();
+      metadata.put(PROPERTIES, props);
+    }
+    props.setProperty(name, value);
+  }
+
+  /**
+   * @param providerRef
+   */
+  public void setProviderReference(ServiceReference providerRef)
+  {
+    provider = providerRef;
+  }
+  
+  /**
+   * @param sharedCacheMode
+   */
+  public void setSharedCacheMode(String sharedCacheMode)
+  {
+    metadata.put(SHARED_CACHE_MODE, sharedCacheMode);
+  }
+  
+  /**
+   * @param validationMode
+   */
+  public void setValidationMode(String validationMode)
+  {
+    metadata.put(VALIDATION_MODE, validationMode);
+  }
+  
+  public String toString()
+  {
+    return "Persistence unit " + metadata.get(UNIT_NAME) + " in bundle "
+    + bundle.getSymbolicName() + "_" + bundle.getVersion();
+  }
+}

Added: aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/parsing/impl/SchemaLocatingHandler.java
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/parsing/impl/SchemaLocatingHandler.java?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/parsing/impl/SchemaLocatingHandler.java (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/parsing/impl/SchemaLocatingHandler.java Sun Feb 27 18:08:10 2011
@@ -0,0 +1,102 @@
+/*
+ * 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.parsing.impl;
+
+import java.net.URL;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.xml.XMLConstants;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * This parser provides a quick mechanism for determining the JPA schema level,
+ * and throws an EarlyParserReturn with the Schema to validate with
+ */
+public class SchemaLocatingHandler extends DefaultHandler
+{
+  
+  /**
+   * A static cache of schemas in use in the runtime
+   */
+  private static final ConcurrentMap<String, Schema> schemaCache = new ConcurrentHashMap<String, Schema>();
+  
+  @Override
+  public void startElement(String uri, String localName, String name, Attributes attributes)
+      throws SAXException
+  {
+    
+    Schema s = null;
+    String version = null;
+    if("persistence".equals(name)) {
+      version = attributes.getValue(uri, "version");
+       s = validate(version);
+    }
+    throw new EarlyParserReturn(s, version);
+  }
+  
+  /**
+   * Find the schema for the version of JPA we're using
+   * @param type  The value of the version attribute in the xml
+   * @return
+   * @throws SAXException
+   */
+  private final Schema validate(String type) throws SAXException
+  {
+    Schema toReturn = (type == null)? null : schemaCache.get(type);
+    
+    if(toReturn == null) {
+      toReturn = getSchema(type);
+      if(toReturn != null) schemaCache.putIfAbsent(type, toReturn);
+    }
+    
+    return toReturn;
+  }
+
+  /**
+   * Locate the schema document
+   * @param type The schema version to find
+   * @return
+   * @throws SAXException
+   */
+  private final Schema getSchema(String type) throws SAXException
+  {
+    SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+
+    URL schemaURL = null;
+    if("1.0".equals(type)) {
+      schemaURL = this.getClass().getResource("persistence.xsd.rsrc");
+    } else if ("2.0".equals(type)) {
+      schemaURL = this.getClass().getResource("persistence_2_0.xsd.rsrc");
+    }
+
+    Schema schema = null;    
+    if(schemaURL != null){
+      schema = schemaFactory.newSchema(schemaURL);
+    }
+    
+    return schema;
+  }
+  
+}

Added: aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/BundleDelegatingClassLoader.java
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/BundleDelegatingClassLoader.java?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/BundleDelegatingClassLoader.java (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/BundleDelegatingClassLoader.java Sun Feb 27 18:08:10 2011
@@ -0,0 +1,54 @@
+/*
+ * 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.io.IOException;
+import java.net.URL;
+import java.util.Enumeration;
+
+import org.osgi.framework.Bundle;
+/**
+ * This is a simple ClassLoader that delegates to the Bundle
+ * and is used by the PersistenceUnitInfo
+ */
+public class BundleDelegatingClassLoader extends ClassLoader {
+
+  private final Bundle bundle;
+  
+  public BundleDelegatingClassLoader(Bundle b) {
+    bundle = b;
+  }
+  
+  @Override
+  protected Class<?> findClass(String className) throws ClassNotFoundException {
+    return bundle.loadClass(className);
+  }
+
+  @Override
+  protected URL findResource(String resName) {
+    return bundle.getResource(resName);
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  protected Enumeration<URL> findResources(String resName) throws IOException {
+    return bundle.getResources(resName);
+  }
+
+}

Added: aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/ManagedPersistenceUnitInfoFactoryImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/ManagedPersistenceUnitInfoFactoryImpl.java?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/ManagedPersistenceUnitInfoFactoryImpl.java (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/ManagedPersistenceUnitInfoFactoryImpl.java Sun Feb 27 18:08:10 2011
@@ -0,0 +1,131 @@
+/*
+ * 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.ArrayList;
+import java.util.Collection;
+
+import org.apache.aries.jpa.container.ManagedPersistenceUnitInfo;
+import org.apache.aries.jpa.container.ManagedPersistenceUnitInfoFactory;
+import org.apache.aries.jpa.container.parsing.ParsedPersistenceUnit;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+public class ManagedPersistenceUnitInfoFactoryImpl implements
+    ManagedPersistenceUnitInfoFactory {
+
+  public Collection<ManagedPersistenceUnitInfo> createManagedPersistenceUnitMetadata(
+      BundleContext containerContext, Bundle persistenceBundle,
+      ServiceReference providerReference,
+      Collection<ParsedPersistenceUnit> persistenceMetadata) {
+    
+    //TODO add support for provider bundle imports (e.g. for weaving) here
+    
+    Collection<ManagedPersistenceUnitInfo> managedUnits = new ArrayList<ManagedPersistenceUnitInfo>();
+    
+    for(ParsedPersistenceUnit unit : persistenceMetadata)
+      managedUnits.add(new ManagedPersistenceUnitInfoImpl(persistenceBundle, unit, providerReference));
+    
+    return managedUnits;
+  }
+
+  public void destroyPersistenceBundle(Bundle bundle) {
+
+  }
+
+  public String getDefaultProviderClassName() {
+    return null;
+  }
+
+  //Code that can be used to attach a fragment for provider wiring
+  
+////If we can't find a provider then bomb out
+//if (providerRef != null)
+//{
+//  try 
+//    FragmentBuilder builder = new FragmentBuilder(b, ".jpa.fragment");
+//    builder.addImportsFromExports(providerRef.getBundle());
+//    fragment = builder.install(ctx);
+//  
+//    
+//    hostToFragmentMap.put(b, fragment);
+//    // If we successfully got a fragment then
+//    // set the provider reference and register the units
+//    Set<ServiceRegistration> registrations = new HashSet<ServiceRegistration>();
+//    Hashtable<String, Object> props = new Hashtable<String, Object>();
+//    
+//    props.put(PersistenceUnitInfoService.PERSISTENCE_BUNDLE_SYMBOLIC_NAME, b.getSymbolicName());
+//    props.put(PersistenceUnitInfoService.PERSISTENCE_BUNDLE_VERSION, b.getVersion());
+//    
+//    for(PersistenceUnitImpl unit : parsedPersistenceUnits){
+//      Hashtable<String, Object> serviceProps = new Hashtable<String, Object>(props);
+//      
+//      String unitName = (String) unit.getPersistenceXmlMetadata().get(PersistenceUnitInfoService.UNIT_NAME);
+//      if(unitName != null)
+//        serviceProps.put(PersistenceUnitInfoService.PERSISTENCE_UNIT_NAME, unitName);
+//      
+//      unit.setProviderReference(providerRef);
+//      registrations.add(ctx.registerService(PersistenceUnitInfoService.class.getName(), unit, serviceProps));
+//    }
+//    hostToPersistenceUnitMap.put(b, registrations);
+//  }
+//  catch (IOException e)
+//  {
+//    // TODO Fragment generation failed, log the error
+//    // No clean up because we didn't register the bundle yet
+//    e.printStackTrace();
+//  }
+//  catch (BundleException be) {
+//    //TODO log the failure to install the fragment, but return null
+//    // to show we didn't get a fragment installed
+//    // No clean up because we didn't register the bundle yet
+//  }
+//}
+//}
+//}
+  
+  //Code that can be used to clear up a persistence unit
+  
+///**
+// * If we have generated a resources for the supplied bundle, then
+// * tidy them  up.
+// * @param host
+// */
+//private void tidyUpPersistenceBundle(Bundle host)
+//{
+//  
+//  Bundle fragment = hostToFragmentMap.remove(host);
+//  Set<ServiceRegistration> services = hostToPersistenceUnitMap.remove(host);
+//  
+//  if(services != null) {
+//    for(ServiceRegistration reg : services)
+//      reg.unregister();
+//  }
+//  
+//  if(fragment != null){
+//    try {
+//      fragment.uninstall();
+//    } catch (BundleException be) {
+//      //TODO log this error, then hope that we don't try to
+//      //recreate the fragment before restarting the framework!
+//    }
+//  }
+//}
+}

Added: aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/ManagedPersistenceUnitInfoImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/ManagedPersistenceUnitInfoImpl.java?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/ManagedPersistenceUnitInfoImpl.java (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/ManagedPersistenceUnitInfoImpl.java Sun Feb 27 18:08:10 2011
@@ -0,0 +1,51 @@
+/*
+ * 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.Collections;
+import java.util.Map;
+
+import javax.persistence.spi.PersistenceUnitInfo;
+
+import org.apache.aries.jpa.container.ManagedPersistenceUnitInfo;
+import org.apache.aries.jpa.container.parsing.ParsedPersistenceUnit;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+
+public class ManagedPersistenceUnitInfoImpl implements
+    ManagedPersistenceUnitInfo {
+
+  private final PersistenceUnitInfo info;
+  
+  public ManagedPersistenceUnitInfoImpl(Bundle persistenceBundle,
+      ParsedPersistenceUnit unit,
+      ServiceReference providerRef) {
+    info = new PersistenceUnitInfoImpl(persistenceBundle, unit, providerRef);
+  }
+
+  public Map<String, Object> getContainerProperties() {
+    return Collections.emptyMap();
+  }
+
+  public PersistenceUnitInfo getPersistenceUnitInfo() {
+    return info;
+  }
+
+
+}

Added: aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/PersistenceUnitInfoImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/PersistenceUnitInfoImpl.java?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/PersistenceUnitInfoImpl.java (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/PersistenceUnitInfoImpl.java Sun Feb 27 18:08:10 2011
@@ -0,0 +1,197 @@
+/*
+ * 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.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.persistence.SharedCacheMode;
+import javax.persistence.ValidationMode;
+import javax.persistence.spi.ClassTransformer;
+import javax.persistence.spi.PersistenceUnitInfo;
+import javax.persistence.spi.PersistenceUnitTransactionType;
+import javax.sql.DataSource;
+
+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 PersistenceUnitInfoImpl implements PersistenceUnitInfo {
+  
+  private final Bundle bundle;
+
+  private final ParsedPersistenceUnit unit;
+  
+  private final BundleDelegatingClassLoader cl;
+  
+  private final ServiceReference providerRef;
+  
+  /** Logger */
+  private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container");
+  
+  public PersistenceUnitInfoImpl (Bundle b, ParsedPersistenceUnit parsedData, final ServiceReference providerRef)
+  {
+    bundle = b;
+    unit = parsedData;
+    this.providerRef = providerRef;
+    cl = new BundleDelegatingClassLoader(b);
+  }
+  
+  public void addTransformer(ClassTransformer arg0) {
+    // TODO Add support for class transformation from this method
+  }
+
+  public boolean excludeUnlistedClasses() {
+    Boolean result = (Boolean) unit.getPersistenceXmlMetadata().get(ParsedPersistenceUnit.EXCLUDE_UNLISTED_CLASSES);
+    return (result == null) ? false : result;
+  }
+
+  public ClassLoader getClassLoader() {
+    return cl;
+  }
+
+  @SuppressWarnings("unchecked")
+  public List<URL> getJarFileUrls() {
+    List<String> jarFiles = (List<String>) unit.getPersistenceXmlMetadata().get(ParsedPersistenceUnit.JAR_FILES);
+    List<URL> urls = new ArrayList<URL>();
+    if(jarFiles != null) {
+      for(String jarFile : jarFiles){
+        URL url = bundle.getResource(jarFile);
+        if(url == null) {
+          _logger.error("The persistence unit {} in bundle {} listed the jar file {}, but " +
+          		"{} could not be found in the bundle", new Object[]{getPersistenceUnitName(),
+              bundle.getSymbolicName() + "_" + bundle.getVersion(), jarFile, jarFile});
+        } else {
+            urls.add(url);
+        }
+      }
+    }
+    return urls;
+  }
+
+  public DataSource getJtaDataSource() {
+    String jndiString = (String) unit.getPersistenceXmlMetadata().get(ParsedPersistenceUnit.JTA_DATASOURCE);
+    DataSource toReturn = null;
+    if(jndiString != null) {
+      try {
+        InitialContext ctx = new InitialContext();
+        toReturn = (DataSource) ctx.lookup(jndiString);
+      } catch (NamingException e) {
+        _logger.error("No JTA datasource could be located using the JNDI name " + jndiString,
+            e);
+      }
+    }
+    return toReturn;
+  }
+
+  @SuppressWarnings("unchecked")
+  public List<String> getManagedClassNames() {
+    List<String> classes = (List<String>) unit.getPersistenceXmlMetadata().get(ParsedPersistenceUnit.MANAGED_CLASSES);
+    if(classes == null)
+      classes = new ArrayList<String>();
+    
+    return Collections.unmodifiableList(classes);
+  }
+
+  @SuppressWarnings("unchecked")
+  public List<String> getMappingFileNames() {
+    List<String> mappingFiles = (List<String>) unit.getPersistenceXmlMetadata().get(ParsedPersistenceUnit.MAPPING_FILES);
+    if(mappingFiles == null)
+      mappingFiles = new ArrayList<String>();
+    
+    return Collections.unmodifiableList(mappingFiles);
+  }
+
+  public ClassLoader getNewTempClassLoader() {
+    return new TempBundleDelegatingClassLoader(bundle, new BundleDelegatingClassLoader(providerRef.getBundle()));
+  }
+
+  public DataSource getNonJtaDataSource() {
+    
+    String jndiString = (String) unit.getPersistenceXmlMetadata().get(ParsedPersistenceUnit.NON_JTA_DATASOURCE);
+    DataSource toReturn = null;
+    if(jndiString != null) {
+      try {
+        InitialContext ctx = new InitialContext();
+        toReturn = (DataSource) ctx.lookup(jndiString);
+      } catch (NamingException e) {
+        _logger.error("No Non JTA datasource could be located using the JNDI name " + jndiString,
+            e);
+      }
+    }
+    return toReturn;
+  }
+
+  public String getPersistenceProviderClassName() {
+    return (String) unit.getPersistenceXmlMetadata().get(ParsedPersistenceUnit.PROVIDER_CLASSNAME);
+  }
+
+  public String getPersistenceUnitName() {
+    return (String) unit.getPersistenceXmlMetadata().get(ParsedPersistenceUnit.UNIT_NAME);
+  }
+
+  public URL getPersistenceUnitRootUrl() {
+    return bundle.getResource("/");
+  }
+
+  public String getPersistenceXMLSchemaVersion() {
+    return (String) unit.getPersistenceXmlMetadata().get(ParsedPersistenceUnit.SCHEMA_VERSION);
+  }
+
+  public Properties getProperties() {
+    return (Properties) unit.getPersistenceXmlMetadata().get(ParsedPersistenceUnit.PROPERTIES);
+  }
+
+  public SharedCacheMode getSharedCacheMode() {
+    String s = (String) unit.getPersistenceXmlMetadata().get(ParsedPersistenceUnit.SHARED_CACHE_MODE);
+    
+    if (s == null)
+      return SharedCacheMode.UNSPECIFIED;
+    else
+      return SharedCacheMode.valueOf(s);
+  }
+
+  public PersistenceUnitTransactionType getTransactionType() {
+    
+    String s = (String) unit.getPersistenceXmlMetadata().get(ParsedPersistenceUnit.TRANSACTION_TYPE);
+
+    if(s == null)
+      return PersistenceUnitTransactionType.JTA;
+    else
+      return PersistenceUnitTransactionType.valueOf(s);
+  }
+
+  public ValidationMode getValidationMode() {
+    String s = (String) unit.getPersistenceXmlMetadata().get(ParsedPersistenceUnit.VALIDATION_MODE);
+    
+    if (s == null)
+      return ValidationMode.AUTO;
+    else
+      return ValidationMode.valueOf(s);
+
+  }
+  
+}
\ No newline at end of file

Added: aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/TempBundleDelegatingClassLoader.java
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/TempBundleDelegatingClassLoader.java?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/TempBundleDelegatingClassLoader.java (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/TempBundleDelegatingClassLoader.java Sun Feb 27 18:08:10 2011
@@ -0,0 +1,80 @@
+/*
+ * 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.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Enumeration;
+
+import org.osgi.framework.Bundle;
+
+/**
+ * This is a simple temporary ClassLoader that delegates to the Bundle,
+ * but does not call loadClass. It is used by the PersistenceUnitInfo
+ */
+public class TempBundleDelegatingClassLoader extends ClassLoader {
+
+  private final Bundle bundle;
+  
+  public TempBundleDelegatingClassLoader(Bundle b, ClassLoader parent) {
+    super(parent);
+    bundle = b;
+  }
+  
+  @Override
+  protected Class<?> findClass(String className) throws ClassNotFoundException {
+    String classResName = className.replace('.', '/').concat(".class");
+    
+    //Don't use loadClass, just load the bytes and call defineClass
+    InputStream is = getResourceAsStream(classResName);
+    
+    if(is == null)
+      throw new ClassNotFoundException(className);
+    
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    
+    byte[] buff = new byte[4096];
+    try {
+      int read = is.read(buff);
+      while(read >0) {
+        baos.write(buff, 0, read);
+        read = is.read(buff);
+      }
+    } catch (IOException ioe) {
+      throw new ClassNotFoundException(className, ioe);
+    }
+    
+    buff = baos.toByteArray();
+    
+    return defineClass(className, buff, 0, buff.length);
+  }
+
+  @Override
+  protected URL findResource(String resName) {
+    return bundle.getResource(resName);
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  protected Enumeration<URL> findResources(String resName) throws IOException {
+    return bundle.getResources(resName);
+  }
+}

Added: aries/tags/jpa-0.1-incubating/jpa-container/src/main/resources/OSGI-INF/blueprint/jpa.xml
URL: http://svn.apache.org/viewvc/aries/tags/jpa-0.1-incubating/jpa-container/src/main/resources/OSGI-INF/blueprint/jpa.xml?rev=1075099&view=auto
==============================================================================
--- aries/tags/jpa-0.1-incubating/jpa-container/src/main/resources/OSGI-INF/blueprint/jpa.xml (added)
+++ aries/tags/jpa-0.1-incubating/jpa-container/src/main/resources/OSGI-INF/blueprint/jpa.xml Sun Feb 27 18:08:10 2011
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+    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.
+-->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+    <bean id="container"  class="org.apache.aries.jpa.container.impl.PersistenceBundleManager" init-method="open" destroy-method="close">
+      <argument ref="blueprintBundleContext"/>
+      <property name="config"><props/></property>
+      <property name="parser" ref="parser"/>
+    </bean>
+
+    <bean id="parser" class="org.apache.aries.jpa.container.parsing.impl.PersistenceDescriptorParserImpl"/>
+
+	<reference-list interface="javax.persistence.spi.PersistenceProvider" availability="optional">
+	  <reference-listener ref="container" bind-method="addingProvider" unbind-method="removingProvider"/>
+	</reference-list>
+    
+    <service interface="org.apache.aries.jpa.container.parsing.PersistenceDescriptorParser" ref="parser"/>
+    
+</blueprint>



Mime
View raw message