All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.discovery.tools.ManagedProperties Maven / Gradle / Ivy

Go to download

Its an port to fix bugs in OSGi support. ... The Apache Commons Discovery 0.5 component is about discovering, or finding, implementations for pluggable interfaces.

There is a newer version: 7.4.0
Show newest version
/*
 * 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.Collections;
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.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 

This class may disappear in the future, or be moved to another project.. *

* *

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. *

* *

This class is one solution. *

* *

Manage properties according to a secure * scheme similar to that used by classloaders: *

    *
  • ClassLoaders are organized in a tree hierarchy.
  • *
  • each ClassLoader has a reference * to a parent ClassLoader.
  • *
  • the root of the tree is the bootstrap ClassLoaderer.
  • *
  • the youngest decendent is the thread context class loader.
  • *
  • properties are bound to a ClassLoader instance *
      *
    • non-default properties bound to a parent ClassLoader * instance take precedence over all properties of the same name bound * to any decendent. * Just to confuse the issue, this is the default case.
    • *
    • default properties bound to a parent ClassLoader * instance may be overriden by (default or non-default) properties of * the same name bound to any decendent. *
    • *
    *
  • *
  • System properties take precedence over all other properties
  • *
*

* *

This is not a perfect solution, as it is possible that * different ClassLoaders load different instances of * ScopedProperties. The 'higher' this class is loaded * within the ClassLoader hierarchy, the more usefull * it will be. *

*/ public class ManagedProperties { private static Log log = LogFactory.getLog(ManagedProperties.class); /** * Sets the {@code Log} for this class. * * @param _log This class {@code Log} * @deprecated This method is not thread-safe */ @Deprecated public static void setLog(Log _log) { log = _log; } /** * Cache of Properties, keyed by (thread-context) class loaders. * Use HashMap because it allows 'null' keys, which * allows us to account for the (null) bootstrap classloader. */ private static final Map> 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 The classloader used to load resources. * @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 The classloader used to load resources. * @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(); Map properties = 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 Properties 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 Properties 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) { /** * Each entry must be mapped to a Property. * 'setProperty' does this for us. */ for (Map.Entry entry : newProperties.entrySet()) { 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. * * @return The list of all property names */ public static Enumeration propertyNames() { Map allProps = new Hashtable(); ClassLoader classLoader = getThreadContextClassLoader(); /** * Order doesn't matter, we are only going to use * the set of all keys... */ while (true) { Map properties = null; synchronized (propertiesCache) { properties = propertiesCache.get(classLoader); } if (properties != null) { allProps.putAll(properties); } if (classLoader == null) { break; } classLoader = getParent(classLoader); } return Collections.enumeration(allProps.keySet()); } /** * 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 java.util.Properties 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 = names.nextElement(); p.put(name, getProperty(name)); } return p; } /***************** INTERNAL IMPLEMENTATION *****************/ private static class Value { final String value; final boolean isDefault; /** * Creates a new Value instance with string value and * the flag to mark is default value or not. * * @param value String representation of this value * @param isDefault The default flag */ 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. * * * @param classLoader The class loader as key * @param propertyName The property name to lookup * @return The Value associated to the input class loader and property name */ 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) { Map properties = propertiesCache.get(classLoader); if (properties != null) { Value altValue = 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; } /** * Returns the thread context class loader. * * @return The thread context class loader */ private static final ClassLoader getThreadContextClassLoader() { return JDKHooks.getJDKHooks().getThreadContextClassLoader(); } /** * Return the parent class loader of the given class loader. * * @param classLoader The class loader from wich the parent has to be extracted * @return The parent class loader of the given class loader */ private static final ClassLoader getParent(final ClassLoader classLoader) { return AccessController.doPrivileged(new PrivilegedAction() { public ClassLoader run() { try { return classLoader.getParent(); } catch (SecurityException se){ return null; } } }); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy