ManagedProperties.java
| Index Score | ||
|---|---|---|
![]() |
![]() |
org.apache.commons.discovery.tools |
![]() |
![]() |
Commons Discovery |
View: Reasons, Metrics, Source Code
These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.discovery.tools;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.discovery.jdk.JDKHooks;
import org.apache.commons.discovery.log.DiscoveryLogFactory;
import org.apache.commons.logging.Log;
/**
* <p>This class may disappear in the future, or be moved to another project..
* </p>
*
* <p>Extend the concept of System properties to a hierarchical scheme
* based around class loaders. System properties are global in nature,
* so using them easily violates sound architectural and design principles
* for maintaining separation between components and runtime environments.
* Nevertheless, there is a need for properties broader in scope than
* class or class instance scope.
* </p>
*
* <p>This class is one solution.
* </p>
*
* <p>Manage properties according to a secure
* scheme similar to that used by classloaders:
* <ul>
* <li><code>ClassLoader</code>s are organized in a tree hierarchy.</li>
* <li>each <code>ClassLoader</code> has a reference
* to a parent <code>ClassLoader</code>.</li>
* <li>the root of the tree is the bootstrap <code>ClassLoader</code>er.</li>
* <li>the youngest decendent is the thread context class loader.</li>
* <li>properties are bound to a <code>ClassLoader</code> instance
* <ul>
* <li><i>non-default</i> properties bound to a parent <code>ClassLoader</code>
* instance take precedence over all properties of the same name bound
* to any decendent.
* Just to confuse the issue, this is the default case.</li>
* <li><i>default</i> properties bound to a parent <code>ClassLoader</code>
* instance may be overriden by (default or non-default) properties of
* the same name bound to any decendent.
* </li>
* </ul>
* </li>
* <li>System properties take precedence over all other properties</li>
* </ul>
* </p>
*
* <p>This is not a perfect solution, as it is possible that
* different <code>ClassLoader</code>s load different instances of
* <code>ScopedProperties</code>. The 'higher' this class is loaded
* within the <code>ClassLoader</code> hierarchy, the more usefull
* it will be.
* </p>
*
* @author Richard A. Sitze
*/
public class ManagedProperties {
private static Log log = DiscoveryLogFactory.newLog(ManagedProperties.class);
public static void setLog(Log _log) {
log = _log;
}
/**
* Cache of Properties, keyed by (thread-context) class loaders.
* Use <code>HashMap</code> because it allows 'null' keys, which
* allows us to account for the (null) bootstrap classloader.
*/
private static final HashMap propertiesCache = new HashMap();
/**
* Get value for property bound to the current thread context class loader.
*
* @param propertyName property name.
* @return property value if found, otherwise default.
*/
public static String getProperty(String propertyName) {
return getProperty(getThreadContextClassLoader(), propertyName);
}
/**
* Get value for property bound to the current thread context class loader.
* If not found, then return default.
*
* @param propertyName property name.
* @param dephault default value.
* @return property value if found, otherwise default.
*/
public static String getProperty(String propertyName, String dephault) {
return getProperty(getThreadContextClassLoader(), propertyName, dephault);
}
/**
* Get value for property bound to the class loader.
*
* @param classLoader
* @param propertyName property name.
* @return property value if found, otherwise default.
*/
public static String getProperty(ClassLoader classLoader, String propertyName) {
String value = JDKHooks.getJDKHooks().getSystemProperty(propertyName);
if (value == null) {
Value val = getValueProperty(classLoader, propertyName);
if (val != null) {
value = val.value;
}
} else if (log.isDebugEnabled()) {
log.debug("found System property '" + propertyName + "'" +
" with value '" + value + "'.");
}
return value;
}
/**
* Get value for property bound to the class loader.
* If not found, then return default.
*
* @param classLoader
* @param propertyName property name.
* @param dephault default value.
* @return property value if found, otherwise default.
*/
public static String getProperty(ClassLoader classLoader, String propertyName, String dephault) {
String value = getProperty(classLoader, propertyName);
return (value == null) ? dephault : value;
}
/**
* Set value for property bound to the current thread context class loader.
* @param propertyName property name
* @param value property value (non-default) If null, remove the property.
*/
public static void setProperty(String propertyName, String value) {
setProperty(propertyName, value, false);
}
/**
* Set value for property bound to the current thread context class loader.
* @param propertyName property name
* @param value property value. If null, remove the property.
* @param isDefault determines if property is default or not.
* A non-default property cannot be overriden.
* A default property can be overriden by a property
* (default or non-default) of the same name bound to
* a decendent class loader.
*/
public static void setProperty(String propertyName, String value, boolean isDefault) {
if (propertyName != null) {
synchronized (propertiesCache) {
ClassLoader classLoader = getThreadContextClassLoader();
HashMap properties = (HashMap)propertiesCache.get(classLoader);
if (value == null) {
if (properties != null) {
properties.remove(propertyName);
}
} else {
if (properties == null) {
properties = new HashMap();
propertiesCache.put(classLoader, properties);
}
properties.put(propertyName, new Value(value, isDefault));
}
}
}
}
/**
* Set property values for <code>Properties</code> bound to the
* current thread context class loader.
*
* @param newProperties name/value pairs to be bound
*/
public static void setProperties(Map newProperties) {
setProperties(newProperties, false);
}
/**
* Set property values for <code>Properties</code> bound to the
* current thread context class loader.
*
* @param newProperties name/value pairs to be bound
* @param isDefault determines if properties are default or not.
* A non-default property cannot be overriden.
* A default property can be overriden by a property
* (default or non-default) of the same name bound to
* a decendent class loader.
*/
public static void setProperties(Map newProperties, boolean isDefault) {
java.util.Iterator it = newProperties.entrySet().iterator();
/**
* Each entry must be mapped to a Property.
* 'setProperty' does this for us.
*/
while (it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
setProperty( String.valueOf(entry.getKey()),
String.valueOf(entry.getValue()),
isDefault);
}
}
/**
* Return list of all property names. This is an expensive
* operation: ON EACH CALL it walks through all property lists
* associated with the current context class loader upto
* and including the bootstrap class loader.
*/
public static Enumeration propertyNames() {
Hashtable allProps = new Hashtable();
ClassLoader classLoader = getThreadContextClassLoader();
/**
* Order doesn't matter, we are only going to use
* the set of all keys...
*/
while (true) {
HashMap properties = null;
synchronized (propertiesCache) {
properties = (HashMap)propertiesCache.get(classLoader);
}
if (properties != null) {
allProps.putAll(properties);
}
if (classLoader == null) break;
classLoader = getParent(classLoader);
}
return allProps.keys();
}
/**
* This is an expensive operation.
* ON EACH CALL it walks through all property lists
* associated with the current context class loader upto
* and including the bootstrap class loader.
*
* @return Returns a <code>java.util.Properties</code> instance
* that is equivalent to the current state of the scoped
* properties, in that getProperty() will return the same value.
* However, this is a copy, so setProperty on the
* returned value will not effect the scoped properties.
*/
public static Properties getProperties() {
Properties p = new Properties();
Enumeration names = propertyNames();
while (names.hasMoreElements()) {
String name = (String)names.nextElement();
p.put(name, getProperty(name));
}
return p;
}
/***************** INTERNAL IMPLEMENTATION *****************/
private static class Value {
final String value;
final boolean isDefault;
Value(String value, boolean isDefault) {
this.value = value;
this.isDefault = isDefault;
}
}
/**
* Get value for properties bound to the class loader.
* Explore up the tree first, as higher-level class
* loaders take precedence over lower-level class loaders.
*/
private static final Value getValueProperty(ClassLoader classLoader, String propertyName) {
Value value = null;
if (propertyName != null) {
/**
* If classLoader isn't bootstrap loader (==null),
* then get up-tree value.
*/
if (classLoader != null) {
value = getValueProperty(getParent(classLoader), propertyName);
}
if (value == null || value.isDefault) {
synchronized (propertiesCache) {
HashMap properties = (HashMap)propertiesCache.get(classLoader);
if (properties != null) {
Value altValue = (Value)properties.get(propertyName);
// set value only if override exists..
// otherwise pass default (or null) on..
if (altValue != null) {
value = altValue;
if (log.isDebugEnabled()) {
log.debug("found Managed property '" + propertyName + "'" +
" with value '" + value + "'" +
" bound to classloader " + classLoader + ".");
}
}
}
}
}
}
return value;
}
private static final ClassLoader getThreadContextClassLoader() {
return JDKHooks.getJDKHooks().getThreadContextClassLoader();
}
private static final ClassLoader getParent(final ClassLoader classLoader) {
return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
try {
return classLoader.getParent();
} catch (SecurityException se){
return null;
}
}
});
}
}
The table below shows all metrics for ManagedProperties.java.




