1 /* 2 * Copyright (c) 1999, 2014, 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 com.sun.naming.internal; 27 28 import javax.naming.NamingEnumeration; 29 import java.io.File; 30 import java.io.FileInputStream; 31 import java.io.IOException; 32 import java.io.InputStream; 33 import java.net.MalformedURLException; 34 import java.net.URL; 35 import java.net.URLClassLoader; 36 import java.security.AccessController; 37 import java.security.PrivilegedAction; 38 import java.security.PrivilegedActionException; 39 import java.security.PrivilegedExceptionAction; 40 import java.util.*; 41 42 /** 43 * VersionHelper was used by JNDI to accommodate differences between 44 * JDK 1.1.x and the Java 2 platform. As this is no longer necessary 45 * since JNDI's inclusion in the platform, this class currently 46 * serves as a set of utilities for performing system-level things, 47 * such as class-loading and reading system properties. 48 * 49 * @author Rosanna Lee 50 * @author Scott Seligman 51 */ 52 53 public final class VersionHelper { 54 private static final VersionHelper helper = new VersionHelper(); 55 56 final static String[] PROPS = new String[]{ 57 javax.naming.Context.INITIAL_CONTEXT_FACTORY, 58 javax.naming.Context.OBJECT_FACTORIES, 59 javax.naming.Context.URL_PKG_PREFIXES, 60 javax.naming.Context.STATE_FACTORIES, 61 javax.naming.Context.PROVIDER_URL, 62 javax.naming.Context.DNS_URL, 63 // The following shouldn't create a runtime dependence on ldap package. 64 javax.naming.ldap.LdapContext.CONTROL_FACTORIES 65 }; 66 67 public final static int INITIAL_CONTEXT_FACTORY = 0; 68 public final static int OBJECT_FACTORIES = 1; 69 public final static int URL_PKG_PREFIXES = 2; 70 public final static int STATE_FACTORIES = 3; 71 public final static int PROVIDER_URL = 4; 72 public final static int DNS_URL = 5; 73 public final static int CONTROL_FACTORIES = 6; 74 75 private VersionHelper() {} // Disallow anyone from creating one of these. 76 77 public static VersionHelper getVersionHelper() { 78 return helper; 79 } 80 81 public Class<?> loadClass(String className) throws ClassNotFoundException { 82 return loadClass(className, getContextClassLoader()); 83 } 84 85 /** 86 * @param className A non-null fully qualified class name. 87 * @param codebase A non-null, space-separated list of URL strings. 88 */ 89 public Class<?> loadClass(String className, String codebase) 90 throws ClassNotFoundException, MalformedURLException { 91 92 ClassLoader parent = getContextClassLoader(); 93 ClassLoader cl = 94 URLClassLoader.newInstance(getUrlArray(codebase), parent); 95 96 return loadClass(className, cl); 97 } 98 99 /** 100 * Package private. 101 * <p> 102 * This internal method is used with Thread Context Class Loader (TCCL), 103 * please don't expose this method as public. 104 */ 105 Class<?> loadClass(String className, ClassLoader cl) 106 throws ClassNotFoundException { 107 Class<?> cls = Class.forName(className, true, cl); 108 return cls; 109 } 110 111 /* 112 * Returns a JNDI property from the system properties. Returns 113 * null if the property is not set, or if there is no permission 114 * to read it. 115 */ 116 String getJndiProperty(int i) { 117 PrivilegedAction<String> act = () -> { 118 try { 119 return System.getProperty(PROPS[i]); 120 } catch (SecurityException e) { 121 return null; 122 } 123 }; 124 return AccessController.doPrivileged(act); 125 } 126 127 /* 128 * Reads each property in PROPS from the system properties, and 129 * returns their values -- in order -- in an array. For each 130 * unset property, the corresponding array element is set to null. 131 * Returns null if there is no permission to call System.getProperties(). 132 */ 133 String[] getJndiProperties() { 134 PrivilegedAction<Properties> act = () -> { 135 try { 136 return System.getProperties(); 137 } catch (SecurityException e) { 138 return null; 139 } 140 }; 141 Properties sysProps = AccessController.doPrivileged(act); 142 if (sysProps == null) { 143 return null; 144 } 145 String[] jProps = new String[PROPS.length]; 146 for (int i = 0; i < PROPS.length; i++) { 147 jProps[i] = sysProps.getProperty(PROPS[i]); 148 } 149 return jProps; 150 } 151 152 /* 153 * Returns the resource of a given name associated with a particular 154 * class (never null), or null if none can be found. 155 */ 156 InputStream getResourceAsStream(Class<?> c, String name) { 157 PrivilegedAction<InputStream> act = () -> c.getResourceAsStream(name); 158 return AccessController.doPrivileged(act); 159 } 160 161 /* 162 * Returns an input stream for a file in <java.home>/lib, 163 * or null if it cannot be located or opened. 164 * 165 * @param filename The file name, sans directory. 166 */ 167 InputStream getJavaHomeLibStream(String filename) { 168 PrivilegedAction<InputStream> act = () -> { 169 try { 170 String javahome = System.getProperty("java.home"); 171 if (javahome == null) { 172 return null; 173 } 174 String pathname = javahome + File.separator + 175 "lib" + File.separator + filename; 176 return new FileInputStream(pathname); 177 } catch (Exception e) { 178 return null; 179 } 180 }; 181 return AccessController.doPrivileged(act); 182 } 183 184 /* 185 * Returns an enumeration (never null) of InputStreams of the 186 * resources of a given name associated with a particular class 187 * loader. Null represents the bootstrap class loader in some 188 * Java implementations. 189 */ 190 NamingEnumeration<InputStream> getResources(ClassLoader cl, 191 String name) throws IOException { 192 Enumeration<URL> urls; 193 PrivilegedExceptionAction<Enumeration<URL>> act = () -> 194 (cl == null) 195 ? ClassLoader.getSystemResources(name) 196 : cl.getResources(name); 197 try { 198 urls = AccessController.doPrivileged(act); 199 } catch (PrivilegedActionException e) { 200 throw (IOException) e.getException(); 201 } 202 return new InputStreamEnumeration(urls); 203 } 204 205 206 /** 207 * Package private. 208 * <p> 209 * This internal method returns Thread Context Class Loader (TCCL), 210 * if null, returns the system Class Loader. 211 * <p> 212 * Please don't expose this method as public. 213 * @throws SecurityException if the class loader is not accessible 214 */ 215 ClassLoader getContextClassLoader() { 216 217 PrivilegedAction<ClassLoader> act = () -> { 218 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 219 if (loader == null) { 220 // Don't use bootstrap class loader directly! 221 loader = ClassLoader.getSystemClassLoader(); 222 } 223 return loader; 224 }; 225 return AccessController.doPrivileged(act); 226 } 227 228 private static URL[] getUrlArray(String codebase) 229 throws MalformedURLException { 230 // Parse codebase into separate URLs 231 StringTokenizer parser = new StringTokenizer(codebase); 232 List<String> list = new ArrayList<>(); 233 while (parser.hasMoreTokens()) { 234 list.add(parser.nextToken()); 235 } 236 String[] url = new String[list.size()]; 237 for (int i = 0; i < url.length; i++) { 238 url[i] = list.get(i); 239 } 240 241 URL[] urlArray = new URL[url.length]; 242 for (int i = 0; i < urlArray.length; i++) { 243 urlArray[i] = new URL(url[i]); 244 } 245 return urlArray; 246 } 247 248 /** 249 * Given an enumeration of URLs, an instance of this class represents 250 * an enumeration of their InputStreams. Each operation on the URL 251 * enumeration is performed within a doPrivileged block. 252 * This is used to enumerate the resources under a foreign codebase. 253 * This class is not MT-safe. 254 */ 255 private class InputStreamEnumeration implements 256 NamingEnumeration<InputStream> { 257 258 private final Enumeration<URL> urls; 259 260 private InputStream nextElement; 261 262 InputStreamEnumeration(Enumeration<URL> urls) { 263 this.urls = urls; 264 } 265 266 /* 267 * Returns the next InputStream, or null if there are no more. 268 * An InputStream that cannot be opened is skipped. 269 */ 270 private InputStream getNextElement() { 271 PrivilegedAction<InputStream> act = () -> { 272 while (urls.hasMoreElements()) { 273 try { 274 return urls.nextElement().openStream(); 275 } catch (IOException e) { 276 // skip this URL 277 } 278 } 279 return null; 280 }; 281 return AccessController.doPrivileged(act); 282 } 283 284 public boolean hasMore() { 285 if (nextElement != null) { 286 return true; 287 } 288 nextElement = getNextElement(); 289 return (nextElement != null); 290 } 291 292 public boolean hasMoreElements() { 293 return hasMore(); 294 } 295 296 public InputStream next() { 297 if (hasMore()) { 298 InputStream res = nextElement; 299 nextElement = null; 300 return res; 301 } else { 302 throw new NoSuchElementException(); 303 } 304 } 305 306 public InputStream nextElement() { 307 return next(); 308 } 309 310 public void close() { 311 } 312 } 313 }