1 /*
2 * Copyright 2000-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.scaffold.http;
18
19 import java.io.BufferedInputStream;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.util.Map;
23 import java.util.Properties;
24
25 import javax.servlet.ServletException;
26 import javax.servlet.UnavailableException;
27 import javax.servlet.http.HttpServlet;
28
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31
32 /**
33 * Base servlet for loading application resources.
34 *
35 * @author Ted Husted
36 * @author Steve Raeburn
37 */
38 public class ResourceServlet extends HttpServlet {
39
40 // TODO: Externalize messages using commons resources.
41 // Previous suggestion was to use MessageResources, but this would
42 // create a dependency on Struts. A better option would be to use
43 // Commons Resources, which Struts will eventually migrate to.
44
45 // ------------------------------------------------------- Class variables
46
47 /**
48 * Commons logging instance
49 */
50 private static Log log = LogFactory.getLog(ResourceServlet.class);
51
52 // ------------------------------------------------------ Logging Messages
53
54 private static final String INIT_FAILED_EVENT =
55 "ResourceServlet: init() failed.";
56
57 private static final String RELOAD_EVENT =
58 "Reloading ResourceServlet";
59
60 private static final String DESTROY_EVENT =
61 "Destroying ResourceServlet";
62
63 private static final String RESOURCE_LOADING =
64 "Loading resources from path: ";
65
66 private static final String RESOURCE_NOT_FOUND =
67 "Resources not found";
68
69 // --------------------------------------------------- Parameter Utilities
70
71 /**
72 * Check for a parameter and returns a default value if not found.
73 *
74 * @param parameter The attribute name to look for
75 * @param defaultValue The default to return if the parameter is not found
76 * @return The customized value or the default value
77 */
78 public String getInitString(String parameter, String defaultValue) {
79
80 String stringValue = getServletConfig().getInitParameter(parameter);
81 if (null == stringValue)
82 return defaultValue;
83 return stringValue;
84
85 }
86
87 /**
88 * Check for a parameter and returns a default value if not found,
89 * or if the value does not convert to an <code>int</code>.
90 *
91 * @param parameter The attribute name to look for
92 * @defaultValue The default to return if the parameter is not found
93 * @return The customized value or the default value
94 */
95 public int getInitInt(String parameter, int defaultValue) {
96
97 String stringValue = null;
98 int intValue = defaultValue;
99
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