JPA_SPEC-146: use ServiceLoader to find providers
Signed-off-by: Lukas Jungmann <lukas.jungmann@oracle.com>
diff --git a/src/javax/persistence/spi/PersistenceProviderResolverHolder.java b/src/javax/persistence/spi/PersistenceProviderResolverHolder.java
index f81f111..daf9db9 100644
--- a/src/javax/persistence/spi/PersistenceProviderResolverHolder.java
+++ b/src/javax/persistence/spi/PersistenceProviderResolverHolder.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008 - 2014 Oracle Corporation. All rights reserved.
+ * Copyright (c) 2008 - 2017 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
@@ -9,31 +9,25 @@
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
+ * Lukas Jungmann - Java Persistence 2.2
* 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.Iterator;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
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}
@@ -73,11 +67,9 @@
/**
* 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.
+ * 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 {
@@ -109,31 +101,25 @@
}
if (loadedProviders == null) {
- Collection<ProviderName> providerNames = getProviderNames(loader);
- loadedProviders = new ArrayList<PersistenceProvider>();
-
- 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);
+ loadedProviders = new ArrayList<>();
+ Iterator<PersistenceProvider> 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() && !providerNames.isEmpty()) {
- log(Level.WARNING, "No valid providers found using:");
- for (ProviderName name : providerNames) {
- log(Level.WARNING, name.toString());
- }
+ if (loadedProviders.isEmpty()) {
+ log(Level.WARNING, "No valid providers found.");
}
providersReferent = new PersistenceProviderReference(loadedProviders, referenceQueue, cacheKey);
@@ -184,63 +170,6 @@
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 Collection<ProviderName> getProviderNames(ClassLoader loader) {
- Enumeration<URL> resources = null;
-
- try {
- resources = loader.getResources(SERVICE_PROVIDER_FILE);
- } catch (IOException ioe) {
- throw new PersistenceException("IOException caught: " + loader + ".getResources(" + SERVICE_PROVIDER_FILE + ")", ioe);
- }
-
- Collection<ProviderName> providerNames = new ArrayList<ProviderName>();
-
- 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<ProviderName> 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
*/
@@ -248,36 +177,6 @@
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