View Javadoc

1   /*
2    * Copyright 1999-2002,2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.commons.latka;
18  
19  import java.io.InputStream;
20  import java.io.IOException;
21  import java.util.Properties;
22  
23  import org.apache.log4j.Category;
24  
25  /***
26   * Stores properties for Latka.  This class is backed by a 
27   * ThreadLocal variable, so every Thread is guaranteed to
28   * get a unique Properties object.  Note, however, that
29   * inside an environment utilizing a Thread pool, such
30   * as many Servlet engines, it is possible for 
31   * the Properties object to travel quite widely.  Use the
32   * {@link #resetProperties()} method to reset the Properties
33   * object for a Thread to its default values.
34   * 
35   * @author Morgan Delagrange
36   * @author dIon Gillard (javadoc changes)
37   */
38  public class LatkaProperties {
39  
40      /*** log4j category to append output to */
41      protected static final Category _log =
42          Category.getInstance(LatkaProperties.class);
43  
44      /*** default Properties file for Latka */
45      protected static Properties _initProps = loadDefaultProps();
46  
47      static {
48          _initProps.putAll(loadUserProps());
49      }
50  
51      /***
52       * This ThreadLocal is automatically instantiated per thread
53       * with a Properties object containing the default properties.
54       */
55      protected static ThreadLocal _propsThreadLocal =
56          new LatkaThreadLocal(_initProps);
57  
58      /***
59       * Returns the unique Properties object for the current
60       * Thread.  The Properties object is initialized with
61       * the default Latka Properties.
62       * 
63       * @return Latka Properties object 
64       */
65      public static Properties getProperties() {
66          return (Properties) _propsThreadLocal.get();
67      }
68  
69      /***
70       * Resets the Latka properties to their initial value
71       * (getProperties() will still return the same Object).
72       * One use for this method is to reset state inside
73       * a Thread-pooling environment.
74       */
75      public static void resetProperties() {
76          Properties props = (Properties) _propsThreadLocal.get();
77          props.clear();
78          props.putAll(_initProps);
79      }
80  
81      /***
82       * Loads the default Properties from the 
83       * first "latka.properties" file located encountered 
84       * in the classpath.
85       * 
86       * @return A Properties object generated from the contents of the
87       *         default property file
88       */
89      protected static Properties loadDefaultProps() {
90  
91          Properties properties  = new Properties();
92      
93          try {
94              properties.putAll(
95                         loadPropsFromClasspath("latka.properties.internal"));
96          } catch (IOException e) {
97              _log.error(
98                  "Couldn't find latka.properties.internal file in the classpath",
99                  e);
100         }
101 
102         return properties;
103 
104     }
105 
106     /***
107      * Load <em>latka.properties</em> from classpath
108      * @return loaded properties
109      */
110     protected static Properties loadUserProps() {
111 
112         Properties properties  = new Properties();
113 
114         try {
115             properties.putAll(loadPropsFromClasspath("latka.properties"));
116         } catch (IOException e) {
117             _log.debug(e);
118             _log.warn(
119              "No user-defined latka.properties file in the classpath (optional)"
120                      );
121         }
122 
123         return properties;
124    
125     }
126 
127     /***
128      * Load properties specified from context class path
129      * @param classpathLocation Resource name to load
130      * @throws IOException from loading resource
131      * @return initialized properties object
132      */
133     protected static Properties
134                      loadPropsFromClasspath(String classpathLocation)
135                      throws IOException {
136         Properties properties  = new Properties();
137     
138         ClassLoader loader = Thread.currentThread().getContextClassLoader();
139         if (loader == null) {
140         	// there may not be a context class loader
141         	loader = LatkaProperties.class.getClassLoader();
142         }
143 
144         InputStream stream = loader.getResourceAsStream(classpathLocation);
145 
146         if (stream == null) {
147             throw new IOException("Could not find this file in classpath: "
148                 + classpathLocation);
149         }
150 
151         properties.load(stream);
152 
153         return properties;
154     }
155 
156     /***
157      * Custom ThreadLocal class that automatically initialized
158      * the default Properties for the Thread.
159      * 
160      * @author Morgan Delagrange
161      */
162     private static class LatkaThreadLocal extends ThreadLocal {
163         /*** default properties for the thread */
164         protected Properties _initProps = null;
165 
166         /***
167          * Constructor specifying the default Properties object
168          * for Latka
169          * 
170          * @param initProps default Properties object
171          */
172         public LatkaThreadLocal(Properties initProps) {
173             _initProps = initProps;
174         }
175 
176         /***
177          * Returns a clone of the default Properties file
178          * for Latka
179          * 
180          * @return Latka Properties file for the current Thread
181          */
182         protected Object initialValue() {
183             return _initProps.clone();
184         }
185 
186     }
187 
188 }