001 /* 002 * Copyright 1999-2002,2004 The Apache Software Foundation. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.apache.commons.latka; 018 019 import java.io.InputStream; 020 import java.io.IOException; 021 import java.util.Properties; 022 023 import org.apache.log4j.Category; 024 025 /** 026 * Stores properties for Latka. This class is backed by a 027 * ThreadLocal variable, so every Thread is guaranteed to 028 * get a unique Properties object. Note, however, that 029 * inside an environment utilizing a Thread pool, such 030 * as many Servlet engines, it is possible for 031 * the Properties object to travel quite widely. Use the 032 * {@link #resetProperties()} method to reset the Properties 033 * object for a Thread to its default values. 034 * 035 * @author Morgan Delagrange 036 * @author dIon Gillard (javadoc changes) 037 */ 038 public class LatkaProperties { 039 040 /** log4j category to append output to */ 041 protected static final Category _log = 042 Category.getInstance(LatkaProperties.class); 043 044 /** default Properties file for Latka */ 045 protected static Properties _initProps = loadDefaultProps(); 046 047 static { 048 _initProps.putAll(loadUserProps()); 049 } 050 051 /** 052 * This ThreadLocal is automatically instantiated per thread 053 * with a Properties object containing the default properties. 054 */ 055 protected static ThreadLocal _propsThreadLocal = 056 new LatkaThreadLocal(_initProps); 057 058 /** 059 * Returns the unique Properties object for the current 060 * Thread. The Properties object is initialized with 061 * the default Latka Properties. 062 * 063 * @return Latka Properties object 064 */ 065 public static Properties getProperties() { 066 return (Properties) _propsThreadLocal.get(); 067 } 068 069 /** 070 * Resets the Latka properties to their initial value 071 * (getProperties() will still return the same Object). 072 * One use for this method is to reset state inside 073 * a Thread-pooling environment. 074 */ 075 public static void resetProperties() { 076 Properties props = (Properties) _propsThreadLocal.get(); 077 props.clear(); 078 props.putAll(_initProps); 079 } 080 081 /** 082 * Loads the default Properties from the 083 * first "latka.properties" file located encountered 084 * in the classpath. 085 * 086 * @return A Properties object generated from the contents of the 087 * default property file 088 */ 089 protected static Properties loadDefaultProps() { 090 091 Properties properties = new Properties(); 092 093 try { 094 properties.putAll( 095 loadPropsFromClasspath("latka.properties.internal")); 096 } catch (IOException e) { 097 _log.error( 098 "Couldn't find latka.properties.internal file in the classpath", 099 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 }