KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > discovery > tools > ManagedProperties


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 2001 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Axis" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation. For more
52  * information on the Apache Software Foundation, please see
53  * <http://www.apache.org/>.
54  */

55
56 package org.apache.commons.discovery.tools;
57
58 import java.security.AccessController JavaDoc;
59 import java.security.PrivilegedAction JavaDoc;
60 import java.util.Enumeration JavaDoc;
61 import java.util.HashMap JavaDoc;
62 import java.util.Hashtable JavaDoc;
63 import java.util.Map JavaDoc;
64 import java.util.Properties JavaDoc;
65
66 import org.apache.commons.discovery.jdk.JDKHooks;
67
68
69
70 /**
71  * <p>This class may disappear in the future, or be moved to another project..
72  * </p>
73  *
74  * <p>Extend the concept of System properties to a hierarchical scheme
75  * based around class loaders. System properties are global in nature,
76  * so using them easily violates sound architectural and design principles
77  * for maintaining separation between components and runtime environments.
78  * Nevertheless, there is a need for properties broader in scope than
79  * class or class instance scope.
80  * </p>
81  *
82  * <p>This class is one solution.
83  * </p>
84  *
85  * <p>Manage properties according to a secure
86  * scheme similar to that used by classloaders:
87  * <ul>
88  * <li><code>ClassLoader</code>s are organized in a tree hierarchy.</li>
89  * <li>each <code>ClassLoader</code> has a reference
90  * to a parent <code>ClassLoader</code>.</li>
91  * <li>the root of the tree is the bootstrap <code>ClassLoader</code>er.</li>
92  * <li>the youngest decendent is the thread context class loader.</li>
93  * <li>properties are bound to a <code>ClassLoader</code> instance
94  * <ul>
95  * <li><i>non-default</i> properties bound to a parent <code>ClassLoader</code>
96  * instance take precedence over all properties of the same name bound
97  * to any decendent.
98  * Just to confuse the issue, this is the default case.</li>
99  * <li><i>default</i> properties bound to a parent <code>ClassLoader</code>
100  * instance may be overriden by (default or non-default) properties of
101  * the same name bound to any decendent.
102  * </li>
103  * </ul>
104  * </li>
105  * <li>System properties take precedence over all other properties</li>
106  * </ul>
107  * </p>
108  *
109  * <p>This is not a perfect solution, as it is possible that
110  * different <code>ClassLoader</code>s load different instances of
111  * <code>ScopedProperties</code>. The 'higher' this class is loaded
112  * within the <code>ClassLoader</code> hierarchy, the more usefull
113  * it will be.
114  * </p>
115  *
116  * @author Richard A. Sitze
117  */

