< prev index next >

src/java.naming/share/classes/javax/naming/spi/NamingManager.java

Print this page
rev 56188 : 8223260: NamingManager should cache InitialContextFactory
Reviewed-by: alanb, plevart, dfuchs

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this

@@ -24,17 +24,19 @@
  */
 
 package javax.naming.spi;
 
 import java.net.MalformedURLException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.*;
 
-
 import javax.naming.*;
 import com.sun.naming.internal.VersionHelper;
 import com.sun.naming.internal.ResourceManager;
 import com.sun.naming.internal.FactoryEnumeration;
+import jdk.internal.loader.ClassLoaderValue;
 
 /**
  * This class contains methods for creating context objects
  * and objects referred to by location information in the naming
  * or directory service.

@@ -77,10 +79,13 @@
     /**
      * Package-private; used by DirectoryManager and NamingManager.
      */
     private static ObjectFactoryBuilder object_factory_builder = null;
 
+    private static final ClassLoaderValue<InitialContextFactory> FACTORIES_CACHE =
+            new ClassLoaderValue<>();
+
     /**
      * The ObjectFactoryBuilder determines the policy used when
      * trying to load object factories.
      * See getObjectInstance() and class ObjectFactory for a description
      * of the default policy.

@@ -670,10 +675,11 @@
      * @see javax.naming.InitialContext
      * @see javax.naming.directory.InitialDirContext
      */
     public static Context getInitialContext(Hashtable<?,?> env)
         throws NamingException {
+        ClassLoader loader;
         InitialContextFactory factory = null;
 
         InitialContextFactoryBuilder builder = getInitialContextFactoryBuilder();
         if (builder == null) {
             // No builder installed, use property

@@ -687,29 +693,53 @@
                     "property, or in an application resource file: " +
                     Context.INITIAL_CONTEXT_FACTORY);
                 throw ne;
             }
 
-            ServiceLoader<InitialContextFactory> loader =
-                    ServiceLoader.load(InitialContextFactory.class);
+            if (System.getSecurityManager() == null) {
+                loader = Thread.currentThread().getContextClassLoader();
+                if (loader == null) loader = ClassLoader.getSystemClassLoader();
+            } else {
+                PrivilegedAction<ClassLoader> pa = () -> {
+                    ClassLoader cl = Thread.currentThread().getContextClassLoader();
+                    return (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
+                };
+                loader = AccessController.doPrivileged(pa);
+            }
 
-            Iterator<InitialContextFactory> iterator = loader.iterator();
+            var key = FACTORIES_CACHE.sub(className);
             try {
-                while (iterator.hasNext()) {
-                    InitialContextFactory f = iterator.next();
-                    if (f.getClass().getName().equals(className)) {
-                        factory = f;
-                        break;
+                factory = key.computeIfAbsent(loader, (ld, ky) -> getFactory(ky.key()));
+            } catch (FactoryInitializationError e) {
+                throw e.getCause();
                     }
+        } else {
+            factory = builder.createInitialContextFactory(env);
                 }
+
+        return factory.getInitialContext(env);
+    }
+
+    private static InitialContextFactory getFactory(String className) {
+        InitialContextFactory factory;
+        try {
+            ServiceLoader<InitialContextFactory> loader =
+                    ServiceLoader.load(InitialContextFactory.class);
+
+            factory = loader
+                    .stream()
+                    .filter(p -> p.type().getName().equals(className))
+                    .findFirst()
+                    .map(ServiceLoader.Provider::get)
+                    .orElse(null);
             } catch (ServiceConfigurationError e) {
                 NoInitialContextException ne =
                         new NoInitialContextException(
                                 "Cannot load initial context factory "
                                         + "'" + className + "'");
                 ne.setRootCause(e);
-                throw ne;
+            throw new FactoryInitializationError(ne);
             }
 
             if (factory == null) {
                 try {
                     @SuppressWarnings("deprecation")

@@ -718,18 +748,14 @@
                 } catch (Exception e) {
                     NoInitialContextException ne =
                             new NoInitialContextException(
                                     "Cannot instantiate class: " + className);
                     ne.setRootCause(e);
-                    throw ne;
+                throw new FactoryInitializationError(ne);
                 }
             }
-        } else {
-            factory = builder.createInitialContextFactory(env);
-        }
-
-        return factory.getInitialContext(env);
+        return factory;
     }
 
 
     /**
      * Sets the InitialContextFactory builder to be builder.

@@ -919,6 +945,19 @@
             answer = factory.getStateToBind(obj, name, nameCtx, environment);
         }
 
         return (answer != null) ? answer : obj;
     }
+
+    private static class FactoryInitializationError extends Error {
+        static final long serialVersionUID = -5805552256848841560L;
+
+        private FactoryInitializationError(NoInitialContextException cause) {
+            super(cause);
+        }
+
+        @Override
+        public NoInitialContextException getCause() {
+            return (NoInitialContextException) super.getCause();
+        }
+    }
 }
< prev index next >