1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
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 }