1 /* 2 * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.naming.spi; 27 28 import java.net.MalformedURLException; 29 import java.util.*; 30 31 32 import javax.naming.*; 33 import com.sun.naming.internal.VersionHelper; 34 import com.sun.naming.internal.ResourceManager; 35 import com.sun.naming.internal.FactoryEnumeration; 36 37 /** 38 * This class contains methods for creating context objects 39 * and objects referred to by location information in the naming 40 * or directory service. 41 *<p> 42 * This class cannot be instantiated. It has only static methods. 43 *<p> 44 * The mention of URL in the documentation for this class refers to 45 * a URL string as defined by RFC 1738 and its related RFCs. It is 46 * any string that conforms to the syntax described therein, and 47 * may not always have corresponding support in the java.net.URL 48 * class or Web browsers. 49 *<p> 50 * NamingManager is safe for concurrent access by multiple threads. 51 *<p> 52 * Except as otherwise noted, 53 * a {@code Name} or environment parameter 54 * passed to any method is owned by the caller. 55 * The implementation will not modify the object or keep a reference 62 63 public class NamingManager { 64 65 /* 66 * Disallow anyone from creating one of these. 67 * Made package private so that DirectoryManager can subclass. 68 */ 69 70 NamingManager() {} 71 72 // should be protected and package private 73 static final VersionHelper helper = VersionHelper.getVersionHelper(); 74 75 // --------- object factory stuff 76 77 /** 78 * Package-private; used by DirectoryManager and NamingManager. 79 */ 80 private static ObjectFactoryBuilder object_factory_builder = null; 81 82 /** 83 * The ObjectFactoryBuilder determines the policy used when 84 * trying to load object factories. 85 * See getObjectInstance() and class ObjectFactory for a description 86 * of the default policy. 87 * setObjectFactoryBuilder() overrides this default policy by installing 88 * an ObjectFactoryBuilder. Subsequent object factories will 89 * be loaded and created using the installed builder. 90 *<p> 91 * The builder can only be installed if the executing thread is allowed 92 * (by the security manager's checkSetFactory() method) to do so. 93 * Once installed, the builder cannot be replaced. 94 * 95 * @param builder The factory builder to install. If null, no builder 96 * is installed. 97 * @exception SecurityException builder cannot be installed 98 * for security reasons. 99 * @exception NamingException builder cannot be installed for 100 * a non-security-related reason. 101 * @exception IllegalStateException If a factory has already been installed. 655 * be in a package which is exported by that module to the 656 * {@code java.naming} module.)</li> 657 * </ul> 658 * </li> 659 * </ul> 660 * @param env The possibly null environment properties used when 661 * creating the context. 662 * @return A non-null initial context. 663 * @exception NoInitialContextException If the 664 * {@code Context.INITIAL_CONTEXT_FACTORY} property 665 * is not found or names a nonexistent 666 * class or a class that cannot be instantiated, 667 * or if the initial context could not be created for some other 668 * reason. 669 * @exception NamingException If some other naming exception was encountered. 670 * @see javax.naming.InitialContext 671 * @see javax.naming.directory.InitialDirContext 672 */ 673 public static Context getInitialContext(Hashtable<?,?> env) 674 throws NamingException { 675 InitialContextFactory factory = null; 676 677 InitialContextFactoryBuilder builder = getInitialContextFactoryBuilder(); 678 if (builder == null) { 679 // No builder installed, use property 680 // Get initial context factory class name 681 682 String className = env != null ? 683 (String)env.get(Context.INITIAL_CONTEXT_FACTORY) : null; 684 if (className == null) { 685 NoInitialContextException ne = new NoInitialContextException( 686 "Need to specify class name in environment or system " + 687 "property, or in an application resource file: " + 688 Context.INITIAL_CONTEXT_FACTORY); 689 throw ne; 690 } 691 692 ServiceLoader<InitialContextFactory> loader = 693 ServiceLoader.load(InitialContextFactory.class); 694 695 Iterator<InitialContextFactory> iterator = loader.iterator(); 696 try { 697 while (iterator.hasNext()) { 698 InitialContextFactory f = iterator.next(); 699 if (f.getClass().getName().equals(className)) { 700 factory = f; 701 break; 702 } 703 } 704 } catch (ServiceConfigurationError e) { 705 NoInitialContextException ne = 706 new NoInitialContextException( 707 "Cannot load initial context factory " 708 + "'" + className + "'"); 709 ne.setRootCause(e); 710 throw ne; 711 } 712 713 if (factory == null) { 714 try { 715 @SuppressWarnings("deprecation") 716 Object o = helper.loadClass(className).newInstance(); 717 factory = (InitialContextFactory) o; 718 } catch (Exception e) { 719 NoInitialContextException ne = 720 new NoInitialContextException( 721 "Cannot instantiate class: " + className); 722 ne.setRootCause(e); 723 throw ne; 724 } 725 } 726 } else { 727 factory = builder.createInitialContextFactory(env); 728 } 729 730 return factory.getInitialContext(env); 731 } 732 733 734 /** 735 * Sets the InitialContextFactory builder to be builder. 736 * 737 *<p> 738 * The builder can only be installed if the executing thread is allowed by 739 * the security manager to do so. Once installed, the builder cannot 740 * be replaced. 741 * @param builder The initial context factory builder to install. If null, 742 * no builder is set. 743 * @exception SecurityException builder cannot be installed for security 744 * reasons. 745 * @exception NamingException builder cannot be installed for 746 * a non-security-related reason. 747 * @exception IllegalStateException If a builder was previous installed. 748 * @see #hasInitialContextFactoryBuilder 749 * @see java.lang.SecurityManager#checkSetFactory 750 */ 903 Hashtable<?,?> environment) 904 throws NamingException 905 { 906 907 FactoryEnumeration factories = ResourceManager.getFactories( 908 Context.STATE_FACTORIES, environment, nameCtx); 909 910 if (factories == null) { 911 return obj; 912 } 913 914 // Try each factory until one succeeds 915 StateFactory factory; 916 Object answer = null; 917 while (answer == null && factories.hasMore()) { 918 factory = (StateFactory)factories.next(); 919 answer = factory.getStateToBind(obj, name, nameCtx, environment); 920 } 921 922 return (answer != null) ? answer : obj; 923 } 924 } | 1 /* 2 * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.naming.spi; 27 28 import java.net.MalformedURLException; 29 import java.security.AccessController; 30 import java.security.PrivilegedAction; 31 import java.util.*; 32 33 import javax.naming.*; 34 import com.sun.naming.internal.VersionHelper; 35 import com.sun.naming.internal.ResourceManager; 36 import com.sun.naming.internal.FactoryEnumeration; 37 import jdk.internal.loader.ClassLoaderValue; 38 39 /** 40 * This class contains methods for creating context objects 41 * and objects referred to by location information in the naming 42 * or directory service. 43 *<p> 44 * This class cannot be instantiated. It has only static methods. 45 *<p> 46 * The mention of URL in the documentation for this class refers to 47 * a URL string as defined by RFC 1738 and its related RFCs. It is 48 * any string that conforms to the syntax described therein, and 49 * may not always have corresponding support in the java.net.URL 50 * class or Web browsers. 51 *<p> 52 * NamingManager is safe for concurrent access by multiple threads. 53 *<p> 54 * Except as otherwise noted, 55 * a {@code Name} or environment parameter 56 * passed to any method is owned by the caller. 57 * The implementation will not modify the object or keep a reference 64 65 public class NamingManager { 66 67 /* 68 * Disallow anyone from creating one of these. 69 * Made package private so that DirectoryManager can subclass. 70 */ 71 72 NamingManager() {} 73 74 // should be protected and package private 75 static final VersionHelper helper = VersionHelper.getVersionHelper(); 76 77 // --------- object factory stuff 78 79 /** 80 * Package-private; used by DirectoryManager and NamingManager. 81 */ 82 private static ObjectFactoryBuilder object_factory_builder = null; 83 84 private static final ClassLoaderValue<InitialContextFactory> FACTORIES_CACHE = 85 new ClassLoaderValue<>(); 86 87 /** 88 * The ObjectFactoryBuilder determines the policy used when 89 * trying to load object factories. 90 * See getObjectInstance() and class ObjectFactory for a description 91 * of the default policy. 92 * setObjectFactoryBuilder() overrides this default policy by installing 93 * an ObjectFactoryBuilder. Subsequent object factories will 94 * be loaded and created using the installed builder. 95 *<p> 96 * The builder can only be installed if the executing thread is allowed 97 * (by the security manager's checkSetFactory() method) to do so. 98 * Once installed, the builder cannot be replaced. 99 * 100 * @param builder The factory builder to install. If null, no builder 101 * is installed. 102 * @exception SecurityException builder cannot be installed 103 * for security reasons. 104 * @exception NamingException builder cannot be installed for 105 * a non-security-related reason. 106 * @exception IllegalStateException If a factory has already been installed. 660 * be in a package which is exported by that module to the 661 * {@code java.naming} module.)</li> 662 * </ul> 663 * </li> 664 * </ul> 665 * @param env The possibly null environment properties used when 666 * creating the context. 667 * @return A non-null initial context. 668 * @exception NoInitialContextException If the 669 * {@code Context.INITIAL_CONTEXT_FACTORY} property 670 * is not found or names a nonexistent 671 * class or a class that cannot be instantiated, 672 * or if the initial context could not be created for some other 673 * reason. 674 * @exception NamingException If some other naming exception was encountered. 675 * @see javax.naming.InitialContext 676 * @see javax.naming.directory.InitialDirContext 677 */ 678 public static Context getInitialContext(Hashtable<?,?> env) 679 throws NamingException { 680 ClassLoader loader; 681 InitialContextFactory factory = null; 682 683 InitialContextFactoryBuilder builder = getInitialContextFactoryBuilder(); 684 if (builder == null) { 685 // No builder installed, use property 686 // Get initial context factory class name 687 688 String className = env != null ? 689 (String)env.get(Context.INITIAL_CONTEXT_FACTORY) : null; 690 if (className == null) { 691 NoInitialContextException ne = new NoInitialContextException( 692 "Need to specify class name in environment or system " + 693 "property, or in an application resource file: " + 694 Context.INITIAL_CONTEXT_FACTORY); 695 throw ne; 696 } 697 698 if (System.getSecurityManager() == null) { 699 loader = Thread.currentThread().getContextClassLoader(); 700 if (loader == null) loader = ClassLoader.getSystemClassLoader(); 701 } else { 702 PrivilegedAction<ClassLoader> pa = () -> { 703 ClassLoader cl = Thread.currentThread().getContextClassLoader(); 704 return (cl == null) ? ClassLoader.getSystemClassLoader() : cl; 705 }; 706 loader = AccessController.doPrivileged(pa); 707 } 708 709 var key = FACTORIES_CACHE.sub(className); 710 try { 711 factory = key.computeIfAbsent(loader, (ld, ky) -> getFactory(ky.key())); 712 } catch (FactoryInitializationError e) { 713 throw e.getCause(); 714 } 715 } else { 716 factory = builder.createInitialContextFactory(env); 717 } 718 719 return factory.getInitialContext(env); 720 } 721 722 private static InitialContextFactory getFactory(String className) { 723 InitialContextFactory factory; 724 try { 725 ServiceLoader<InitialContextFactory> loader = 726 ServiceLoader.load(InitialContextFactory.class); 727 728 factory = loader 729 .stream() 730 .filter(p -> p.type().getName().equals(className)) 731 .findFirst() 732 .map(ServiceLoader.Provider::get) 733 .orElse(null); 734 } catch (ServiceConfigurationError e) { 735 NoInitialContextException ne = 736 new NoInitialContextException( 737 "Cannot load initial context factory " 738 + "'" + className + "'"); 739 ne.setRootCause(e); 740 throw new FactoryInitializationError(ne); 741 } 742 743 if (factory == null) { 744 try { 745 @SuppressWarnings("deprecation") 746 Object o = helper.loadClass(className).newInstance(); 747 factory = (InitialContextFactory) o; 748 } catch (Exception e) { 749 NoInitialContextException ne = 750 new NoInitialContextException( 751 "Cannot instantiate class: " + className); 752 ne.setRootCause(e); 753 throw new FactoryInitializationError(ne); 754 } 755 } 756 return factory; 757 } 758 759 760 /** 761 * Sets the InitialContextFactory builder to be builder. 762 * 763 *<p> 764 * The builder can only be installed if the executing thread is allowed by 765 * the security manager to do so. Once installed, the builder cannot 766 * be replaced. 767 * @param builder The initial context factory builder to install. If null, 768 * no builder is set. 769 * @exception SecurityException builder cannot be installed for security 770 * reasons. 771 * @exception NamingException builder cannot be installed for 772 * a non-security-related reason. 773 * @exception IllegalStateException If a builder was previous installed. 774 * @see #hasInitialContextFactoryBuilder 775 * @see java.lang.SecurityManager#checkSetFactory 776 */ 929 Hashtable<?,?> environment) 930 throws NamingException 931 { 932 933 FactoryEnumeration factories = ResourceManager.getFactories( 934 Context.STATE_FACTORIES, environment, nameCtx); 935 936 if (factories == null) { 937 return obj; 938 } 939 940 // Try each factory until one succeeds 941 StateFactory factory; 942 Object answer = null; 943 while (answer == null && factories.hasMore()) { 944 factory = (StateFactory)factories.next(); 945 answer = factory.getStateToBind(obj, name, nameCtx, environment); 946 } 947 948 return (answer != null) ? answer : obj; 949 } 950 951 private static class FactoryInitializationError extends Error { 952 @java.io.Serial 953 static final long serialVersionUID = -5805552256848841560L; 954 955 private FactoryInitializationError(NoInitialContextException cause) { 956 super(cause); 957 } 958 959 @Override 960 public NoInitialContextException getCause() { 961 return (NoInitialContextException) super.getCause(); 962 } 963 } 964 } |