001: /*
002: * Copyright 1999,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.catalina.logger;
018:
019: import java.beans.PropertyChangeListener;
020: import java.beans.PropertyChangeSupport;
021: import java.io.CharArrayWriter;
022: import java.io.PrintWriter;
023:
024: import javax.management.MBeanRegistration;
025: import javax.management.MBeanServer;
026: import javax.management.ObjectName;
027: import javax.servlet.ServletException;
028:
029: import org.apache.catalina.Container;
030: import org.apache.catalina.Lifecycle;
031: import org.apache.catalina.LifecycleException;
032: import org.apache.catalina.LifecycleListener;
033: import org.apache.catalina.Logger;
034: import org.apache.catalina.core.StandardContext;
035: import org.apache.catalina.core.StandardEngine;
036: import org.apache.catalina.core.StandardHost;
037: import org.apache.catalina.util.LifecycleSupport;
038: import org.apache.commons.logging.Log;
039: import org.apache.commons.logging.LogFactory;
040: import org.apache.commons.modeler.Registry;
041:
042: /**
043: * Convenience base class for <b>Logger</b> implementations. The only
044: * method that must be implemented is <code>log(String msg)</code>, plus
045: * any property setting and lifecycle methods required for configuration.
046: *
047: * @author Craig R. McClanahan
048: * @version $Revision: 1.9 $ $Date: 2004/05/26 15:48:29 $
049: */
050:
051: public class LoggerBase implements Lifecycle, Logger, MBeanRegistration {
052: private static Log log = LogFactory.getLog(LoggerBase.class);
053:
054: // ----------------------------------------------------- Instance Variables
055:
056: /**
057: * The Container with which this Logger has been associated.
058: */
059: protected Container container = null;
060:
061: /**
062: * The debugging detail level for this component.
063: */
064: protected int debug = 0;
065:
066: /**
067: * The descriptive information about this implementation.
068: */
069: protected static final String info = "org.apache.catalina.logger.LoggerBase/1.0";
070:
071: /**
072: * The lifecycle event support for this component.
073: */
074: protected LifecycleSupport lifecycle = new LifecycleSupport(this );
075:
076: /**
077: * The property change support for this component.
078: */
079: protected PropertyChangeSupport support = new PropertyChangeSupport(
080: this );
081:
082: /**
083: * The verbosity level for above which log messages may be filtered.
084: */
085: protected int verbosity = ERROR;
086:
087: // ------------------------------------------------------------- Properties
088:
089: /**
090: * Return the Container with which this Logger has been associated.
091: */
092: public Container getContainer() {
093:
094: return (container);
095:
096: }
097:
098: /**
099: * Set the Container with which this Logger has been associated.
100: *
101: * @param container The associated Container
102: */
103: public void setContainer(Container container) {
104:
105: Container oldContainer = this .container;
106: this .container = container;
107: support.firePropertyChange("container", oldContainer,
108: this .container);
109:
110: }
111:
112: /**
113: * Return the debugging detail level for this component.
114: */
115: public int getDebug() {
116:
117: return (this .debug);
118:
119: }
120:
121: /**
122: * Set the debugging detail level for this component.
123: *
124: * @param debug The new debugging detail level
125: */
126: public void setDebug(int debug) {
127:
128: this .debug = debug;
129:
130: }
131:
132: /**
133: * Return descriptive information about this Logger implementation and
134: * the corresponding version number, in the format
135: * <code><description>/<version></code>.
136: */
137: public String getInfo() {
138:
139: return (info);
140:
141: }
142:
143: /**
144: * Return the verbosity level of this logger. Messages logged with a
145: * higher verbosity than this level will be silently ignored.
146: */
147: public int getVerbosity() {
148:
149: return (this .verbosity);
150:
151: }
152:
153: /**
154: * Set the verbosity level of this logger. Messages logged with a
155: * higher verbosity than this level will be silently ignored.
156: *
157: * @param verbosity The new verbosity level
158: */
159: public void setVerbosity(int verbosity) {
160:
161: this .verbosity = verbosity;
162:
163: }
164:
165: /**
166: * Set the verbosity level of this logger. Messages logged with a
167: * higher verbosity than this level will be silently ignored.
168: *
169: * @param verbosity The new verbosity level, as a string
170: */
171: public void setVerbosityLevel(String verbosity) {
172:
173: if ("FATAL".equalsIgnoreCase(verbosity))
174: this .verbosity = FATAL;
175: else if ("ERROR".equalsIgnoreCase(verbosity))
176: this .verbosity = ERROR;
177: else if ("WARNING".equalsIgnoreCase(verbosity))
178: this .verbosity = WARNING;
179: else if ("INFORMATION".equalsIgnoreCase(verbosity))
180: this .verbosity = INFORMATION;
181: else if ("DEBUG".equalsIgnoreCase(verbosity))
182: this .verbosity = DEBUG;
183:
184: }
185:
186: // --------------------------------------------------------- Public Methods
187:
188: /**
189: * Add a property change listener to this component.
190: *
191: * @param listener The listener to add
192: */
193: public void addPropertyChangeListener(
194: PropertyChangeListener listener) {
195:
196: support.addPropertyChangeListener(listener);
197:
198: }
199:
200: /**
201: * Writes the specified message to a servlet log file, usually an event
202: * log. The name and type of the servlet log is specific to the
203: * servlet container. This message will be logged unconditionally.
204: *
205: * @param msg A <code>String</code> specifying the message to be
206: * written to the log file
207: */
208: public void log(String msg) {
209: log.debug(msg);
210: }
211:
212: /**
213: * Writes the specified exception, and message, to a servlet log file.
214: * The implementation of this method should call
215: * <code>log(msg, exception)</code> instead. This method is deprecated
216: * in the ServletContext interface, but not deprecated here to avoid
217: * many useless compiler warnings. This message will be logged
218: * unconditionally.
219: *
220: * @param exception An <code>Exception</code> to be reported
221: * @param msg The associated message string
222: */
223: public void log(Exception exception, String msg) {
224:
225: log(msg, exception);
226:
227: }
228:
229: /**
230: * Writes an explanatory message and a stack trace for a given
231: * <code>Throwable</code> exception to the servlet log file. The name
232: * and type of the servlet log file is specific to the servlet container,
233: * usually an event log. This message will be logged unconditionally.
234: *
235: * @param msg A <code>String</code> that describes the error or
236: * exception
237: * @param throwable The <code>Throwable</code> error or exception
238: */
239: public void log(String msg, Throwable throwable) {
240:
241: CharArrayWriter buf = new CharArrayWriter();
242: PrintWriter writer = new PrintWriter(buf);
243: writer.println(msg);
244: throwable.printStackTrace(writer);
245: Throwable rootCause = null;
246: if (throwable instanceof LifecycleException)
247: rootCause = ((LifecycleException) throwable).getThrowable();
248: else if (throwable instanceof ServletException)
249: rootCause = ((ServletException) throwable).getRootCause();
250: if (rootCause != null) {
251: writer.println("----- Root Cause -----");
252: rootCause.printStackTrace(writer);
253: }
254: log(buf.toString());
255:
256: }
257:
258: /**
259: * Writes the specified message to the servlet log file, usually an event
260: * log, if the logger is set to a verbosity level equal to or higher than
261: * the specified value for this message.
262: *
263: * @param message A <code>String</code> specifying the message to be
264: * written to the log file
265: * @param verbosity Verbosity level of this message
266: */
267: public void log(String message, int verbosity) {
268:
269: if (this .verbosity >= verbosity)
270: log(message);
271:
272: }
273:
274: /**
275: * Writes the specified message and exception to the servlet log file,
276: * usually an event log, if the logger is set to a verbosity level equal
277: * to or higher than the specified value for this message.
278: *
279: * @param message A <code>String</code> that describes the error or
280: * exception
281: * @param throwable The <code>Throwable</code> error or exception
282: * @param verbosity Verbosity level of this message
283: */
284: public void log(String message, Throwable throwable, int verbosity) {
285:
286: if (this .verbosity >= verbosity)
287: log(message, throwable);
288:
289: }
290:
291: /**
292: * Remove a property change listener from this component.
293: *
294: * @param listener The listener to remove
295: */
296: public void removePropertyChangeListener(
297: PropertyChangeListener listener) {
298:
299: support.removePropertyChangeListener(listener);
300:
301: }
302:
303: protected String domain;
304: protected String host;
305: protected String path;
306: protected ObjectName oname;
307: protected ObjectName controller;
308: protected MBeanServer mserver;
309:
310: public ObjectName getController() {
311: return controller;
312: }
313:
314: public void setController(ObjectName controller) {
315: this .controller = controller;
316: }
317:
318: public ObjectName getObjectName() {
319: return oname;
320: }
321:
322: public String getDomain() {
323: return domain;
324: }
325:
326: public ObjectName preRegister(MBeanServer server, ObjectName name)
327: throws Exception {
328: oname = name;
329: mserver = server;
330: // FIXME null pointer exception
331: if (name == null) {
332: return null;
333: }
334: domain = name.getDomain();
335: host = name.getKeyProperty("host");
336: path = name.getKeyProperty("path");
337: if (container == null) {
338: // Register with the parent
339: try {
340: ObjectName cname = null;
341: if (host == null) {
342: // global
343: cname = new ObjectName(domain + ":type=Engine");
344: } else if (path == null) {
345: cname = new ObjectName(domain + ":type=Host,host="
346: + host);
347: } else {
348: cname = new ObjectName(domain
349: + ":j2eeType=WebModule,name=//" + host
350: + "/" + path);
351: }
352: log.debug("Register with " + cname);
353: mserver.invoke(cname, "setLogger",
354: new Object[] { this },
355: new String[] { "org.apache.catalina.Logger" });
356: } catch (Exception e) {
357: e.printStackTrace(); //To change body of catch statement use Options | File Templates.
358: }
359: }
360:
361: return name;
362: }
363:
364: public void postRegister(Boolean registrationDone) {
365: }
366:
367: public void preDeregister() throws Exception {
368: }
369:
370: public void postDeregister() {
371: }
372:
373: public void init() {
374:
375: }
376:
377: public void destroy() {
378:
379: }
380:
381: public ObjectName createObjectName() {
382: // register
383: try {
384: StandardEngine engine = null;
385: String suffix = "";
386: if (container instanceof StandardEngine) {
387: engine = (StandardEngine) container;
388: } else if (container instanceof StandardHost) {
389: engine = (StandardEngine) container.getParent();
390: suffix = ",host=" + container.getName();
391: } else if (container instanceof StandardContext) {
392: String path = ((StandardContext) container).getPath();
393: // add "/" to avoid MalformedObjectName Exception
394: if (path.equals("")) {
395: path = "/";
396: }
397: engine = (StandardEngine) container.getParent()
398: .getParent();
399: suffix = ",path=" + path + ",host="
400: + container.getParent().getName();
401: } else {
402: log.error("Unknown container " + container);
403: }
404: if (engine != null) {
405: oname = new ObjectName(engine.getDomain()
406: + ":type=Logger" + suffix);
407: } else {
408: log.error("Null engine !! " + container);
409: }
410: } catch (Throwable e) {
411: e.printStackTrace(); //To change body of catch statement use Options | File Templates.
412: }
413: return oname;
414: }
415:
416: // ------------------------------------------------------ Lifecycle Methods
417:
418: /**
419: * Add a lifecycle event listener to this component.
420: *
421: * @param listener The listener to add
422: */
423: public void addLifecycleListener(LifecycleListener listener) {
424:
425: lifecycle.addLifecycleListener(listener);
426:
427: }
428:
429: /**
430: * Get the lifecycle listeners associated with this lifecycle. If this
431: * Lifecycle has no listeners registered, a zero-length array is returned.
432: */
433: public LifecycleListener[] findLifecycleListeners() {
434:
435: return lifecycle.findLifecycleListeners();
436:
437: }
438:
439: /**
440: * Remove a lifecycle event listener from this component.
441: *
442: * @param listener The listener to add
443: */
444: public void removeLifecycleListener(LifecycleListener listener) {
445:
446: lifecycle.removeLifecycleListener(listener);
447:
448: }
449:
450: /**
451: * Prepare for the beginning of active use of the public methods of this
452: * component. This method should be called after <code>configure()</code>,
453: * and before any of the public methods of the component are utilized.
454: *
455: * @exception LifecycleException if this component detects a fatal error
456: * that prevents this component from being used
457: */
458: public void start() throws LifecycleException {
459:
460: // register this logger
461: if (getObjectName() == null) {
462: ObjectName oname = createObjectName();
463: try {
464: Registry.getRegistry(null, null).registerComponent(
465: this , oname, null);
466: log.debug("registering logger " + oname);
467: } catch (Exception ex) {
468: log.error("Can't register logger " + oname, ex);
469: }
470: }
471:
472: }
473:
474: /**
475: * Gracefully terminate the active use of the public methods of this
476: * component. This method should be the last one called on a given
477: * instance of this component.
478: *
479: * @exception LifecycleException if this component detects a fatal error
480: * that needs to be reported
481: */
482: public void stop() throws LifecycleException {
483:
484: // unregister this logger
485: if (getObjectName() != null) {
486: ObjectName oname = createObjectName();
487: try {
488: Registry.getRegistry(null, null).unregisterComponent(
489: oname);
490: log.info("unregistering logger " + oname);
491: } catch (Exception ex) {
492: log.error("Can't unregister logger " + oname, ex);
493: }
494: }
495: }
496:
497: }
|