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)
{