001 /* 002 * Copyright 2000-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.scaffold.http; 018 019 import java.io.BufferedInputStream; 020 import java.io.IOException; 021 import java.io.InputStream; 022 import java.util.Map; 023 import java.util.Properties; 024 025 import javax.servlet.ServletException; 026 import javax.servlet.UnavailableException; 027 import javax.servlet.http.HttpServlet; 028 029 import org.apache.commons.logging.Log; 030 import org.apache.commons.logging.LogFactory; 031 032 /** 033 * Base servlet for loading application resources. 034 * 035 * @author Ted Husted 036 * @author Steve Raeburn 037 */ 038 public class ResourceServlet extends HttpServlet { 039 040 // TODO: Externalize messages using commons resources. 041 // Previous suggestion was to use MessageResources, but this would 042 // create a dependency on Struts. A better option would be to use 043 // Commons Resources, which Struts will eventually migrate to. 044 045 // ------------------------------------------------------- Class variables 046 047 /** 048 * Commons logging instance 049 */ 050 private static Log log = LogFactory.getLog(ResourceServlet.class); 051 052 // ------------------------------------------------------ Logging Messages 053 054 private static final String INIT_FAILED_EVENT = 055 "ResourceServlet: init() failed."; 056 057 private static final String RELOAD_EVENT = 058 "Reloading ResourceServlet"; 059 060 private static final String DESTROY_EVENT = 061 "Destroying ResourceServlet"; 062 063 private static final String RESOURCE_LOADING = 064 "Loading resources from path: "; 065 066 private static final String RESOURCE_NOT_FOUND = 067 "Resources not found"; 068 069 // --------------------------------------------------- Parameter Utilities 070 071 /** 072 * Check for a parameter and returns a default value if not found. 073 * 074 * @param parameter The attribute name to look for 075 * @param defaultValue The default to return if the parameter is not found 076 * @return The customized value or the default value 077 */ 078 public String getInitString(String parameter, String defaultValue) { 079 080 String stringValue = getServletConfig().getInitParameter(parameter); 081 if (null == stringValue) 082 return defaultValue; 083 return stringValue; 084 085 } 086 087 /** 088 * Check for a parameter and returns a default value if not found, 089 * or if the value does not convert to an <code>int</code>. 090 * 091 * @param parameter The attribute name to look for 092 * @defaultValue The default to return if the parameter is not found 093 * @return The customized value or the default value 094 */ 095 public int getInitInt(String parameter, int defaultValue) { 096 097 String stringValue = null; 098 int intValue = defaultValue; 099 100 try { 101 102 stringValue = getServletConfig().getInitParameter(parameter); 103 intValue = Integer.parseInt(stringValue); 104 105 } catch (Throwable t) { 106 intValue = defaultValue; 107 } 108 109 return intValue; 110 } 111 112 /** 113 * Return a map of this servlet's initialization parameters. 114 * 115 * @return A map of this servlet's initialization parameters. 116 * @fixme Not tested yet 117 */ 118 public Map getInitParameters() { 119 120 // :FIXME: Not tested yet. 121 122 java.util.Enumeration names = 123 getServletConfig().getInitParameterNames(); 124 java.util.HashMap map = new java.util.HashMap(); 125 while (names.hasMoreElements()) { 126 String name = (String) names.nextElement(); 127 String value = getServletConfig().getInitParameter(name); 128 map.put(name, value); 129 } 130 return map; 131 } 132 133 // --------------------------------------------------- Internal Properties 134 135 /** 136 * The parameter to check for a new path to the default properties 137 * ["default"]. 138 */ 139 private static final String DEFAULT_PARAMETER = "default"; 140 141 /** 142 * The default path to use if parameter is not set 143 *["resources/default.properties"]. 144 */ 145 private static final String DEFAULT_PATH = "resources/default.properties"; 146 147 /** 148 * The default attribute for the application properties. 149 * The properties are exposed in the servlet context 150 * under this attribute name 151 * [lang.Tokens.PROPERTIES_KEY]. 152 */ 153 private static final String DEFAULT_ATTRIBUTE = 154 org.apache.commons.scaffold.lang.Tokens.PROPERTIES_KEY; 155 156 /** 157 * Our default properties object. 158 * <p> 159 * The default properties can be used to store applications 160 * settings that do not need to be localized and may 161 * not even be displayed to the user. 162 */ 163 Properties properties = null; 164 165 /** 166 * Set the default properties object. 167 */ 168 public void setProperties(Properties properties) { 169 this.properties = properties; 170 } 171 172 /** 173 * Return the default properties object. 174 * 175 * @return The default properties object 176 */ 177 public Properties getProperties() { 178 return this.properties; 179 } 180 181 /** 182 * A utility method for loading a Properties file 183 * specified by an initialization parameter. 184 * 185 * The initialization parameter should specify the 186 * package and folder for the Properties in system 187 * path format (resources/custom.properties). 188 * 189 * @param parameter The name of the initialization 190 * parameter 191 * @param defaultPath The path to use if the 192 * parameter is not found 193 * @param attribute If not null, store in 194 * application scope under this attribute name 195 */ 196 public Properties loadProperties( 197 String parameter, 198 String defaultPath, 199 String attribute) 200 throws ServletException { 201 202 String path = getInitString(parameter, defaultPath); 203 204 if (log.isDebugEnabled()) { 205 log.debug(RESOURCE_LOADING); 206 log.debug(path); 207 } 208 209 InputStream is = null; 210 is = this.getClass().getClassLoader().getResourceAsStream(path); 211 if (null == is) 212 throw new UnavailableException(RESOURCE_NOT_FOUND); 213 214 Properties p = null; 215 BufferedInputStream bis = new BufferedInputStream(is); 216 217 try { 218 219 p = new Properties(); 220 p.load(bis); 221 bis.close(); 222 is.close(); 223 } catch (IOException e) { 224 225 p = null; 226 227 } finally { 228 is = null; 229 bis = null; 230 } 231 232 if ((null != p) && (null != attribute)) { 233 234 this.getServletContext().setAttribute(attribute, p); 235 236 } 237 238 if (log.isDebugEnabled()) { 239 log.debug(p.toString()); 240 } 241 242 return p; 243 } 244 245 /** 246 * Initialize the default properties for this application. 247 * <p> 248 * Use the <code>default</code> initialization parameter to specify 249 * another path. Otherwise ["resources/default.properties"] is used. 250 * <p> 251 * If the default properties will not be used or specified, 252 * override this method with one that does not try to load the 253 * default properties. 254 * 255 * @exception IOException if an input/output error is encountered 256 * @exception ServletException if we cannot initialize these resources 257 * @todo The PROPERTIES_KEY could be made configurable, 258 * but the BaseAction would need to be notified. 259 */ 260 protected void initDefault() throws IOException, ServletException { 261 262 setProperties( 263 loadProperties(DEFAULT_PARAMETER, DEFAULT_PATH, DEFAULT_ATTRIBUTE)); 264 } 265 266 /** 267 * Release any default resources created at initialization 268 */ 269 protected void destroyDefault() { 270 setProperties(null); 271 } 272 273 // --------------------------------------------------- HttpServlet Methods 274 275 /** 276 * Initialize this servlet by caling three extension points: 277 * <ul> 278 * <li><code>initLogging</code></li> 279 * <li><code>initDefault</code></li> 280 * <li><code>initCustom</code></li> 281 * </ul> 282 * The main extension point is <code><b>initCustom</b></code> 283 * The default implementation does nothing. 284 * The other two methods have reasonable default behaviors that most 285 * subclasses could use as-is. 286 * This may be called again from <code>reload</code> and should be 287 * "re-enterant". 288 * 289 * @exception ServletException if we cannot configure ourselves 290 * correctly 291 */ 292 public void init() throws ServletException { 293 294 try { 295 296 initDefault(); 297 // initMessages(); 298 initCustom(); 299 300 } catch (IOException e) { 301 302 throw new UnavailableException(INIT_FAILED_EVENT); 303 304 } 305 } 306 307 /** 308 * Gracefully shut down this controller servlet, releasing any resources 309 * that were allocated at initialization. 310 */ 311 public void destroy() { 312 313 if (log.isDebugEnabled()) { 314 log.debug(DESTROY_EVENT); 315 } 316 317 destroyCustom(); 318 // destroyMessages(); 319 destroyDefault(); 320 321 } 322 323 // ------------------------------------------------------ Extension Points 324 325 /** 326 * Initialize the custom properties or objects for this application. 327 * 328 * @exception IOException if an input/output error is encountered 329 * @exception ServletException if we cannot initialize these resources 330 */ 331 protected void initCustom() throws IOException, ServletException { 332 333 // Override with custom initializations 334 335 } 336 337 /** 338 * Release any custom resources created at initialization 339 */ 340 protected void destroyCustom() { 341 // override to provide functionality if needed 342 } 343 344 // -------------------------------------------------------- Public Methods 345 346 /** 347 * Reload the configuration of this controller servlet from our 348 * underlying configuration files. 349 * 350 * @exception IOException if an input/output error occurs 351 * @exception ServletException if a servlet exception occurs 352 */ 353 public void reload() throws IOException, ServletException { 354 355 if (log.isDebugEnabled()) { 356 log.debug(RELOAD_EVENT); 357 } 358 359 // Re-initialize 360 init(); 361 } 362 363 } // end ResourceServlet