118 public class ManagedProperties {
119     /**
120      * Cache of Properties, keyed by (thread-context) class loaders.
121      * Use <code>HashMap</code> because it allows 'null' keys, which
122      * allows us to account for the (null) bootstrap classloader.
123      */

124     private static final HashMap JavaDoc propertiesCache = new HashMap JavaDoc();
125     
126                                                         
127     /**
128      * Get value for property bound to the current thread context class loader.
129      *
130      * @param property property name.
131      * @return property value if found, otherwise default.
132      */

133     public static String JavaDoc getProperty(String JavaDoc propertyName) {
134         return getProperty(getThreadContextClassLoader(), propertyName);
135     }
136     
137     /**
138      * Get value for property bound to the current thread context class loader.
139      * If not found, then return default.
140      *
141      * @param property property name.
142      * @param dephault default value.
143      * @return property value if found, otherwise default.
144      */

145     public static String JavaDoc getProperty(String JavaDoc propertyName, String JavaDoc dephault) {
146         return getProperty(getThreadContextClassLoader(), propertyName, dephault);
147     }
148     
149     /**
150      * Get value for property bound to the class loader.
151      *
152      * @param classLoader
153      * @param property property name.
154      * @return property value if found, otherwise default.
155      */

156     public static String JavaDoc getProperty(ClassLoader JavaDoc classLoader, String JavaDoc propertyName) {
157         String JavaDoc value = System.getProperty(propertyName);
158         if (value == null) {
159             Value val = getValueProperty(classLoader, propertyName);
160             if (val != null) {
161                 value = val.value;
162             }
163         }
164         return value;
165     }
166     
167     /**
168      * Get value for property bound to the class loader.
169      * If not found, then return default.
170      *
171      * @param classLoader
172      * @param property property name.
173      * @param dephault default value.
174      * @return property value if found, otherwise default.
175      */

176     public static String JavaDoc getProperty(ClassLoader JavaDoc classLoader, String JavaDoc propertyName, String JavaDoc dephault) {
177         String JavaDoc value = getProperty(classLoader, propertyName);
178         return (value == null) ? dephault : value;
179     }
180
181     /**
182      * Set value for property bound to the current thread context class loader.
183      * @param property property name
184      * @param value property value (non-default) If null, remove the property.
185      */

186     public static void setProperty(String JavaDoc propertyName, String JavaDoc value) {
187         setProperty(propertyName, value, false);
188     }
189     
190     /**
191      * Set value for property bound to the current thread context class loader.
192      * @param property property name
193      * @param value property value. If null, remove the property.
194      * @param isDefault determines if property is default or not.
195      * A non-default property cannot be overriden.
196      * A default property can be overriden by a property
197      * (default or non-default) of the same name bound to
198      * a decendent class loader.
199      */

200     public static void setProperty(String JavaDoc propertyName, String JavaDoc value, boolean isDefault) {
201         if (propertyName != null) {
202             synchronized (propertiesCache) {
203                 ClassLoader JavaDoc classLoader = getThreadContextClassLoader();
204                 HashMap JavaDoc properties = (HashMap JavaDoc)propertiesCache.get(classLoader);
205                 
206                 if (value == null) {
207                     properties.remove(propertyName);
208                 } else {
209                     if (properties == null) {
210                         properties = new HashMap JavaDoc();
211                         propertiesCache.put(classLoader, properties);
212                     }
213                 
214                     properties.put(propertyName, new Value(value, isDefault));
215                 }
216             }
217         }
218     }
219     
220     /**
221      * Set property values for <code>Properties</code> bound to the
222      * current thread context class loader.
223      *
224      * @param newProperties name/value pairs to be bound
225      */

226     public static void setProperties(Map JavaDoc newProperties) {
227         setProperties(newProperties, false);
228     }
229     
230     
231     /**
232      * Set property values for <code>Properties</code> bound to the
233      * current thread context class loader.
234      *
235      * @param newProperties name/value pairs to be bound
236      * @param isDefault determines if properties are default or not.
237      * A non-default property cannot be overriden.
238      * A default property can be overriden by a property
239      * (default or non-default) of the same name bound to
240      * a decendent class loader.
241      */

242     public static void setProperties(Map JavaDoc newProperties, boolean isDefault) {
243         java.util.Iterator JavaDoc it = newProperties.entrySet().iterator();
244
245         /**
246          * Each entry must be mapped to a Property.
247          * 'setProperty' does this for us.
248          */

249         while (it.hasNext()) {
250             Map.Entry JavaDoc entry = (Map.Entry JavaDoc)it.next();
251             setProperty( String.valueOf(entry.getKey()),
252                          String.valueOf(entry.getValue()),
253                          isDefault);
254         }
255     }
256
257     
258     /**
259      * Return list of all property names. This is an expensive
260      * operation: ON EACH CALL it walks through all property lists
261      * associated with the current context class loader upto
262      * and including the bootstrap class loader.
263      */

264     public static Enumeration JavaDoc propertyNames() {
265         Hashtable JavaDoc allProps = new Hashtable JavaDoc();
266
267         ClassLoader JavaDoc classLoader = getThreadContextClassLoader();
268
269         /**
270          * Order doesn't matter, we are only going to use
271          * the set of all keys...
272          */

273         while (true) {
274             HashMap JavaDoc properties = null;
275
276             synchronized (propertiesCache) {
277                 properties = (HashMap JavaDoc)propertiesCache.get(classLoader);
278             }
279
280             if (properties != null) {
281                 allProps.putAll(properties);
282             }
283
284             if (classLoader == null) break;
285             
286             classLoader = getParent(classLoader);
287         }
288         
289         return allProps.keys();
290     }
291     
292     /**
293      * This is an expensive operation.
294      * ON EACH CALL it walks through all property lists
295      * associated with the current context class loader upto
296      * and including the bootstrap class loader.
297      *
298      * @return Returns a <code>java.util.Properties</code> instance
299      * that is equivalent to the current state of the scoped
300      * properties, in that getProperty() will return the same value.
301      * However, this is a copy, so setProperty on the
302      * returned value will not effect the scoped properties.
303      */

304     public static Properties JavaDoc getProperties() {
305         Properties JavaDoc p = new Properties JavaDoc();
306         
307         Enumeration JavaDoc names = propertyNames();
308         while (names.hasMoreElements()) {
309             String JavaDoc name = (String JavaDoc)names.nextElement();
310             p.put(name, getProperty(name));
311         }
312         
313         return p;
314     }
315
316
317     /***************** INTERNAL IMPLEMENTATION *****************/
318
319     private static class Value {
320         final String JavaDoc value;
321         final boolean isDefault;
322         
323         Value(String JavaDoc value, boolean isDefault) {
324             this.value = value;
325             this.isDefault = isDefault;
326         }
327     }
328
329     /**
330      * Get value for properties bound to the class loader.
331      * Explore up the tree first, as higher-level class
332      * loaders take precedence over lower-level class loaders.
333      */

334     private static final Value getValueProperty(ClassLoader JavaDoc classLoader, String JavaDoc propertyName) {
335         Value value = null;
336
337         if (propertyName != null) {
338             /**
339              * If classLoader isn't bootstrap loader (==null),
340              * then get up-tree value.
341              */

342             if (classLoader != null) {
343                 value = getValueProperty(getParent(classLoader), propertyName);
344             }
345             
346             if (value == null || value.isDefault) {
347                 synchronized (propertiesCache) {
348                     HashMap JavaDoc properties = (HashMap JavaDoc)propertiesCache.get(classLoader);
349                         
350                     if (properties != null) {
351                         Value altValue = (Value)properties.get(propertyName);
352                         
353                         // set value only if override exists..
354
// otherwise pass default (or null) on..
355
if (altValue != null)
356                             value = altValue;
357                     }
358                 }
359             }
360         }
361         
362         return value;
363     }
364     
365     private static final ClassLoader JavaDoc getThreadContextClassLoader() {
366         return JDKHooks.getJDKHooks().getThreadContextClassLoader();
367     }
368
369     private static final ClassLoader JavaDoc getParent(final ClassLoader JavaDoc classLoader) {
370         return (ClassLoader JavaDoc)AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
371                     public Object JavaDoc run() {
372                         return classLoader.getParent();
373                     }
374                 });
375     }
376 }
377
Popular Tags