javax.persistence.spi.PersistenceProviderResolverHolder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jpa-api Show documentation
Show all versions of jpa-api Show documentation
Hibernate developmental JSR 317 (Java Persistence API 2.0) contracts. Used to
allow incremental implementation of features on the way to full JPA 2.0 support.
The newest version!
// $Id: PersistenceProviderResolverHolder.java 17201 2009-07-25 05:24:55Z epbernard $
// EJB3 Specification Copyright 2004-2009 Sun Microsystems, Inc.
package javax.persistence.spi;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.ref.WeakReference;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.persistence.PersistenceException;
/**
* Holds the global PersistenceProviderResolver instance.
* If no PersistenceProviderResolver is set by the environment,
* the default PersistenceProviderResolver is used.
*
* Implementations must be thread-safe.
*/
public class PersistenceProviderResolverHolder {
private static volatile PersistenceProviderResolver resolver;
private static final PersistenceProviderResolver defaultResolver = new PersistenceProviderResolverPerClassLoader();
/**
* Returns the current persistence provider resolver
*/
public static PersistenceProviderResolver getPersistenceProviderResolver() {
return resolver == null ? defaultResolver : resolver;
}
/**
* Defines the persistence provider resolver used
*/
public static void setPersistenceProviderResolver(PersistenceProviderResolver resolver) {
PersistenceProviderResolverHolder.resolver = resolver;
}
/**
* Cache PersistenceProviderResolver per classloader and use the current classloader as a
* key.
* Use CachingPersistenceProviderResolver for each PersistenceProviderResolver instance.
*
* @author Emmanuel Bernard
*/
private static class PersistenceProviderResolverPerClassLoader implements PersistenceProviderResolver {
//FIXME use a ConcurrentHashMap with weak entry
private final WeakHashMap resolvers =
new WeakHashMap();
private volatile short barrier = 1;
public List getPersistenceProviders() {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if ( cl == null ) {
cl = PersistenceProviderResolverPerClassLoader.class.getClassLoader();
}
if (barrier == 1) {} //read barrier syncs state with other threads
PersistenceProviderResolver currentResolver = resolvers.get( cl );
if (currentResolver == null) {
currentResolver = new CachingPersistenceProviderResolver(cl);
resolvers.put( cl, currentResolver );
barrier = 1;
}
return currentResolver.getPersistenceProviders();
}
/**
* Resolve the list of Persistence providers for a given classloader and cache the results.
*
* Avoids to keep any reference from this class to the classloader being
* passed to the constructor.
*
* @author Emmanuel Bernard
*/
private static class CachingPersistenceProviderResolver implements PersistenceProviderResolver {
//this assumes that the class loader keeps the list of classes loaded
private final List>> resolverClasses;
public CachingPersistenceProviderResolver(ClassLoader cl) {
resolverClasses = new ArrayList>>();
try {
Enumeration resources = cl.getResources( "META-INF/services/" + PersistenceProvider.class.getName() );
Set names = new HashSet();
while ( resources.hasMoreElements() ) {
URL url = resources.nextElement();
InputStream is = url.openStream();
try {
names.addAll( providerNamesFromReader( new BufferedReader( new InputStreamReader( is ) ) ) );
}
finally {
is.close();
}
}
for ( String s : names ) {
@SuppressWarnings( "unchecked" )
Class extends PersistenceProvider> providerClass = (Class extends PersistenceProvider>) cl.loadClass( s );
WeakReference> reference
= new WeakReference>(providerClass);
//keep Hibernate atop
if ( s.endsWith( "HibernatePersistence" ) && resolverClasses.size() > 0 ) {
WeakReference> movedReference = resolverClasses.get( 0 );
resolverClasses.add( 0, reference );
resolverClasses.add( movedReference );
}
else {
resolverClasses.add( reference );
}
}
}
catch ( IOException e ) {
throw new PersistenceException( e );
}
catch ( ClassNotFoundException e ) {
throw new PersistenceException( e );
}
}
//TODO find a way to cache property instances
//problem #1: avoid hard ref with classloader (List>?
//problem #2: avoid half GC lists
public List getPersistenceProviders() {
List providers = new ArrayList( resolverClasses.size() );
try {
for ( WeakReference> providerClass : resolverClasses ) {
providers.add( providerClass.get().newInstance() );
}
}
catch ( InstantiationException e ) {
throw new PersistenceException( e );
}
catch ( IllegalAccessException e ) {
throw new PersistenceException( e );
}
return providers;
}
private static final Pattern nonCommentPattern = Pattern.compile( "^([^#]+)" );
private static Set providerNamesFromReader(BufferedReader reader) throws IOException {
Set names = new HashSet();
String line;
while ( ( line = reader.readLine() ) != null ) {
line = line.trim();
Matcher m = nonCommentPattern.matcher( line );
if ( m.find() ) {
names.add( m.group().trim() );
}
}
return names;
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy