#194: Simplify implementation lookup

Signed-off-by: Lukas Jungmann <lukas.jungmann@oracle.com>
diff --git a/jaxb-api/src/main/java/jakarta/xml/bind/ContextFinder.java b/jaxb-api/src/main/java/jakarta/xml/bind/ContextFinder.java
index 65667d8..6435cd1 100644
--- a/jaxb-api/src/main/java/jakarta/xml/bind/ContextFinder.java
+++ b/jaxb-api/src/main/java/jakarta/xml/bind/ContextFinder.java
@@ -10,10 +10,8 @@
 
 package jakarta.xml.bind;
 
-import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.net.URL;
@@ -32,16 +30,13 @@
  * This class is package private and therefore is not exposed as part of the
  * Jakarta XML Binding API.
  *
- * This code is designed to implement the JAXB 1.0 spec pluggability feature
+ * This code is designed to implement the XML Binding spec pluggability feature
  *
  * @author <ul><li>Ryan Shoemaker, Sun Microsystems, Inc.</li></ul>
  * @see JAXBContext
  */
 class ContextFinder {
 
-    // previous value of JAXBContext.JAXB_CONTEXT_FACTORY, using also this to ensure backwards compatibility
-    private static final String JAXB_CONTEXT_FACTORY_DEPRECATED = "jakarta.xml.bind.context.factory";
-
     private static final Logger logger;
 
     /**
@@ -303,18 +298,6 @@
         //ModuleUtil is mr-jar class, scans context path for jaxb classes on jdk9 and higher
         Class<?>[] contextPathClasses = ModuleUtil.getClassesFromContextPath(contextPath, classLoader);
 
-        //first try with classloader#getResource
-        String factoryClassName = jaxbProperties(contextPath, classLoader, factoryId);
-        if (factoryClassName == null && contextPathClasses != null) {
-            //try with class#getResource
-            factoryClassName = jaxbProperties(contextPathClasses, factoryId);
-        }
-
-        if (factoryClassName != null) {
-            return newInstance(contextPath, contextPathClasses, factoryClassName, classLoader, properties);
-        }
-
-
         String factoryName = classNameFromSystemProperties();
         if (factoryName != null) return newInstance(contextPath, contextPathClasses, factoryName, classLoader, properties);
 
@@ -326,12 +309,8 @@
             return obj.createContext(contextPath, classLoader, properties);
         }
 
-        // to ensure backwards compatibility
-        factoryName = firstByServiceLoaderDeprecated(JAXBContext.class, classLoader);
-        if (factoryName != null) return newInstance(contextPath, contextPathClasses, factoryName, classLoader, properties);
-
         Class<?> ctxFactory = (Class<?>) ServiceLoaderUtil.lookupUsingOSGiServiceLoader(
-                "jakarta.xml.bind.JAXBContext", logger);
+                JAXBContext.JAXB_CONTEXT_FACTORY, logger);
 
         if (ctxFactory != null) {
             return newInstance(contextPath, contextPathClasses, ctxFactory, classLoader, properties);
@@ -343,34 +322,6 @@
     }
 
     static JAXBContext find(Class<?>[] classes, Map<String, ?> properties) throws JAXBException {
-
-        // search for jaxb.properties in the class loader of each class first
-        logger.fine("Searching jaxb.properties");
-        for (final Class<?> c : classes) {
-            // this classloader is used only to load jaxb.properties, so doing this should be safe.
-            // this is possible for primitives, arrays, and classes that are
-            // loaded by poorly implemented ClassLoaders
-            if (c.getPackage() == null) continue;
-
-            // TODO: do we want to optimize away searching the same package?  org.Foo, org.Bar, com.Baz
-            // classes from the same package might come from different class loades, so it might be a bad idea
-            // TODO: it's easier to look things up from the class
-            // c.getResourceAsStream("jaxb.properties");
-
-            URL jaxbPropertiesUrl = getResourceUrl(c, "jaxb.properties");
-
-            if (jaxbPropertiesUrl != null) {
-
-                String factoryClassName =
-                        classNameFromPackageProperties(
-                                jaxbPropertiesUrl,
-                                JAXBContext.JAXB_CONTEXT_FACTORY, JAXB_CONTEXT_FACTORY_DEPRECATED);
-
-                return newInstance(classes, properties, factoryClassName, getClassClassLoader(c));
-            }
-
-        }
-
         String factoryClassName = classNameFromSystemProperties();
         if (factoryClassName != null) return newInstance(classes, properties, factoryClassName);
 
@@ -382,22 +333,9 @@
             return factory.createContext(classes, properties);
         }
 
-        // to ensure backwards compatibility
-        ClassLoader loader = getContextClassLoader();
-        // it is guaranteed classes are not null but it is not guaranteed, that array is not empty
-        if (classes.length > 0) {
-            ClassLoader c = getClassClassLoader(classes[0]);
-            //switch to classloader which loaded the class if it is not a bootstrap cl
-            if (c != null) {
-                loader = c;
-            }
-        }
-        String className = firstByServiceLoaderDeprecated(JAXBContext.class, loader);
-        if (className != null) return newInstance(classes, properties, className, loader);
-
         logger.fine("Trying to create the platform default provider");
         Class<?> ctxFactoryClass =
-                (Class) ServiceLoaderUtil.lookupUsingOSGiServiceLoader("jakarta.xml.bind.JAXBContext", logger);
+                (Class) ServiceLoaderUtil.lookupUsingOSGiServiceLoader(JAXBContext.JAXB_CONTEXT_FACTORY, logger);
 
         if (ctxFactoryClass != null) {
             return newInstance(classes, properties, ctxFactoryClass);
@@ -408,53 +346,14 @@
         return newInstance(classes, properties, DEFAULT_FACTORY_CLASS);
     }
 
-
-    /**
-     * first factoryId should be the preferred one,
-     * more of those can be provided to support backwards compatibility
-     */
-    private static String classNameFromPackageProperties(URL packagePropertiesUrl,
-                                                         String ... factoryIds) throws JAXBException {
-
-        logger.log(Level.FINE, "Trying to locate {0}", packagePropertiesUrl.toString());
-        Properties props = loadJAXBProperties(packagePropertiesUrl);
-        for(String factoryId : factoryIds) {
-            if (props.containsKey(factoryId)) {
-                return props.getProperty(factoryId);
-            }
-        }
-        //Factory key not found
-        String propertiesUrl = packagePropertiesUrl.toExternalForm();
-        String packageName = propertiesUrl.substring(0, propertiesUrl.indexOf("/jaxb.properties"));
-        throw new JAXBException(Messages.format(Messages.MISSING_PROPERTY, packageName, factoryIds[0]));
-    }
-
     private static String classNameFromSystemProperties() throws JAXBException {
 
         String factoryClassName = getSystemProperty(JAXBContext.JAXB_CONTEXT_FACTORY);
         if (factoryClassName != null) {
             return factoryClassName;
         }
-        // leave this here to assure compatibility
-        factoryClassName = getDeprecatedSystemProperty(JAXB_CONTEXT_FACTORY_DEPRECATED);
-        if (factoryClassName != null) {
-            return factoryClassName;
-        }
-        // leave this here to assure compatibility
-        factoryClassName = getDeprecatedSystemProperty(JAXBContext.class.getName());
-        if (factoryClassName != null) {
-            return factoryClassName;
-        }
-        return null;
-    }
 
-    private static String getDeprecatedSystemProperty(String property) {
-        String value = getSystemProperty(property);
-        if (value != null) {
-            logger.log(Level.WARNING, "Using non-standard property: {0}. Property {1} should be used instead.",
-                    new Object[] {property, JAXBContext.JAXB_CONTEXT_FACTORY});
-        }
-        return value;
+        return null;
     }
 
     private static String getSystemProperty(String property) {
@@ -588,72 +487,4 @@
         }
     }
 
