001: /*
002: * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
003: * Copyright (C) 2006 - Javolution (http://javolution.org/)
004: * All rights reserved.
005: *
006: * Permission to use, copy, modify, and distribute this software is
007: * freely granted, provided that this notice is preserved.
008: */
009: package javolution.context;
010:
011: import javolution.Javolution;
012: import javolution.lang.Configurable;
013: import javolution.util.StandardLog;
014: import j2me.lang.CharSequence;
015:
016: /**
017: * <p> This class represents a context for object-based/thread-based logging
018: * capabilities.</p>
019: *
020: * <p> The {@link #DEFAULT default} logging context is {@link
021: * StandardLog StandardLog} to leverage <code>java.util.logging</code>
022: * capabilities.</p>
023: *
024: * <p> Logging can be temporarily modified on a thread or object basis.
025: * For example:[code]
026: * public static main(String[] args) {
027: * LogContext.enter(LogContext.NULL); // Temporarily disables logging.
028: * try {
029: * ClassInitializer.initializeAll(); // Initializes bootstrap, extensions and classpath classes.
030: * } finally {
031: * LogContext.exit(LogContext.NULL); // Goes back to default logging.
032: * }
033: * ...
034: * }[/code]</p>
035: *
036: * <p> Applications may extend this base class to address specific logging
037: * requirements. For example:[code]
038: * // This class allows for custom logging of session events.
039: * public abstract class SessionLog extends LogContext {
040: * public static void start(Session session) {
041: * LogContext log = LogContext.current();
042: * if (log instanceof SessionLog.Loggable) {
043: * ((SessionLog.Loggable)log).logStart(session);
044: * } else if (log.isInfoLogged()){
045: * log.logInfo("Session " + session.id() + " started");
046: * }
047: * }
048: * public static void end(Session session) { ... }
049: * public interface Loggable {
050: * void logStart(Session session);
051: * void logEnd(Session session);
052: * }
053: * }[/code]</p>
054: *
055: * <p> The use of interfaces (such as <code>Loggable</code> above) makes it easy
056: * for any context to support customs logging events.
057: * For example:[code]
058: * class MyLog extends StandardLog implements SessionLog.Loggable, DatabaseLog.Loggable {
059: * ... // Specialized logging for session and database events.
060: * }
061: * MyLog myLog = new MyLog();
062: * LogContext.enter(myLog);
063: * try {
064: * ...
065: * LogContext.info("Informative message"); // Standard logging.
066: * ...
067: * DatabaseLog.fail(transaction); // Database custom logging.
068: * ...
069: * SessionLog.start(session); // Session custom logging.
070: * ...
071: * } finally {
072: * LogContext.exit(myLog);
073: * }[/code]</p>
074: *
075: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
076: * @version 5.2, August 5, 2007
077: */
078: public abstract class LogContext extends Context {
079:
080: /**
081: * Holds the default logging context instance.
082: */
083: private static volatile LogContext _Default = new StandardLog();
084:
085: /**
086: * Holds the logging context implementation forwarding log events to the
087: * root <code>java.util.logging.Logger</code> (default logging context).
088: * The info/warning/error events are mapped to the info/warning/severe
089: * log levels respectively.
090: */
091: public static final Class/*<? extends LogContext>*/STANDARD = _Default
092: .getClass();
093:
094: /**
095: * Holds a logging context implementation ignoring logging events.
096: */
097: public static final Class/*<? extends LogContext>*/NULL = new NullLog()
098: .getClass();
099:
100: /**
101: * Holds a context logging messages to <code>System.out</code>.
102: */
103: public static final Class/*<? extends LogContext>*/SYSTEM_OUT = new SystemOut()
104: .getClass();
105:
106: /**
107: * Holds a context logging informative/warnings/errors events to
108: * the system console.
109: */
110: public static final Class/*<? extends LogContext>*/CONSOLE = new ConsoleLog()
111: .getClass();
112:
113: /**
114: * Holds the logging context default implementation (configurable,
115: * default value {@link #STANDARD}).
116: */
117: public static final Configurable/*<Class<? extends LogContext>>*/
118: DEFAULT = new Configurable(STANDARD) {
119: protected void notifyChange() {
120: _Default = (LogContext) ObjectFactory.getInstance(
121: (Class) get()).object();
122: }
123: };
124:
125: /**
126: * Default constructor.
127: */
128: protected LogContext() {
129: }
130:
131: /**
132: * Returns the current logging context. If the current thread has not
133: * entered any logging context the {@link #getDefault()} is returned.
134: *
135: * @return the current logging context.
136: */
137: public static/*LogContext*/Context getCurrent() {
138: for (Context ctx = Context.getCurrent(); ctx != null; ctx = ctx
139: .getOuter()) {
140: if (ctx instanceof LogContext)
141: return (LogContext) ctx;
142: }
143: return LogContext._Default;
144: }
145:
146: /**
147: * Returns the default instance ({@link #DEFAULT} implementation).
148: *
149: * @return the default instance.
150: */
151: public static LogContext getDefault() {
152: return LogContext._Default;
153: }
154:
155: /**
156: * Logs the specified informative message.
157: *
158: * @param message the informative message being logged.
159: * @see #logInfo(CharSequence)
160: */
161: public static void info(CharSequence message) {
162: LogContext logContext = (LogContext) LogContext.getCurrent();
163: logContext.logInfo(message);
164: }
165:
166: /**
167: * Equivalent to {@link #info(CharSequence)} (for J2ME compatibility).
168: */
169: public static void info(String message) {
170: LogContext logContext = (LogContext) LogContext.getCurrent();
171: logContext.logInfo(message);
172: }
173:
174: /**
175: * Logs the specified warning message to the current logging context.
176: *
177: * @param message the warning message being logged.
178: * @see #logWarning(CharSequence)
179: */
180: public static void warning(CharSequence message) {
181: LogContext logContext = (LogContext) LogContext.getCurrent();
182: logContext.logWarning(message);
183: }
184:
185: /**
186: * Equivalent to {@link #warning(CharSequence)} (for J2ME compatibility).
187: */
188: public static void warning(String message) {
189: LogContext logContext = (LogContext) LogContext.getCurrent();
190: logContext.logWarning(message);
191: }
192:
193: /**
194: * Logs the specified error to the current logging context.
195: *
196: * @param error the error being logged.
197: */
198: public static void error(Throwable error) {
199: LogContext logContext = (LogContext) LogContext.getCurrent();
200: logContext.logError(error, (CharSequence) null);
201: }
202:
203: /**
204: * Logs the specified error and error message to the current logging
205: * context.
206: *
207: * @param error the error being logged.
208: * @param message the supplementary message.
209: */
210: public static void error(Throwable error, CharSequence message) {
211: LogContext logContext = (LogContext) LogContext.getCurrent();
212: logContext.logError(error, message);
213: }
214:
215: /**
216: * Equivalent to {@link #error(Throwable, CharSequence)}
217: * (for J2ME compatibility).
218: */
219: public static void error(Throwable error, String message) {
220: LogContext logContext = (LogContext) LogContext.getCurrent();
221: logContext.logError(error, message);
222: }
223:
224: /**
225: * Logs the specified error message to the current logging
226: * context.
227: *
228: * @param message the error message being logged.
229: */
230: public static void error(CharSequence message) {
231: LogContext logContext = (LogContext) LogContext.getCurrent();
232: logContext.logError(null, message);
233: }
234:
235: /**
236: * Equivalent to {@link #error(CharSequence)} (for J2ME compatibility).
237: */
238: public static final void error(String message) {
239: LogContext logContext = (LogContext) LogContext.getCurrent();
240: logContext.logError(null, message);
241: }
242:
243: /**
244: * Indicates if informative messages are logged.
245: *
246: * @return <code>true</code> if informative messages are logged;
247: * <code>false</code> otherwise.
248: */
249: public abstract boolean isInfoLogged();
250:
251: /**
252: * Logs the specified informative message.
253: *
254: * @param message the informative message being logged.
255: */
256: public abstract void logInfo(CharSequence message);
257:
258: /**
259: * Equivalent to {@link #logInfo(CharSequence)} (for J2ME compatibility).
260: */
261: public final void logInfo(String message) {
262: logInfo(Javolution.j2meToCharSeq(message));
263: }
264:
265: /**
266: * Indicates if warning messages are logged.
267: *
268: * @return <code>true</code> if warnings message are logged;
269: * <code>false</code> otherwise.
270: */
271: public abstract boolean isWarningLogged();
272:
273: /**
274: * Logs the specified warning message.
275: *
276: * @param message the warning message being logged.
277: */
278: public abstract void logWarning(CharSequence message);
279:
280: /**
281: * Equivalent to {@link #logWarning(CharSequence)} (for J2ME compatibility).
282: */
283: public final void logWarning(String message) {
284: logWarning(Javolution.j2meToCharSeq(message));
285: }
286:
287: /**
288: * Indicates if errors are logged.
289: *
290: * @return <code>true</code> if errors are logged;
291: * <code>false</code> otherwise.
292: */
293: public abstract boolean isErrorLogged();
294:
295: /**
296: * Logs the specified error.
297: *
298: * @param error the error being logged or <code>null</code> if none.
299: * @param message the associated message or <code>null</code> if none.
300: */
301: public abstract void logError(Throwable error, CharSequence message);
302:
303: /**
304: * Equivalent to {@link #logError(Throwable, CharSequence)}
305: * (for J2ME compatibility).
306: */
307: public final void logError(Throwable error, String message) {
308: logError(error, Javolution.j2meToCharSeq(message));
309: }
310:
311: // Implements Context abstract method.
312: protected void enterAction() {
313: // Do nothing.
314: }
315:
316: // Implements Context abstract method.
317: protected void exitAction() {
318: // Do nothing.
319: }
320:
321: /**
322: * This class represents the system logging context.
323: */
324: private static class SystemOut extends LogContext {
325:
326: public boolean isInfoLogged() {
327: return true;
328: }
329:
330: public void logInfo(CharSequence message) {
331: System.out.print("[info] ");
332: System.out.println(message);
333: }
334:
335: public boolean isWarningLogged() {
336: return true;
337: }
338:
339: public void logWarning(CharSequence message) {
340: System.out.print("[warning] ");
341: System.out.println(message);
342: }
343:
344: public boolean isErrorLogged() {
345: return true;
346: }
347:
348: public void logError(Throwable error, CharSequence message) {
349: System.out.print("[error] ");
350: if (error != null) {
351: System.out.print(error.getClass().getName());
352: System.out.print(" - ");
353: }
354: String description = (message != null) ? message.toString()
355: : (error != null) ? error.getMessage() : "";
356: System.out.println(description);
357: if (error != null) {
358: error.printStackTrace();
359: }
360: }
361: }
362:
363: /**
364: * This class represents a non-logging context.
365: */
366: private static final class NullLog extends SystemOut {
367:
368: public boolean isInfoLogged() {
369: return false;
370: }
371:
372: public void logInfo(CharSequence message) {
373: // Do nothing.
374: }
375:
376: public boolean isWarningLogged() {
377: return false;
378: }
379:
380: public void logWarning(CharSequence message) {
381: // Do nothing.
382: }
383:
384: public boolean isErrorLogged() {
385: return false;
386: }
387:
388: public void logError(Throwable error, CharSequence message) {
389: // Do nothing.
390: }
391: }
392:
393: /**
394: * This class represents the console logging context.
395: */
396: private static class ConsoleLog extends SystemOut {
397: /*@JVM-1.6+@
398: final java.io.PrintWriter writer;
399: ConsoleLog() {
400: java.io.Console console = System.console();
401: writer = console != null ? console.writer() : null;
402: }
403:
404: public void logInfo(CharSequence message) {
405: if (writer == null) {
406: super.logInfo(message);
407: } else {
408: writer.print("[info] ");
409: writer.println(message);
410: }
411: }
412:
413: public void logWarning(CharSequence message) {
414: if (writer == null) {
415: super.logWarning(message);
416: } else {
417: writer.print("[warning] ");
418: writer.println(message);
419: }
420: }
421:
422: public void logError(Throwable error, CharSequence message) {
423: if (writer == null) {
424: super.logError(error, message);
425: } else {
426: writer.print("[error] ");
427: if (error != null) {
428: writer.print(error.getClass().getName());
429: writer.print(" - ");
430: }
431: String description = (message != null) ? message.toString()
432: : (error != null) ? error.getMessage() : "";
433: writer.println(description);
434: writer.println();
435: }
436: }
437: /**/
438: }
439:
440: // Allows instances of private classes to be factory produced.
441: static {
442: ObjectFactory.setInstance(new ObjectFactory() {
443: protected Object create() {
444: return new ConsoleLog();
445: }
446: }, CONSOLE);
447: ObjectFactory.setInstance(new ObjectFactory() {
448: protected Object create() {
449: return new NullLog();
450: }
451: }, NULL);
452: ObjectFactory.setInstance(new ObjectFactory() {
453: protected Object create() {
454: return new SystemOut();
455: }
456: }, SYSTEM_OUT);
457: }
458: }
|