Path: blob/master/src/java.naming/share/classes/com/sun/naming/internal/VersionHelper.java
41161 views
/*1* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.naming.internal;2627import javax.naming.NamingEnumeration;28import java.io.IOException;29import java.io.InputStream;30import java.net.MalformedURLException;31import java.net.URL;32import java.net.URLClassLoader;33import java.nio.file.Files;34import java.nio.file.Path;35import java.security.AccessController;36import java.security.PrivilegedAction;37import java.security.PrivilegedActionException;38import java.security.PrivilegedExceptionAction;39import java.util.*;4041/**42* VersionHelper was used by JNDI to accommodate differences between43* JDK 1.1.x and the Java 2 platform. As this is no longer necessary44* since JNDI's inclusion in the platform, this class currently45* serves as a set of utilities for performing system-level things,46* such as class-loading and reading system properties.47*48* @author Rosanna Lee49* @author Scott Seligman50*/5152public final class VersionHelper {53private static final VersionHelper helper = new VersionHelper();5455/**56* Determines whether classes may be loaded from an arbitrary URL code base.57*/58private static final boolean TRUST_URL_CODE_BASE;5960static {61// System property to control whether classes may be loaded from an62// arbitrary URL code base63PrivilegedAction<String> act64= () -> System.getProperty("com.sun.jndi.ldap.object.trustURLCodebase", "false");65@SuppressWarnings("removal")66String trust = AccessController.doPrivileged(act);67TRUST_URL_CODE_BASE = "true".equalsIgnoreCase(trust);68}6970static final String[] PROPS = new String[]{71javax.naming.Context.INITIAL_CONTEXT_FACTORY,72javax.naming.Context.OBJECT_FACTORIES,73javax.naming.Context.URL_PKG_PREFIXES,74javax.naming.Context.STATE_FACTORIES,75javax.naming.Context.PROVIDER_URL,76javax.naming.Context.DNS_URL,77// The following shouldn't create a runtime dependence on ldap package.78javax.naming.ldap.LdapContext.CONTROL_FACTORIES79};8081public static final int INITIAL_CONTEXT_FACTORY = 0;82public static final int OBJECT_FACTORIES = 1;83public static final int URL_PKG_PREFIXES = 2;84public static final int STATE_FACTORIES = 3;85public static final int PROVIDER_URL = 4;86public static final int DNS_URL = 5;87public static final int CONTROL_FACTORIES = 6;8889private VersionHelper() {} // Disallow anyone from creating one of these.9091public static VersionHelper getVersionHelper() {92return helper;93}9495public Class<?> loadClass(String className) throws ClassNotFoundException {96return loadClass(className, getContextClassLoader());97}9899public Class<?> loadClassWithoutInit(String className) throws ClassNotFoundException {100return loadClass(className, false, getContextClassLoader());101}102103/**104* @param className A non-null fully qualified class name.105* @param codebase A non-null, space-separated list of URL strings.106*/107public Class<?> loadClass(String className, String codebase)108throws ClassNotFoundException, MalformedURLException {109if (TRUST_URL_CODE_BASE) {110ClassLoader parent = getContextClassLoader();111ClassLoader cl112= URLClassLoader.newInstance(getUrlArray(codebase), parent);113return loadClass(className, cl);114} else {115return null;116}117}118119/**120* Package private.121* <p>122* This internal method is used with Thread Context Class Loader (TCCL),123* please don't expose this method as public.124*/125Class<?> loadClass(String className, boolean initialize, ClassLoader cl)126throws ClassNotFoundException {127Class<?> cls = Class.forName(className, initialize, cl);128return cls;129}130131Class<?> loadClass(String className, ClassLoader cl)132throws ClassNotFoundException {133return loadClass(className, true, cl);134}135136/*137* Returns a JNDI property from the system properties. Returns138* null if the property is not set, or if there is no permission139* to read it.140*/141@SuppressWarnings("removal")142String getJndiProperty(int i) {143PrivilegedAction<String> act = () -> {144try {145return System.getProperty(PROPS[i]);146} catch (SecurityException e) {147return null;148}149};150return AccessController.doPrivileged(act);151}152153/*154* Reads each property in PROPS from the system properties, and155* returns their values -- in order -- in an array. For each156* unset property, the corresponding array element is set to null.157* Returns null if there is no permission to call System.getProperties().158*/159String[] getJndiProperties() {160PrivilegedAction<Properties> act = () -> {161try {162return System.getProperties();163} catch (SecurityException e) {164return null;165}166};167@SuppressWarnings("removal")168Properties sysProps = AccessController.doPrivileged(act);169if (sysProps == null) {170return null;171}172String[] jProps = new String[PROPS.length];173for (int i = 0; i < PROPS.length; i++) {174jProps[i] = sysProps.getProperty(PROPS[i]);175}176return jProps;177}178179private static String resolveName(Class<?> c, String name) {180if (name == null) {181return name;182}183if (!name.startsWith("/")) {184if (!c.isPrimitive()) {185String baseName = c.getPackageName();186if (!baseName.isEmpty()) {187name = baseName.replace('.', '/') + "/"188+ name;189}190}191} else {192name = name.substring(1);193}194return name;195}196197/*198* Returns the resource of a given name associated with a particular199* class (never null), or null if none can be found.200*/201@SuppressWarnings("removal")202InputStream getResourceAsStream(Class<?> c, String name) {203PrivilegedAction<InputStream> act = () -> {204try {205return c.getModule().getResourceAsStream(resolveName(c, name));206} catch (IOException x) {207return null;208}209};210return AccessController.doPrivileged(act);211}212213/*214* Returns an input stream for a file in <java.home>/conf,215* or null if it cannot be located or opened.216*217* @param filename The file name, sans directory.218*/219@SuppressWarnings("removal")220InputStream getJavaHomeConfStream(String filename) {221PrivilegedAction<InputStream> act = () -> {222try {223String javahome = System.getProperty("java.home");224if (javahome == null) {225return null;226}227return Files.newInputStream(Path.of(javahome, "conf", filename));228} catch (Exception e) {229return null;230}231};232return AccessController.doPrivileged(act);233}234235/*236* Returns an enumeration (never null) of InputStreams of the237* resources of a given name associated with a particular class238* loader. Null represents the bootstrap class loader in some239* Java implementations.240*/241@SuppressWarnings("removal")242NamingEnumeration<InputStream> getResources(ClassLoader cl,243String name) throws IOException {244Enumeration<URL> urls;245PrivilegedExceptionAction<Enumeration<URL>> act = () ->246(cl == null)247? ClassLoader.getSystemResources(name)248: cl.getResources(name);249try {250urls = AccessController.doPrivileged(act);251} catch (PrivilegedActionException e) {252throw (IOException) e.getException();253}254return new InputStreamEnumeration(urls);255}256257258/**259* Package private.260* <p>261* This internal method returns Thread Context Class Loader (TCCL),262* if null, returns the system Class Loader.263* <p>264* Please don't expose this method as public.265* @throws SecurityException if the class loader is not accessible266*/267@SuppressWarnings("removal")268ClassLoader getContextClassLoader() {269270PrivilegedAction<ClassLoader> act = () -> {271ClassLoader loader = Thread.currentThread().getContextClassLoader();272if (loader == null) {273// Don't use bootstrap class loader directly!274loader = ClassLoader.getSystemClassLoader();275}276return loader;277};278return AccessController.doPrivileged(act);279}280281private static URL[] getUrlArray(String codebase)282throws MalformedURLException {283// Parse codebase into separate URLs284StringTokenizer parser = new StringTokenizer(codebase);285List<URL> list = new ArrayList<>();286while (parser.hasMoreTokens()) {287list.add(new URL(parser.nextToken()));288}289return list.toArray(new URL[0]);290}291292/**293* Given an enumeration of URLs, an instance of this class represents294* an enumeration of their InputStreams. Each operation on the URL295* enumeration is performed within a doPrivileged block.296* This is used to enumerate the resources under a foreign codebase.297* This class is not MT-safe.298*/299private class InputStreamEnumeration implements300NamingEnumeration<InputStream> {301302private final Enumeration<URL> urls;303304private InputStream nextElement;305306InputStreamEnumeration(Enumeration<URL> urls) {307this.urls = urls;308}309310/*311* Returns the next InputStream, or null if there are no more.312* An InputStream that cannot be opened is skipped.313*/314@SuppressWarnings("removal")315private InputStream getNextElement() {316PrivilegedAction<InputStream> act = () -> {317while (urls.hasMoreElements()) {318try {319return urls.nextElement().openStream();320} catch (IOException e) {321// skip this URL322}323}324return null;325};326return AccessController.doPrivileged(act);327}328329public boolean hasMore() {330if (nextElement != null) {331return true;332}333nextElement = getNextElement();334return (nextElement != null);335}336337public boolean hasMoreElements() {338return hasMore();339}340341public InputStream next() {342if (hasMore()) {343InputStream res = nextElement;344nextElement = null;345return res;346} else {347throw new NoSuchElementException();348}349}350351public InputStream nextElement() {352return next();353}354355public void close() {356}357}358}359360361