History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/com/sun/naming/internal/ResourceManager.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/naming/internal/ResourceManager.java+608−0
@@ -0,0 +1,608 @@
1+/*
2+ * Copyright (c) 1999, 2001, 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 java.io.InputStream;
29+import java.io.IOException;
30+import java.net.URL;
31+import java.lang.ref.WeakReference;
32+import java.lang.reflect.Method;
33+import java.lang.reflect.InvocationTargetException;
34+import java.util.Enumeration;
35+import java.util.HashMap;
36+import java.util.Hashtable;
37+import java.util.Map;
38+import java.util.Properties;
39+import java.util.StringTokenizer;
40+import java.util.List;
41+import java.util.ArrayList;
42+import java.util.WeakHashMap;
43+
44+import javax.naming.*;
45+
46+/**
47+ * The ResourceManager class facilitates the reading of JNDI resource files.
48+ *
49+ * @author Rosanna Lee
50+ * @author Scott Seligman
51+ */
52+
53+public final class ResourceManager {
54+
55+ /*
56+ * Name of provider resource files (without the package-name prefix.)
57+ */
58+ private static final String PROVIDER_RESOURCE_FILE_NAME =
59+ "jndiprovider.properties";
60+
61+ /*
62+ * Name of application resource files.
63+ */
64+ private static final String APP_RESOURCE_FILE_NAME = "jndi.properties";
65+
66+ /*
67+ * Name of properties file in <java.home>/lib.
68+ */
69+ private static final String JRELIB_PROPERTY_FILE_NAME = "jndi.properties";
70+
71+ /*
72+ * The standard JNDI properties that specify colon-separated lists.
73+ */
74+ private static final String[] listProperties = {
75+ Context.OBJECT_FACTORIES,
76+ Context.URL_PKG_PREFIXES,
77+ Context.STATE_FACTORIES,
78+ // The following shouldn't create a runtime dependence on ldap package.
79+ javax.naming.ldap.LdapContext.CONTROL_FACTORIES
80+ };
81+
82+ private static final VersionHelper helper =
83+ VersionHelper.getVersionHelper();
84+
85+ /*
86+ * A cache of the properties that have been constructed by
87+ * the ResourceManager. A Hashtable from a provider resource
88+ * file is keyed on a class in the resource file's package.
89+ * One from application resource files is keyed on the thread's
90+ * context class loader.
91+ */
92+ private static final WeakHashMap propertiesCache = new WeakHashMap(11);
93+
94+ /*
95+ * A cache of factory objects (ObjectFactory, StateFactory, ControlFactory).
96+ *
97+ * A two-level cache keyed first on context class loader and then
98+ * on propValue. Value is a list of class or factory objects,
99+ * weakly referenced so as not to prevent GC of the class loader.
100+ * Used in getFactories().
101+ */
102+ private static final WeakHashMap factoryCache = new WeakHashMap(11);
103+
104+ /*
105+ * A cache of URL factory objects (ObjectFactory).
106+ *
107+ * A two-level cache keyed first on context class loader and then
108+ * on classSuffix+propValue. Value is the factory itself (weakly
109+ * referenced so as not to prevent GC of the class loader) or
110+ * NO_FACTORY if a previous search revealed no factory. Used in
111+ * getFactory().
112+ */
113+ private static final WeakHashMap urlFactoryCache = new WeakHashMap(11);
114+ private static final WeakReference NO_FACTORY = new WeakReference(null);
115+
116+ /**
117+ * A class to allow JNDI properties be specified as applet parameters
118+ * without creating a static dependency on java.applet.
119+ */
120+ private static class AppletParameter {
121+ private static final Class<?> clazz = getClass("java.applet.Applet");
122+ private static final Method getMethod =
123+ getMethod(clazz, "getParameter", String.class);
124+ private static Class<?> getClass(String name) {
125+ try {
126+ return Class.forName(name, true, null);
127+ } catch (ClassNotFoundException e) {
128+ return null;
129+ }
130+ }
131+ private static Method getMethod(Class<?> clazz,
132+ String name,
133+ Class<?>... paramTypes)
134+ {
135+ if (clazz != null) {
136+ try {
137+ return clazz.getMethod(name, paramTypes);
138+ } catch (NoSuchMethodException e) {
139+ throw new AssertionError(e);
140+ }
141+ } else {
142+ return null;
143+ }
144+ }
145+
146+ /**
147+ * Returns the value of the applet's named parameter.
148+ */
149+ static Object get(Object applet, String name) {
150+ // if clazz is null then applet cannot be an Applet.
151+ if (clazz == null || !clazz.isInstance(applet))
152+ throw new ClassCastException(applet.getClass().getName());
153+ try {
154+ return getMethod.invoke(applet, name);
155+ } catch (InvocationTargetException e) {
156+ throw new AssertionError(e);
157+ } catch (IllegalAccessException iae) {
158+ throw new AssertionError(iae);
159+ }
160+ }
161+ }
162+
163+ // There should be no instances of this class.
164+ private ResourceManager() {
165+ }
166+
167+
168+ // ---------- Public methods ----------
169+
170+ /*
171+ * Given the environment parameter passed to the initial context
172+ * constructor, returns the full environment for that initial
173+ * context (never null). This is based on the environment
174+ * parameter, the applet parameters (where appropriate), the
175+ * system properties, and all application resource files.
176+ *
177+ * <p> This method will modify <tt>env</tt> and save
178+ * a reference to it. The caller may no longer modify it.
179+ *
180+ * @param env environment passed to initial context constructor.
181+ * Null indicates an empty environment.
182+ *
183+ * @throws NamingException if an error occurs while reading a
184+ * resource file
185+ */
186+ public static Hashtable getInitialEnvironment(Hashtable env)
187+ throws NamingException
188+ {
189+ String[] props = VersionHelper.PROPS; // system/applet properties
190+ if (env == null) {
191+ env = new Hashtable(11);
192+ }
193+ Object applet = env.get(Context.APPLET);
194+
195+ // Merge property values from env param, applet params, and system
196+ // properties. The first value wins: there's no concatenation of
197+ // colon-separated lists.
198+ // Read system properties by first trying System.getProperties(),
199+ // and then trying System.getProperty() if that fails. The former
200+ // is more efficient due to fewer permission checks.
201+ //
202+ String[] jndiSysProps = helper.getJndiProperties();
203+ for (int i = 0; i < props.length; i++) {
204+ Object val = env.get(props[i]);
205+ if (val == null) {
206+ if (applet != null) {
207+ val = AppletParameter.get(applet, props[i]);
208+ }
209+ if (val == null) {
210+ // Read system property.
211+ val = (jndiSysProps != null)
212+ ? jndiSysProps[i]
213+ : helper.getJndiProperty(i);
214+ }
215+ if (val != null) {
216+ env.put(props[i], val);
217+ }
218+ }
219+ }
220+
221+ // Merge the above with the values read from all application
222+ // resource files. Colon-separated lists are concatenated.
223+ mergeTables(env, getApplicationResources());
224+ return env;
225+ }
226+
227+ /**
228+ * Retrieves the property from the environment, or from the provider
229+ * resource file associated with the given context. The environment
230+ * may in turn contain values that come from applet parameters,
231+ * system properties, or application resource files.
232+ *
233+ * If <tt>concat</tt> is true and both the environment and the provider
234+ * resource file contain the property, the two values are concatenated
235+ * (with a ':' separator).
236+ *
237+ * Returns null if no value is found.
238+ *
239+ * @param propName The non-null property name
240+ * @param env The possibly null environment properties
241+ * @param ctx The possibly null context
242+ * @param concat True if multiple values should be concatenated
243+ * @return the property value, or null is there is none.
244+ * @throws NamingException if an error occurs while reading the provider
245+ * resource file.
246+ */
247+ public static String getProperty(String propName, Hashtable env,
248+ Context ctx, boolean concat)
249+ throws NamingException {
250+
251+ String val1 = (env != null) ? (String)env.get(propName) : null;
252+ if ((ctx == null) ||
253+ ((val1 != null) && !concat)) {
254+ return val1;
255+ }
256+ String val2 = (String)getProviderResource(ctx).get(propName);
257+ if (val1 == null) {
258+ return val2;
259+ } else if ((val2 == null) || !concat) {
260+ return val1;
261+ } else {
262+ return (val1 + ":" + val2);
263+ }
264+ }
265+
266+ /**
267+ * Retrieves an enumeration of factory classes/object specified by a
268+ * property.
269+ *
270+ * The property is gotten from the environment and the provider
271+ * resource file associated with the given context and concantenated.
272+ * See getProperty(). The resulting property value is a list of class names.
273+ *<p>
274+ * This method then loads each class using the current thread's context
275+ * class loader and keeps them in a list. Any class that cannot be loaded
276+ * is ignored. The resulting list is then cached in a two-level
277+ * hash table, keyed first by the context class loader and then by
278+ * the property's value.
279+ * The next time threads of the same context class loader call this
280+ * method, they can use the cached list.
281+ *<p>
282+ * After obtaining the list either from the cache or by creating one from
283+ * the property value, this method then creates and returns a
284+ * FactoryEnumeration using the list. As the FactoryEnumeration is
285+ * traversed, the cached Class object in the list is instantiated and
286+ * replaced by an instance of the factory object itself. Both class
287+ * objects and factories are wrapped in weak references so as not to
288+ * prevent GC of the class loader.
289+ *<p>
290+ * Note that multiple threads can be accessing the same cached list
291+ * via FactoryEnumeration, which locks the list during each next().
292+ * The size of the list will not change,
293+ * but a cached Class object might be replaced by an instantiated factory
294+ * object.
295+ *
296+ * @param propName The non-null property name
297+ * @param env The possibly null environment properties
298+ * @param ctx The possibly null context
299+ * @return An enumeration of factory classes/objects; null if none.
300+ * @exception NamingException If encounter problem while reading the provider
301+ * property file.
302+ * @see javax.naming.spi.NamingManager#getObjectInstance
303+ * @see javax.naming.spi.NamingManager#getStateToBind
304+ * @see javax.naming.spi.DirectoryManager#getObjectInstance
305+ * @see javax.naming.spi.DirectoryManager#getStateToBind
306+ * @see javax.naming.ldap.ControlFactory#getControlInstance
307+ */
308+ public static FactoryEnumeration getFactories(String propName, Hashtable env,
309+ Context ctx) throws NamingException {
310+
311+ String facProp = getProperty(propName, env, ctx, true);
312+ if (facProp == null)
313+ return null; // no classes specified; return null
314+
315+ // Cache is based on context class loader and property val
316+ ClassLoader loader = helper.getContextClassLoader();
317+
318+ Map perLoaderCache = null;
319+ synchronized (factoryCache) {
320+ perLoaderCache = (Map) factoryCache.get(loader);
321+ if (perLoaderCache == null) {
322+ perLoaderCache = new HashMap(11);
323+ factoryCache.put(loader, perLoaderCache);
324+ }
325+ }
326+
327+ synchronized (perLoaderCache) {
328+ List factories = (List) perLoaderCache.get(facProp);
329+ if (factories != null) {
330+ // Cached list
331+ return factories.size() == 0 ? null
332+ : new FactoryEnumeration(factories, loader);
333+ } else {
334+ // Populate list with classes named in facProp; skipping
335+ // those that we cannot load
336+ StringTokenizer parser = new StringTokenizer(facProp, ":");
337+ factories = new ArrayList(5);
338+ while (parser.hasMoreTokens()) {
339+ try {
340+ // System.out.println("loading");
341+ String className = parser.nextToken();
342+ Class c = helper.loadClass(className, loader);
343+ factories.add(new NamedWeakReference(c, className));
344+ } catch (Exception e) {
345+ // ignore ClassNotFoundException, IllegalArgumentException
346+ }
347+ }
348+ // System.out.println("adding to cache: " + factories);
349+ perLoaderCache.put(facProp, factories);
350+ return new FactoryEnumeration(factories, loader);
351+ }
352+ }
353+ }
354+
355+ /**
356+ * Retrieves a factory from a list of packages specified in a
357+ * property.
358+ *
359+ * The property is gotten from the environment and the provider
360+ * resource file associated with the given context and concatenated.
361+ * classSuffix is added to the end of this list.
362+ * See getProperty(). The resulting property value is a list of package
363+ * prefixes.
364+ *<p>
365+ * This method then constructs a list of class names by concatenating
366+ * each package prefix with classSuffix and attempts to load and
367+ * instantiate the class until one succeeds.
368+ * Any class that cannot be loaded is ignored.
369+ * The resulting object is then cached in a two-level hash table,
370+ * keyed first by the context class loader and then by the property's
371+ * value and classSuffix.
372+ * The next time threads of the same context class loader call this
373+ * method, they use the cached factory.
374+ * If no factory can be loaded, NO_FACTORY is recorded in the table
375+ * so that next time it'll return quickly.
376+ *
377+ * @param propName The non-null property name
378+ * @param env The possibly null environment properties
379+ * @param ctx The possibly null context
380+ * @param classSuffix The non-null class name
381+ * (e.g. ".ldap.ldapURLContextFactory).
382+ * @param defaultPkgPrefix The non-null default package prefix.
383+ * (e.g., "com.sun.jndi.url").
384+ * @return An factory object; null if none.
385+ * @exception NamingException If encounter problem while reading the provider
386+ * property file, or problem instantiating the factory.
387+ *
388+ * @see javax.naming.spi.NamingManager#getURLContext
389+ * @see javax.naming.spi.NamingManager#getURLObject
390+ */
391+ public static Object getFactory(String propName, Hashtable env, Context ctx,
392+ String classSuffix, String defaultPkgPrefix) throws NamingException {
393+
394+ // Merge property with provider property and supplied default
395+ String facProp = getProperty(propName, env, ctx, true);
396+ if (facProp != null)
397+ facProp += (":" + defaultPkgPrefix);
398+ else
399+ facProp = defaultPkgPrefix;
400+
401+ // Cache factory based on context class loader, class name, and
402+ // property val
403+ ClassLoader loader = helper.getContextClassLoader();
404+ String key = classSuffix + " " + facProp;
405+
406+ Map perLoaderCache = null;
407+ synchronized (urlFactoryCache) {
408+ perLoaderCache = (Map) urlFactoryCache.get(loader);
409+ if (perLoaderCache == null) {
410+ perLoaderCache = new HashMap(11);
411+ urlFactoryCache.put(loader, perLoaderCache);
412+ }
413+ }
414+
415+ synchronized (perLoaderCache) {
416+ Object factory = null;
417+
418+ WeakReference factoryRef = (WeakReference) perLoaderCache.get(key);
419+ if (factoryRef == NO_FACTORY) {
420+ return null;
421+ } else if (factoryRef != null) {
422+ factory = factoryRef.get();
423+ if (factory != null) { // check if weak ref has been cleared
424+ return factory;
425+ }
426+ }
427+
428+ // Not cached; find first factory and cache
429+ StringTokenizer parser = new StringTokenizer(facProp, ":");
430+ String className;
431+ while (factory == null && parser.hasMoreTokens()) {
432+ className = parser.nextToken() + classSuffix;
433+ try {
434+ // System.out.println("loading " + className);
435+ factory = helper.loadClass(className, loader).newInstance();
436+ } catch (InstantiationException e) {
437+ NamingException ne =
438+ new NamingException("Cannot instantiate " + className);
439+ ne.setRootCause(e);
440+ throw ne;
441+ } catch (IllegalAccessException e) {
442+ NamingException ne =
443+ new NamingException("Cannot access " + className);
444+ ne.setRootCause(e);
445+ throw ne;
446+ } catch (Exception e) {
447+ // ignore ClassNotFoundException, IllegalArgumentException,
448+ // etc.
449+ }
450+ }
451+
452+ // Cache it.
453+ perLoaderCache.put(key, (factory != null)
454+ ? new WeakReference(factory)
455+ : NO_FACTORY);
456+ return factory;
457+ }
458+ }
459+
460+
461+ // ---------- Private methods ----------
462+
463+ /*
464+ * Returns the properties contained in the provider resource file
465+ * of an object's package. Returns an empty hash table if the
466+ * object is null or the resource file cannot be found. The
467+ * results are cached.
468+ *
469+ * @throws NamingException if an error occurs while reading the file.
470+ */
471+ private static Hashtable getProviderResource(Object obj)
472+ throws NamingException
473+ {
474+ if (obj == null) {
475+ return (new Hashtable(1));
476+ }
477+ synchronized (propertiesCache) {
478+ Class c = obj.getClass();
479+
480+ Hashtable props = (Hashtable)propertiesCache.get(c);
481+ if (props != null) {
482+ return props;
483+ }
484+ props = new Properties();
485+
486+ InputStream istream =
487+ helper.getResourceAsStream(c, PROVIDER_RESOURCE_FILE_NAME);
488+
489+ if (istream != null) {
490+ try {
491+ ((Properties)props).load(istream);
492+ } catch (IOException e) {
493+ NamingException ne = new ConfigurationException(
494+ "Error reading provider resource file for " + c);
495+ ne.setRootCause(e);
496+ throw ne;
497+ }
498+ }
499+ propertiesCache.put(c, props);
500+ return props;
501+ }
502+ }
503+
504+
505+ /*
506+ * Returns the Hashtable (never null) that results from merging
507+ * all application resource files available to this thread's
508+ * context class loader. The properties file in <java.home>/lib
509+ * is also merged in. The results are cached.
510+ *
511+ * SECURITY NOTES:
512+ * 1. JNDI needs permission to read the application resource files.
513+ * 2. Any class will be able to use JNDI to view the contents of
514+ * the application resource files in its own classpath. Give
515+ * careful consideration to this before storing sensitive
516+ * information there.
517+ *
518+ * @throws NamingException if an error occurs while reading a resource
519+ * file.
520+ */
521+ private static Hashtable getApplicationResources() throws NamingException {
522+
523+ ClassLoader cl = helper.getContextClassLoader();
524+
525+ synchronized (propertiesCache) {
526+ Hashtable result = (Hashtable)propertiesCache.get(cl);
527+ if (result != null) {
528+ return result;
529+ }
530+
531+ try {
532+ NamingEnumeration resources =
533+ helper.getResources(cl, APP_RESOURCE_FILE_NAME);
534+ while (resources.hasMore()) {
535+ Properties props = new Properties();
536+ props.load((InputStream)resources.next());
537+
538+ if (result == null) {
539+ result = props;
540+ } else {
541+ mergeTables(result, props);
542+ }
543+ }
544+
545+ // Merge in properties from file in <java.home>/lib.
546+ InputStream istream =
547+ helper.getJavaHomeLibStream(JRELIB_PROPERTY_FILE_NAME);
548+ if (istream != null) {
549+ Properties props = new Properties();
550+ props.load(istream);
551+
552+ if (result == null) {
553+ result = props;
554+ } else {
555+ mergeTables(result, props);
556+ }
557+ }
558+
559+ } catch (IOException e) {
560+ NamingException ne = new ConfigurationException(
561+ "Error reading application resource file");
562+ ne.setRootCause(e);
563+ throw ne;
564+ }
565+ if (result == null) {
566+ result = new Hashtable(11);
567+ }
568+ propertiesCache.put(cl, result);
569+ return result;
570+ }
571+ }
572+
573+ /*
574+ * Merge the properties from one hash table into another. Each
575+ * property in props2 that is not in props1 is added to props1.
576+ * For each property in both hash tables that is one of the
577+ * standard JNDI properties that specify colon-separated lists,
578+ * the values are concatenated and stored in props1.
579+ */
580+ private static void mergeTables(Hashtable props1, Hashtable props2) {
581+ Enumeration keys = props2.keys();
582+
583+ while (keys.hasMoreElements()) {
584+ String prop = (String)keys.nextElement();
585+ Object val1 = props1.get(prop);
586+ if (val1 == null) {
587+ props1.put(prop, props2.get(prop));
588+ } else if (isListProperty(prop)) {
589+ String val2 = (String)props2.get(prop);
590+ props1.put(prop, ((String)val1) + ":" + val2);
591+ }
592+ }
593+ }
594+
595+ /*
596+ * Is a property one of the standard JNDI properties that specify
597+ * colon-separated lists?
598+ */
599+ private static boolean isListProperty(String prop) {
600+ prop = prop.intern();
601+ for (int i = 0; i < listProperties.length; i++) {
602+ if (prop == listProperties[i]) {
603+ return true;
604+ }
605+ }
606+ return false;
607+ }
608+}