-    // ServiceLoaderUtil.firstByServiceLoaderDeprecated should be used instead.
-    @Deprecated
-    static String firstByServiceLoaderDeprecated(Class<?> spiClass,
-                                                 ClassLoader classLoader) throws JAXBException {
-
-        final String jaxbContextFQCN = spiClass.getName();
-
-        logger.fine("Searching META-INF/services");
-
-        // search META-INF services next
-        BufferedReader r = null;
-        final String resource = "META-INF/services/" + jaxbContextFQCN;
-        try {
-            final InputStream resourceStream =
-                    (classLoader == null) ?
-                            ClassLoader.getSystemResourceAsStream(resource) :
-                            classLoader.getResourceAsStream(resource);
-
-            if (resourceStream != null) {
-                r = new BufferedReader(new InputStreamReader(resourceStream, "UTF-8"));
-                String factoryClassName = r.readLine();
-                if (factoryClassName != null) {
-                    factoryClassName = factoryClassName.trim();
-                }
-                r.close();
-                logger.log(Level.FINE, "Configured factorty class:{0}", factoryClassName);
-                return factoryClassName;
-            } else {
-                logger.log(Level.FINE, "Unable to load:{0}", resource);
-                return null;
-            }
-        } catch (IOException e) {
-            throw new JAXBException(e);
-        } finally {
-            try {
-                if (r != null) {
-                    r.close();
-                }
-            } catch (IOException ex) {
-                logger.log(Level.SEVERE, "Unable to close resource: " + resource, ex);
-            }
-        }
-    }
-
-    private static String jaxbProperties(String contextPath, ClassLoader classLoader, String factoryId) throws JAXBException {
-        String[] packages = contextPath.split(":");
-
-        for (String pkg : packages) {
-            String pkgUrl = pkg.replace('.', '/');
-            URL jaxbPropertiesUrl = getResourceUrl(classLoader, pkgUrl + "/jaxb.properties");
-            if (jaxbPropertiesUrl != null) {
-                return classNameFromPackageProperties(jaxbPropertiesUrl,
-                                                      factoryId, JAXB_CONTEXT_FACTORY_DEPRECATED);
-            }
-        }
-        return null;
-    }
-
-    private static String jaxbProperties(Class<?>[] classesFromContextPath, String factoryId) throws JAXBException {
-        for (Class<?> c : classesFromContextPath) {
-            URL jaxbPropertiesUrl = getResourceUrl(c, "jaxb.properties");
-            if (jaxbPropertiesUrl != null) {
-                return classNameFromPackageProperties(jaxbPropertiesUrl, factoryId, JAXB_CONTEXT_FACTORY_DEPRECATED);
-            }
-        }
-        return null;
-    }
-
 }
