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 javax.persistence Show documentation
Show all versions of javax.persistence Show documentation
The Java Persistence API (JPA) : a standard interface-based Java model abstraction of persistence, developed by the JCP.
/*
* Copyright (c) 2008, 2009, 2011 Oracle, Inc. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution. The Eclipse Public License is available
* at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License
* is available at http://www.eclipse.org/org/documents/edl-v10.php.
*/
package javax.persistence.spi;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* 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 PersistenceProviderResolver singleton = new DefaultPersistenceProviderResolver();
/**
* Returns the current persistence provider resolver.
* @return the current persistence provider resolver
*/
public static PersistenceProviderResolver getPersistenceProviderResolver()
{
return singleton;
}
/**
* Defines the persistence provider resolver used.
* @param resolver persistence provider resolver to be used.
*/
public static void setPersistenceProviderResolver(PersistenceProviderResolver resolver)
{
if (resolver == null)
{
singleton = new DefaultPersistenceProviderResolver();
}
else
{
singleton = resolver;
}
}
/**
* Default provider resolver class to use when none is explicitly set. Uses service loading mechanism as
* described in the Java Persistence specification. A ServiceLoader.load() call is made with the current
* context classloader to find the service provider files on the classpath.
*/
private static class DefaultPersistenceProviderResolver implements PersistenceProviderResolver
{
/**
* Cached list of available providers cached by CacheKey to ensure there is not potential for provider
* visibility issues.
*/
private volatile Map providers = new HashMap<>();
/**
* Queue for reference objects referring to class loaders or persistence providers.
*/
private static final ReferenceQueue referenceQueue = new ReferenceQueue();
public List getPersistenceProviders()
{
// Before we do the real loading work, see whether we need to
// do some cleanup: If references to class loaders or
// persistence providers have been nulled out, remove all related
// information from the cache.
processQueue();
ClassLoader loader = getContextClassLoader();
CacheKey cacheKey = new CacheKey(loader);
PersistenceProviderReference providersReferent = this.providers.get(cacheKey);
List loadedProviders = null;
if (providersReferent != null)
{
loadedProviders = providersReferent.get();
}
if (loadedProviders == null)
{
loadedProviders = new ArrayList<>();
Iterator ipp = ServiceLoader.load(PersistenceProvider.class, loader).iterator();
try
{
while (ipp.hasNext())
{
try
{
PersistenceProvider pp = ipp.next();
loadedProviders.add(pp);
}
catch (ServiceConfigurationError sce)
{
log(Level.FINEST, sce.toString());
}
}
}
catch (ServiceConfigurationError sce)
{
log(Level.FINEST, sce.toString());
}
// If none are found we'll log the provider names for diagnostic
// purposes.
if (loadedProviders.isEmpty())
{
}
providersReferent = new PersistenceProviderReference(loadedProviders, referenceQueue, cacheKey);
this.providers.put(cacheKey, providersReferent);
}
return loadedProviders;
}
/**
* Remove garbage collected cache keys & providers.
*/
private void processQueue()
{
CacheKeyReference ref;
while ((ref = (CacheKeyReference) referenceQueue.poll()) != null)
{
providers.remove(ref.getCacheKey());
}
}
/**
* Wraps Thread.currentThread().getContextClassLoader()
into a doPrivileged block if
* security manager is present
*/
private static ClassLoader getContextClassLoader()
{
if (System.getSecurityManager() == null)
{
return Thread.currentThread().getContextClassLoader();
}
else
{
return (ClassLoader) java.security.AccessController.doPrivileged(new java.security.PrivilegedAction()
{
public java.lang.Object run()
{
return Thread.currentThread().getContextClassLoader();
}
});
}
}
private static final String LOGGER_SUBSYSTEM = "javax.persistence.spi";
private Logger logger;
private void log(Level level, String message)
{
if (this.logger == null)
{
this.logger = Logger.getLogger(LOGGER_SUBSYSTEM);
}
this.logger.log(level, LOGGER_SUBSYSTEM + "::" + message);
}
/**
* Clear all cached providers
*/
public void clearCachedProviders()
{
this.providers.clear();
}
/**
* The common interface to get a CacheKey implemented by LoaderReference and
* PersistenceProviderReference.
*/
private interface CacheKeyReference
{
public CacheKey getCacheKey();
}
/**
* Key used for cached persistence providers. The key checks the class loader to determine if the
* persistence providers is a match to the requested one. The loader may be null.
*/
private class CacheKey implements Cloneable
{
/* Weak Reference to ClassLoader */
private LoaderReference loaderRef;
/* Cached Hashcode */
private int hashCodeCache;
CacheKey(ClassLoader loader)
{
if (loader == null)
{
this.loaderRef = null;
}
else
{
loaderRef = new LoaderReference(loader, referenceQueue, this);
}
calculateHashCode();
}
ClassLoader getLoader()
{
return (loaderRef != null) ? loaderRef.get() : null;
}
public boolean equals(Object other)
{
if (this == other)
{
return true;
}
try
{
final CacheKey otherEntry = (CacheKey) other;
// quick check to see if they are not equal
if (hashCodeCache != otherEntry.hashCodeCache)
{
return false;
}
// are refs (both non-null) or (both null)?
if (loaderRef == null)
{
return otherEntry.loaderRef == null;
}
ClassLoader loader = loaderRef.get();
return (otherEntry.loaderRef != null)
// with a null reference we can no longer find
// out which class loader was referenced; so
// treat it as unequal
&& (loader != null) && (loader == otherEntry.loaderRef.get());
}
catch (NullPointerException e)
{
}
catch (ClassCastException e)
{
}
return false;
}
public int hashCode()
{
return hashCodeCache;
}
private void calculateHashCode()
{
ClassLoader loader = getLoader();
if (loader != null)
{
hashCodeCache = loader.hashCode();
}
}
public Object clone()
{
try
{
CacheKey clone = (CacheKey) super.clone();
if (loaderRef != null)
{
clone.loaderRef = new LoaderReference(loaderRef.get(), referenceQueue, clone);
}
return clone;
}
catch (CloneNotSupportedException e)
{
// this should never happen
throw new InternalError();
}
}
public String toString()
{
return "CacheKey[" + getLoader() + ")]";
}
}
/**
* References to class loaders are weak references, so that they can be garbage collected when nobody
* else is using them. The DefaultPersistenceProviderResolver class has no reason to keep class
* loaders alive.
*/
private class LoaderReference extends WeakReference implements CacheKeyReference
{
private CacheKey cacheKey;
LoaderReference(ClassLoader referent, ReferenceQueue q, CacheKey key)
{
super(referent, q);
cacheKey = key;
}
public CacheKey getCacheKey()
{
return cacheKey;
}
}
/**
* References to persistence provider are soft references so that they can be garbage collected when
* they have no hard references.
*/
private class PersistenceProviderReference extends SoftReference> implements CacheKeyReference
{
private CacheKey cacheKey;
PersistenceProviderReference(List referent, ReferenceQueue q, CacheKey key)
{
super(referent, q);
cacheKey = key;
}
public CacheKey getCacheKey()
{
return cacheKey;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy