FileDocCategorySizeDatePackage
ResourceManager.javaAPI DocJava SE 5 API18382Fri Aug 26 14:55:16 BST 2005com.sun.naming.internal

ResourceManager

public final class ResourceManager extends Object
The ResourceManager class facilitates the reading of JNDI resource files.
author
Rosanna Lee
author
Scott Seligman
version
1.13 03/12/19

Fields Summary
private static final String
PROVIDER_RESOURCE_FILE_NAME
private static final String
APP_RESOURCE_FILE_NAME
private static final String
JRELIB_PROPERTY_FILE_NAME
private static final String[]
listProperties
private static final VersionHelper
helper
private static final WeakHashMap
propertiesCache
private static final WeakHashMap
factoryCache
private static final WeakHashMap
urlFactoryCache
private static final WeakReference
NO_FACTORY
Constructors Summary
private ResourceManager()



    // There should be no instances of this class.
      
    
Methods Summary
private static java.util.HashtablegetApplicationResources()


	ClassLoader cl = helper.getContextClassLoader();

	synchronized (propertiesCache) {
	    Hashtable result = (Hashtable)propertiesCache.get(cl);
	    if (result != null) {
		return result;
	    }

	    try {
		NamingEnumeration resources =
		    helper.getResources(cl, APP_RESOURCE_FILE_NAME);
		while (resources.hasMore()) {
		    Properties props = new Properties();
		    props.load((InputStream)resources.next());

		    if (result == null) {
			result = props;
		    } else {
			mergeTables(result, props);
		    }
		}

		// Merge in properties from file in <java.home>/lib.
		InputStream istream =
		    helper.getJavaHomeLibStream(JRELIB_PROPERTY_FILE_NAME);
		if (istream != null) {
		    Properties props = new Properties();
		    props.load(istream);

		    if (result == null) {
			result = props;
		    } else {
			mergeTables(result, props);
		    }
		}
		
	    } catch (IOException e) {
		NamingException ne = new ConfigurationException(
			"Error reading application resource file");
		ne.setRootCause(e);
		throw ne;
	    }
	    if (result == null) {
		result = new Hashtable(11);
	    }
	    propertiesCache.put(cl, result);
	    return result;
	}
    
public static com.sun.naming.internal.FactoryEnumerationgetFactories(java.lang.String propName, java.util.Hashtable env, javax.naming.Context ctx)
Retrieves an enumeration of factory classes/object specified by a property. The property is gotten from the environment and the provider resource file associated with the given context and concantenated. See getProperty(). The resulting property value is a list of class names.

This method then loads each class using the current thread's context class loader and keeps them in a list. Any class that cannot be loaded is ignored. The resulting list is then cached in a two-level hash table, keyed first by the context class loader and then by the property's value. The next time threads of the same context class loader call this method, they can use the cached list.

After obtaining the list either from the cache or by creating one from the property value, this method then creates and returns a FactoryEnumeration using the list. As the FactoryEnumeration is traversed, the cached Class object in the list is instantiated and replaced by an instance of the factory object itself. Both class objects and factories are wrapped in weak references so as not to prevent GC of the class loader.

Note that multiple threads can be accessing the same cached list via FactoryEnumeration, which locks the list during each next(). The size of the list will not change, but a cached Class object might be replaced by an instantiated factory object.

param
propName The non-null property name
param
env The possibly null environment properties
param
ctx The possibly null context
return
An enumeration of factory classes/objects; null if none.
exception
NamingException If encounter problem while reading the provider property file.
see
javax.naming.spi.NamingManager#getObjectInstance
see
javax.naming.spi.NamingManager#getStateToBind
see
javax.naming.spi.DirectoryManager#getObjectInstance
see
javax.naming.spi.DirectoryManager#getStateToBind
see
javax.naming.ldap.ControlFactory#getControlInstance


	String facProp = getProperty(propName, env, ctx, true);
	if (facProp == null)
	    return null;  // no classes specified; return null

	// Cache is based on context class loader and property val
	ClassLoader loader = helper.getContextClassLoader();

	Map perLoaderCache = null;
	synchronized (factoryCache) {
	    perLoaderCache = (Map) factoryCache.get(loader);
	    if (perLoaderCache == null) {
		perLoaderCache = new HashMap(11);
		factoryCache.put(loader, perLoaderCache);
	    }
	}

	synchronized (perLoaderCache) {
	    List factories = (List) perLoaderCache.get(facProp);
	    if (factories != null) {
		// Cached list
		return factories.size() == 0 ? null 
		    : new FactoryEnumeration(factories, loader);
	    } else {
		// Populate list with classes named in facProp; skipping
		// those that we cannot load
		StringTokenizer parser = new StringTokenizer(facProp, ":");
		factories = new ArrayList(5);
		while (parser.hasMoreTokens()) {
		    try {
			// System.out.println("loading");
			String className = parser.nextToken();
			Class c = helper.loadClass(className, loader);
			factories.add(new NamedWeakReference(c, className));
		    } catch (Exception e) {
			// ignore ClassNotFoundException, IllegalArgumentException
		    }
		}
		// System.out.println("adding to cache: " + factories);
		perLoaderCache.put(facProp, factories);
		return new FactoryEnumeration(factories, loader);
	    }
	}
    
public static java.lang.ObjectgetFactory(java.lang.String propName, java.util.Hashtable env, javax.naming.Context ctx, java.lang.String classSuffix, java.lang.String defaultPkgPrefix)
Retrieves a factory from a list of packages specified in a property. The property is gotten from the environment and the provider resource file associated with the given context and concatenated. classSuffix is added to the end of this list. See getProperty(). The resulting property value is a list of package prefixes.

This method then constructs a list of class names by concatenating each package prefix with classSuffix and attempts to load and instantiate the class until one succeeds. Any class that cannot be loaded is ignored. The resulting object is then cached in a two-level hash table, keyed first by the context class loader and then by the property's value and classSuffix. The next time threads of the same context class loader call this method, they use the cached factory. If no factory can be loaded, NO_FACTORY is recorded in the table so that next time it'll return quickly.

param
propName The non-null property name
param
env The possibly null environment properties
param
ctx The possibly null context
param
classSuffix The non-null class name (e.g. ".ldap.ldapURLContextFactory).
param
defaultPkgPrefix The non-null default package prefix. (e.g., "com.sun.jndi.url").
return
An factory object; null if none.
exception
NamingException If encounter problem while reading the provider property file, or problem instantiating the factory.
see
javax.naming.spi.NamingManager#getURLContext
see
javax.naming.spi.NamingManager#getURLObject


	// Merge property with provider property and supplied default
	String facProp = getProperty(propName, env, ctx, true);
	if (facProp != null)
	    facProp += (":" + defaultPkgPrefix);
	else
	    facProp = defaultPkgPrefix;

	// Cache factory based on context class loader, class name, and
	// property val
	ClassLoader loader = helper.getContextClassLoader();
	String key = classSuffix + " " + facProp;

	Map perLoaderCache = null;
	synchronized (urlFactoryCache) {
	    perLoaderCache = (Map) urlFactoryCache.get(loader);
	    if (perLoaderCache == null) {
		perLoaderCache = new HashMap(11);
		urlFactoryCache.put(loader, perLoaderCache);
	    }
	}

	synchronized (perLoaderCache) {
	    Object factory = null;

	    WeakReference factoryRef = (WeakReference) perLoaderCache.get(key);
	    if (factoryRef == NO_FACTORY) {
		return null;
	    } else if (factoryRef != null) {
		factory = factoryRef.get();
		if (factory != null) {	// check if weak ref has been cleared
		    return factory;
		}
	    }

	    // Not cached; find first factory and cache
	    StringTokenizer parser = new StringTokenizer(facProp, ":");
	    String className;
	    while (factory == null && parser.hasMoreTokens()) {
		className = parser.nextToken() + classSuffix;
		try {
		    // System.out.println("loading " + className);
		    factory = helper.loadClass(className, loader).newInstance();
		} catch (InstantiationException e) {
		    NamingException ne = 
			new NamingException("Cannot instantiate " + className);
		    ne.setRootCause(e);
		    throw ne;
		} catch (IllegalAccessException e) {
		    NamingException ne = 
			new NamingException("Cannot access " + className);
		    ne.setRootCause(e);
		    throw ne;
		} catch (Exception e) {
		    // ignore ClassNotFoundException, IllegalArgumentException,
		    // etc.
		}
	    }

	    // Cache it.
	    perLoaderCache.put(key, (factory != null)
					? new WeakReference(factory)
					: NO_FACTORY);
	    return factory;
	}
    
public static java.util.HashtablegetInitialEnvironment(java.util.Hashtable env)

	String[] props = VersionHelper.PROPS;	// system/applet properties
	if (env == null) {
	    env = new Hashtable(11);
	}
	Applet applet = (Applet)env.get(Context.APPLET);

	// Merge property values from env param, applet params, and system
	// properties.  The first value wins:  there's no concatenation of
	// colon-separated lists.
	// Read system properties by first trying System.getProperties(),
	// and then trying System.getProperty() if that fails.  The former
	// is more efficient due to fewer permission checks.
	//
	String[] jndiSysProps = helper.getJndiProperties();
	for (int i = 0; i < props.length; i++) {
	    Object val = env.get(props[i]);
	    if (val == null) {
		if (applet != null) {
		    val = applet.getParameter(props[i]);
		}
		if (val == null) {
		    // Read system property.
		    val = (jndiSysProps != null)
			? jndiSysProps[i]
			: helper.getJndiProperty(i);
		}
		if (val != null) {
		    env.put(props[i], val);
		}
	    }
	}

	// Merge the above with the values read from all application
	// resource files.  Colon-separated lists are concatenated.
	mergeTables(env, getApplicationResources());
	return env;
    
public static java.lang.StringgetProperty(java.lang.String propName, java.util.Hashtable env, javax.naming.Context ctx, boolean concat)
Retrieves the property from the environment, or from the provider resource file associated with the given context. The environment may in turn contain values that come from applet parameters, system properties, or application resource files. If concat is true and both the environment and the provider resource file contain the property, the two values are concatenated (with a ':' separator). Returns null if no value is found.

param
propName The non-null property name
param
env The possibly null environment properties
param
ctx The possibly null context
param
concat True if multiple values should be concatenated
return
the property value, or null is there is none.
throws
NamingException if an error occurs while reading the provider resource file.


	String val1 = (env != null) ? (String)env.get(propName) : null;
	if ((ctx == null) ||
	    ((val1 != null) && !concat)) {
	    return val1;
	}
	String val2 = (String)getProviderResource(ctx).get(propName);
	if (val1 == null) {
	    return val2;
	} else if ((val2 == null) || !concat) {
	    return val1;
	} else {
	    return (val1 + ":" + val2);
	}
    
private static java.util.HashtablegetProviderResource(java.lang.Object obj)

	if (obj == null) {
	    return (new Hashtable(1));
	}
	synchronized (propertiesCache) {
	    Class c = obj.getClass();

	    Hashtable props = (Hashtable)propertiesCache.get(c);
	    if (props != null) {
		return props;
	    }
	    props = new Properties();

	    InputStream istream =
		helper.getResourceAsStream(c, PROVIDER_RESOURCE_FILE_NAME);

	    if (istream != null) {
		try {
		    ((Properties)props).load(istream);
		} catch (IOException e) {
		    NamingException ne = new ConfigurationException(
			    "Error reading provider resource file for " + c);
		    ne.setRootCause(e);
		    throw ne;
		}
	    }
	    propertiesCache.put(c, props);
	    return props;
	}
    
private static booleanisListProperty(java.lang.String prop)

	prop = prop.intern();
	for (int i = 0; i < listProperties.length; i++) {
	    if (prop == listProperties[i]) {
		return true;
	    }
	}
	return false;
    
private static voidmergeTables(java.util.Hashtable props1, java.util.Hashtable props2)

	Enumeration keys = props2.keys();

	while (keys.hasMoreElements()) {
	    String prop = (String)keys.nextElement();
	    Object val1 = props1.get(prop);
	    if (val1 == null) {
		props1.put(prop, props2.get(prop));
	    } else if (isListProperty(prop)) {
		String val2 = (String)props2.get(prop);
		props1.put(prop, ((String)val1) + ":" + val2);
	    }
	}