diff --git a/jaxb-api/src/main/java/jakarta/xml/bind/JAXBContext.java b/jaxb-api/src/main/java/jakarta/xml/bind/JAXBContext.java
index 5967785..e3a99bc 100644
--- a/jaxb-api/src/main/java/jakarta/xml/bind/JAXBContext.java
+++ b/jaxb-api/src/main/java/jakarta/xml/bind/JAXBContext.java
@@ -13,10 +13,8 @@
 import org.w3c.dom.Node;
 
 import java.io.IOException;
-import java.io.InputStream;
 import java.util.Collections;
 import java.util.Map;
-import java.util.Properties;
 
 /**
  * The {@code JAXBContext} class provides the client's entry point to the
@@ -44,21 +42,7 @@
  * </ul>
  *
  * <p><i>
- * The following JAXB 1.0 requirement is only required for schema to
- * java interface/implementation binding. It does not apply to Jakarta XML Binding annotated
- * classes. Jakarta XML Binding Providers must generate a {@code jaxb.properties} file in
- * each package containing schema derived classes.  The property file must
- * contain a property named {@code jakarta.xml.bind.context.factory} whose
- * value is the name of the class that implements the {@code createContext}
- * APIs.</i>
- *
- * <p><i>
- * The class supplied by the provider does not have to be assignable to
- * {@code jakarta.xml.bind.JAXBContext}, it simply has to provide a class that
- * implements the {@code createContext} APIs.</i>
- *
- * <p><i>
- * In addition, the provider must call the
+ * The provider must call the
  * {@link DatatypeConverter#setDatatypeConverter(DatatypeConverterInterface)
  * DatatypeConverter.setDatatypeConverter} api prior to any client
  * invocations of the marshal and unmarshal methods.  This is necessary to
@@ -191,29 +175,8 @@
  * <ol>
  *
  * <li>
- * Packages/classes explicitly passed in to the {@link #newInstance} method are processed in the order they are
- * specified, until {@code jaxb.properties} file is looked up in its package, by using the associated classloader &mdash;
- * this is {@link Class#getClassLoader() the owner class loader} for a {@link Class} argument, and for a package
- * the specified {@link ClassLoader}.
- *
- * <p>
- * If such a resource is discovered, it is {@link Properties#load(InputStream) loaded} as a property file, and
- * the value of the {@link #JAXB_CONTEXT_FACTORY} key will be assumed to be the provider factory class. If no value
- * found, {@code "jakarta.xml.bind.context.factory"} is used as a key for backwards compatibility reasons. This class is
- * then loaded by the associated class loader discussed above.
- *
- * <p>
- * This phase of the look up allows some packages to force the use of a certain Jakarta XML Binding implementation.
- * (For example, perhaps the schema compiler has generated some vendor extension in the code.)
- *
- * <p>
- * This configuration method is deprecated.
- *
- * <li>
  * If the system property {@link #JAXB_CONTEXT_FACTORY} exists, then its value is assumed to be the provider
- * factory class. If no such property exists, properties {@code "jakarta.xml.bind.context.factory"} and
- * {@code "jakarta.xml.bind.JAXBContext"} are checked too (in this order), for backwards compatibility reasons. This phase
- * of the look up enables per-JVM override of the Jakarta XML Binding implementation.
+ * factory class. This phase of the look up enables per-JVM override of the Jakarta XML Binding implementation.
  *
  * <li>
  * Provider of {@link jakarta.xml.bind.JAXBContextFactory} is loaded using the service-provider loading
@@ -228,57 +191,15 @@
  * configuration error} a {@link jakarta.xml.bind.JAXBException} will be thrown.
  *
  * <li>
- * Look for resource {@code /META-INF/services/jakarta.xml.bind.JAXBContext} using provided class loader.
- * Methods without class loader parameter use {@code Thread.currentThread().getContextClassLoader()}.
- * If such a resource exists, its content is assumed to be the provider factory class.
- *
- * This configuration method is deprecated.
- *
- * <li>
  * Finally, if all the steps above fail, then the rest of the look up is unspecified. That said,
  * the recommended behavior is to simply look for some hard-coded platform default Jakarta XML Binding implementation.
- * This phase of the look up is so that Java SE can have its own JAXB implementation as the last resort.
+ * This phase of the look up is so that the environment can have its own Jakarta XML Binding implementation as the last resort.
  * </ol>
  *
  * <p>
  * Once the provider factory class is discovered, context creation is delegated to one of its
  * {@code createContext(...)} methods.
  *
- * For backward compatibility reasons, there are two ways how to implement provider factory class:
- * <ol>
- *     <li>the class is implementation of {@link jakarta.xml.bind.JAXBContextFactory}. It must also implement no-arg
- *     constructor. If discovered in other step then 3, new instance using no-arg constructor is created first.
- *     After that, appropriate instance method is invoked on this instance.
- *     <li>the class is not implementation of interface above and then it is mandated to implement the following
- *     static method signatures:
- * <pre>
- *
- * public static JAXBContext createContext(
- *                                      String contextPath,
- *                                      ClassLoader classLoader,
- *                                      Map&lt;String,Object&gt; properties ) throws JAXBException
- *
- * public static JAXBContext createContext(
- *                                      Class[] classes,
- *                                      Map&lt;String,Object&gt; properties ) throws JAXBException
- * </pre>
- *      In this scenario, appropriate static method is used instead of instance method. This approach is incompatible
- *      with {@link java.util.ServiceLoader} so it can't be used with step 3.
- * </ol>
- * <p>
- * There is no difference in behavior of given method {@code createContext(...)} regardless of whether it uses approach
- * 1 (JAXBContextFactory) or 2 (no interface, static methods).
- *
- * @apiNote
- * Service discovery method using resource {@code /META-INF/services/jakarta.xml.bind.JAXBContext} (described in step 4)
- * is supported only to allow backwards compatibility, it is strongly recommended to migrate to standard
- * {@link java.util.ServiceLoader} mechanism (described in step 3). The difference here is the resource name, which
- * doesn't match service's type name.
- * <p>
- * Also using providers implementing interface {@link JAXBContextFactory} is preferred over using ones defining
- * static methods, same as {@link JAXBContext#JAXB_CONTEXT_FACTORY} property is preferred over property
- * {@code "jakarta.xml.bind.context.factory"}
- *
  * @implNote
  * Within the last step, if Glassfish AS environment detected, its specific service loader is used to find factory class.
  *
@@ -381,16 +302,6 @@
      * </ul>
      *
      * <p>
-     * To maintain compatibility with JAXB 1.0 schema to java
-     * interface/implementation binding, enabled by schema customization
-     * {@code <jaxb:globalBindings valueClass="false">},
-     * the Jakarta XML Binding provider will ensure that each package on the context path
-     * has a {@code jaxb.properties} file which contains a value for the
-     * {@code jakarta.xml.bind.context.factory} property and that all values
-     * resolve to the same provider.  This requirement does not apply to
-     * Jakarta XML Binding annotated classes.
-     *
-     * <p>
      * If there are any global XML element name collisions across the various
      * packages listed on the {@code contextPath}, a {@code JAXBException}
      * will be thrown.
diff --git a/spec/src/main/asciidoc/appI-changelog.adoc b/spec/src/main/asciidoc/appI-changelog.adoc
index b6f941b..0245fe9 100644
--- a/spec/src/main/asciidoc/appI-changelog.adoc
+++ b/spec/src/main/asciidoc/appI-changelog.adoc
@@ -8,8 +8,12 @@
 === Changes in Version 4
 
 * fixed cross-references in the specification document
-* removed deprecated jakarta.xml.bind.Validator
+* removed deprecated `jakarta.xml.bind.Validator`
 * removed constraints on using `java.beans.Introspector`
+* removed deprecated steps in implementation lookup algorithm - dropped search
+through `jaxb.properties` file, `jakarta.xml.bind.context.factory` and
+`jakarta.xml.bind.JAXBContext` properties and `/META-INF/services/jakarta.xml.bind.JAXBContext`
+resource file
 
 === Changes in Version 3
 
diff --git a/spec/src/main/asciidoc/ch04-binding_framework.adoc b/spec/src/main/asciidoc/ch04-binding_framework.adoc
index 2b1d522..65e15b0 100644
--- a/spec/src/main/asciidoc/ch04-binding_framework.adoc
+++ b/spec/src/main/asciidoc/ch04-binding_framework.adoc
@@ -792,34 +792,15 @@
 Implementation discovery consists of following steps in the order
 specified (first successful resolution applies):
 
-. Context path or classes’ packages explicitly passed in
-to the newInstance method are searched for the jaxb.properties file. +
- +
-If such a resource is discovered, it is loaded as a property file,
-and the value of the `jakarta.xml.bind.JAXBContextFactory` key
-will be assumed to be the provider factory class.
-If no value found, `jakarta.xml.bind.context.factory` is used
-as a key for backwards compatibility reasons. +
- +
-This configuration method is deprecated.
-
 . If the system property `jakarta.xml.bind.JAXBContextFactory` exists,
-then its value is assumed to be the provider factory class.
-If no such property exists, properties `jakarta.xml.bind.context.factory`
-and `jakarta.xml.bind.JAXBContext` are checked too (in this order),
-for backwards compatibility reasons.
+then its value is assumed to be the provider factory class. This phase
+of the look up enables per-JVM override of the Jakarta XML Binding implementation.
 
 . Provider of `jakarta.xml.bind.JAXBContextFactory` is loaded
 using the service-provider loading facilities, as defined by
 Java SE Platform, to attempt to locate and load
 an implementation of the service.
 
-. Look for resource `/META-INF/services/jakarta.xml.bind.JAXBContext`.
-If such a resource exists, its content is assumed to be the provider
-factory class. +
- +
- This configuration method is deprecated.
- 
  . Finally, if all of the steps above fail,
  then the rest of the look up is unspecified.