![JAR search and dependency download from the Maven repository](/logo.png)
javax.persistence.spi.PersistenceProviderResolverHolder Maven / Gradle / Ivy
/******************************************************************************* * Copyright (c) 2008 - 2013 Oracle Corporation. 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. * * Contributors: * Linda DeMichiel - Java Persistence 2.1 * Linda DeMichiel - Java Persistence 2.0 * ******************************************************************************/ package javax.persistence.spi; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.List; import java.util.HashMap; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.persistence.PersistenceException; /** * Holds the global {@link javax.persistence.spi.PersistenceProviderResolver} * instance. If no
PersistenceProviderResolver is used. * * Implementations must be thread-safe. * * @since Java Persistence 2.0 */ 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 the META-INF/services approach as described in the Java Persistence * specification. A getResources() call is made on the current context * classloader to find the service provider files on the classpath. Any * service files found are then read to obtain the classes that implement * the persistence provider interface. */ 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 HashMapPersistenceProviderResolver
is set by the * environment, the defaultproviders = 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) { Collection providerNames = getProviderNames(loader); loadedProviders = new ArrayList (); for (ProviderName providerName : providerNames) { try { PersistenceProvider provider = (PersistenceProvider) loader.loadClass(providerName.getName()).newInstance(); loadedProviders.add(provider); } catch (ClassNotFoundException cnfe) { log(Level.FINEST, cnfe + ": " + providerName); } catch (InstantiationException ie) { log(Level.FINEST, ie + ": " + providerName); } catch (IllegalAccessException iae) { log(Level.FINEST, iae + ": " + providerName); } catch (ClassCastException cce) { log(Level.FINEST, cce + ": " + providerName); } } // If none are found we'll log the provider names for diagnostic // purposes. if (loadedProviders.isEmpty() && !providerNames.isEmpty()) { log(Level.WARNING, "No valid providers found using:"); for (ProviderName name : providerNames) { log(Level.WARNING, name.toString()); } } 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); } private static final String SERVICE_PROVIDER_FILE = "META-INF/services/javax.persistence.spi.PersistenceProvider"; /** * Locate all JPA provider services files and collect all of the * provider names available. */ private CollectiongetProviderNames(ClassLoader loader) { Enumeration resources = null; try { resources = loader.getResources(SERVICE_PROVIDER_FILE); } catch (IOException ioe) { throw new PersistenceException("IOException caught: " + loader + ".getResources(" + SERVICE_PROVIDER_FILE + ")", ioe); } Collection providerNames = new ArrayList (); while (resources.hasMoreElements()) { URL url = resources.nextElement(); addProviderNames(url, providerNames); } return providerNames; } private static final Pattern nonCommentPattern = Pattern.compile("^([^#]+)"); /** * For each services file look for uncommented provider names on each * line. */ private void addProviderNames(URL url, Collection providerNames) { InputStream in = null; try { in = url.openStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); String line; while ((line = reader.readLine()) != null) { line = line.trim(); Matcher m = nonCommentPattern.matcher(line); if (m.find()) { providerNames.add(new ProviderName(m.group().trim(), url)); } } } catch (IOException ioe) { throw new PersistenceException("IOException caught reading: " + url, ioe); } finally { if (in != null) { try { in.close(); } catch (IOException e) { } } } } /** * Clear all cached providers */ public void clearCachedProviders() { this.providers.clear(); } /** * A ProviderName captures each provider name found in a service file as * well as the URL for the service file it was found in. This * information is only used for diagnostic purposes. */ private class ProviderName { /** Provider name **/ private String name; /** URL for the service file where the provider name was found **/ private URL source; public ProviderName(String name, URL sourceURL) { this.name = name; this.source = sourceURL; } public String getName() { return name; } public URL getSource() { return source; } public String toString() { return getName() + " - " + getSource(); } } /** * 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