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