1 package org.apache.turbine.services;
2
3 /* ====================================================================
4 * The Apache Software License, Version 1.1
5 *
6 * Copyright (c) 2001 The Apache Software Foundation. All rights
7 * reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * 3. The end-user documentation included with the redistribution,
22 * if any, must include the following acknowledgment:
23 * "This product includes software developed by the
24 * Apache Software Foundation (http://www.apache.org/)."
25 * Alternately, this acknowledgment may appear in the software itself,
26 * if and wherever such third-party acknowledgments normally appear.
27 *
28 * 4. The names "Apache" and "Apache Software Foundation" and
29 * "Apache Turbine" must not be used to endorse or promote products
30 * derived from this software without prior written permission. For
31 * written permission, please contact apache@apache.org.
32 *
33 * 5. Products derived from this software may not be called "Apache",
34 * "Apache Turbine", nor may "Apache" appear in their name, without
35 * prior written permission of the Apache Software Foundation.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 * ====================================================================
50 *
51 * This software consists of voluntary contributions made by many
52 * individuals on behalf of the Apache Software Foundation. For more
53 * information on the Apache Software Foundation, please see
54 * <http://www.apache.org/>.
55 */
56
57 import java.io.PrintWriter;
58 import java.io.StringWriter;
59 import java.util.Iterator;
60 import java.util.Properties;
61 import java.util.Vector;
62 import javax.servlet.ServletConfig;
63 import org.apache.commons.configuration.Configuration;
64 import org.apache.turbine.services.logging.LoggingService;
65 import org.apache.turbine.services.resources.ResourceService;
66 import org.apache.turbine.services.resources.TurbineResources;
67
68
69 /***
70 * This is a singleton utility class that acts as a Services broker.
71 *
72 * @author <a href="mailto:greg@shwoop.com">Greg Ritter</a>
73 * @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a>
74 * @author <a href="mailto:burton@apache.org">Kevin Burton</a>
75 * @author <a href="mailto:krzewski@e-point.pl">Rafal Krzewski</a>
76 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
77 * @version $Id: TurbineServices.java,v 1.5 2002/07/11 16:53:28 mpoeschl Exp $
78 */
79 public class TurbineServices
80 extends BaseServiceBroker
81 {
82 /***
83 * Servlet initialization parameter name for defining the resources
84 * service implementation to use (<code>resources</code>).
85 */
86 public final static String RESOURCES_CLASS_KEY = "resources";
87
88 /***
89 * Default resources service implementation to use when none explicitly
90 * specified (<code>
91 * org.apache.turbine.services.resources.TurbineResourceService</code>)
92 */
93 public final static String RESOURCES_CLASS_DEFAULT =
94 "org.apache.turbine.services.resources.TurbineResourceService";
95
96 /*** Default bootstrap logger implementation */
97 public final static String LOGGING_CLASS_DEFAULT =
98 "org.apache.turbine.services.logging.TurbineLoggingService";
99
100 /***
101 * Servlet initialization parameter name for defining the logging
102 * service implementation to use.
103 */
104 public final static String LOGGING_CLASS_KEY="logging";
105
106 /***
107 * Servlet initialization parameter name for the path to
108 * TurbineResources.properties file used by
109 * {@link org.apache.turbine.services.resources.TurbineResourceService}
110 * (<code>properties</code>).
111 */
112 public static final String PROPERTIES_PATH_KEY = "properties";
113
114 /***
115 * Default value of TurbineResources.properties file path
116 * (<code>/WEB-INF/conf/TurbineResources.properties</code>).
117 */
118 public static final String PROPERTIES_PATH_DEFAULT =
119 "/WEB-INF/conf/TurbineResources.properties";
120
121 /***
122 * A prefix for <code>Service</code> properties in
123 * TurbineResource.properties.
124 */
125 public static final String SERVICE_PREFIX = "services.";
126
127 /***
128 * A <code>Service</code> property determining its implementing
129 * class name .
130 */
131 public static final String CLASSNAME_SUFFIX = ".classname";
132
133 /*** The single instance of this class. */
134 protected static ServiceBroker instance = new TurbineServices();
135
136 /*** True if logging should go throught LoggingService, false if not. */
137 private boolean enabledLogging = false;
138
139 /*** caches log messages before logging is enabled */
140 private Vector logCache = new Vector(5);
141
142 /*** the logger */
143 private LoggingService logger;
144
145 /***
146 * This constructor is protected to force clients to use
147 * getInstance() to access this class.
148 */
149 protected TurbineServices()
150 {
151 super();
152 }
153
154 /***
155 * The method through which this class is accessed.
156 *
157 * @return The single instance of this class.
158 */
159 public static ServiceBroker getInstance()
160 {
161 return instance;
162 }
163
164 /***
165 * Initialize the primary services (Logging and Resources).
166 */
167 public void initPrimaryServices(ServletConfig config)
168 throws InstantiationException, InitializationException
169 {
170 // Resource service must start as the very first
171 String resourcesClass = config.getInitParameter(RESOURCES_CLASS_KEY);
172
173 try
174 {
175 if (resourcesClass == null)
176 {
177 resourcesClass = RESOURCES_CLASS_DEFAULT;
178 }
179 mapping.setProperty(ResourceService.SERVICE_NAME, resourcesClass);
180 initService(ResourceService.SERVICE_NAME, config);
181
182 // Now logging can be initialized
183 String loggingClass = config.getInitParameter(LOGGING_CLASS_KEY);
184 if (loggingClass == null)
185 {
186 loggingClass = LOGGING_CLASS_DEFAULT;
187 }
188 mapping.setProperty(LoggingService.SERVICE_NAME, loggingClass);
189 try
190 {
191 initService(LoggingService.SERVICE_NAME, config);
192 logger = getLogger();
193 }
194 catch (InitializationException e)
195 {
196 mapping.clearProperty(LoggingService.SERVICE_NAME);
197 throw e;
198 }
199 catch (InstantiationException e)
200 {
201 mapping.clearProperty(LoggingService.SERVICE_NAME);
202 throw e;
203 }
204 }
205 finally
206 {
207 // All further messages will go through LoggingService
208 // if logging service could not be initialized we still want
209 // to enable logging for further messages to go to console
210 enableLogging();
211 }
212 // Since we have ResourceService running, real mappings of services
213 // may be loaded now
214 initMapping();
215 }
216
217 /***
218 * Creates mapping of Service names to class names.
219 * BaseServiceBroker knows no mappings.
220 */
221 public void initMapping(Configuration mapping)
222 {
223 this.mapping = mapping;
224 }
225
226 /***
227 * Creates a mapping between Service names and class names.
228 *
229 * The mapping is built according to settings present in
230 * TurbineResources.properties. The entries should have the
231 * following form:
232 *
233 * <pre>
234 * services.MyService.classname=com.mycompany.MyServiceImpl
235 * services.MyOtherService.classname=com.mycompany.MyOtherServiceImpl
236 * </pre>
237 *
238 * <br>
239 *
240 * Generic ServiceBroker provides no Services.
241 */
242 protected void initMapping()
243 {
244 int pref = SERVICE_PREFIX.length();
245 int suff = CLASSNAME_SUFFIX.length();
246
247 /*
248 * These keys returned in an order that corresponds
249 * to the order the services are listed in
250 * the TR.props.
251 *
252 * When the mapping is created we use a Configuration
253 * object to ensure that the we retain the order
254 * in which the order the keys are returned.
255 *
256 * There's no point in retrieving an ordered set
257 * of keys if they aren't kept in order :-)
258 */
259 Iterator keys = TurbineResources.getKeys();
260 while(keys.hasNext())
261 {
262 String key = (String)keys.next();
263 if (key.startsWith(SERVICE_PREFIX) && key.endsWith(CLASSNAME_SUFFIX))
264 {
265 String serviceKey = key.substring(pref, key.length() - suff);
266 notice ("Added Mapping for Service: " + serviceKey);
267
268 if (!mapping.containsKey(serviceKey))
269 mapping.setProperty(serviceKey, TurbineResources.getString(key));
270 }
271 }
272 }
273
274 /***
275 * Returns the properites of a specific service. Properties are
276 * retrieved from TurbineResources.properties provided that you
277 * have the following entries:
278 *
279 * <br>
280 *
281 * services.MyService.greeting=Hello\, I'm Jan B.
282 *
283 * <br>
284 *
285 * services.MyService.defaultAction=beep
286 *
287 * <br>
288 *
289 * Service "MyService" will get a set of two properites:
290 * "greeting" = "Hello, I'm Jan B." and "defaultAction" = "beep".
291 *
292 * <p> Note that this way you will receive a 'collapsed' version
293 * of your resources - multiple entries with the same key will
294 * have only one value stored. Use the {@link #getConfiguration}
295 * or {@link #getResources} method to take advantage of the capabilities
296 * of the {@link org.apache.turbine.services.resources.TurbineResources}
297 * class.
298 *
299 * @param name The name of the service.
300 * @return Properties of requested Service.
301 */
302 public Properties getProperties( String name )
303 {
304 Properties properties = new Properties();
305
306 String servicePrefix = SERVICE_PREFIX + name + '.';
307 Iterator keys = TurbineResources.getKeys(servicePrefix);
308
309 while(keys.hasNext())
310 {
311 String key = (String)keys.next();
312 String value;
313 try
314 {
315 value = TurbineResources.getString(key);
316 }
317 catch (ClassCastException propIsArray)
318 {
319 String[] values = TurbineResources.getStringArray(key);
320 value = values[values.length - 1];
321 }
322 properties.setProperty(key.substring(servicePrefix.length()),
323 value);
324 }
325
326 return properties;
327 }
328
329 /***
330 * Returns the Configuration for the specified service.
331 *
332 * @param name The name of the service.
333 */
334 public Configuration getConfiguration( String name )
335 {
336 return TurbineResources.getConfiguration(SERVICE_PREFIX + name);
337 }
338
339 /***
340 * Returns the configuration resources of a specific service.
341 *
342 * This method extracts the configuration options of a service
343 * from global Turbine configuration. The interface
344 * {@link org.apache.turbine.services.resources.ResourceService}
345 * offers significant advantages over plain java.util.Properties -
346 * you can request for exaple you can retrieve <code>int</code>s
347 * <code>boolean</code>s, and vectors of <code>String</code>s.
348 *
349 * <p> Note that the proces extracting the configuration might
350 * be time consuming, it might be a good idea to store the
351 * reference returned by this method in an instance variable
352 * of the service.</p>
353 *
354 * @param name The name of the Service.
355 * @return The configuration resources of the Service.
356 */
357 public ResourceService getResources( String name )
358 {
359 return TurbineResources.getResources(SERVICE_PREFIX + name);
360 }
361
362 /***
363 * Output a diagnostic notice.
364 *
365 * This method is used by the service framework classes for producing
366 * tracing mesages that might be useful for debugging.
367 *
368 * <p>Standard Turbine logging facilities are used.
369 *
370 * @param msg the message to print.
371 */
372 public void notice(String msg)
373 {
374 if (enabledLogging)
375 {
376 if (logger == null)
377 {
378 System.out.println("(!) NOTICE: " + msg);
379 }
380 else
381 {
382 logger.info(msg);
383 }
384 }
385 else
386 {
387 // cache the message to log as soon as logiing is on
388 logCache.add(msg);
389 }
390 }
391
392 /***
393 * Output an error message.
394 *
395 * This method is used by the service framework classes for displaying
396 * stacktraces of any exceptions that might be caught during processing.
397 *
398 * <p>Standard Turbine logging facilities are used.
399 *
400 * @param msg the message to print.
401 */
402 public void error(Throwable t)
403 {
404 if (enabledLogging)
405 {
406 if (logger == null)
407 {
408 System.out.println("(!) ERROR: " + t.getMessage());
409 }
410 else
411 {
412 logger.error("", t);
413 }
414 }
415 else
416 {
417 // cache the message to log as soon as logiing is on
418 logCache.add("ERROR: " + t.getMessage());
419 StringWriter sw = new StringWriter();
420 t.printStackTrace(new PrintWriter(sw));
421 logCache.add(sw.toString());
422 }
423
424 }
425
426 /***
427 * Allows logging using a logging service instead of console
428 * This method should be called after initialization of the logging service
429 */
430 private void enableLogging()
431 {
432 enabledLogging = true;
433 //log all cached log messages
434 for (int i = 0; i < logCache.size(); i++)
435 {
436 String s = (String) logCache.elementAt(i);
437 notice(s);
438 }
439 //dispose of the cache
440 logCache = null;
441
442 notice("ServiceBroker: LoggingService enabled.");
443
444 }
445
446 /***
447 * Macro to reduce duplicated code and casting.
448 */
449 private final LoggingService getLogger()
450 {
451 return (LoggingService) getService(LoggingService.SERVICE_NAME);
452 }
453 }
This page was automatically generated by Maven