001: /*
002: *
003: */
004:
005: package org.enhydra.dm.api.loggers;
006:
007: import java.io.InputStream;
008: import java.io.PrintWriter;
009: import java.io.StringWriter;
010: import java.text.DateFormat;
011: import java.text.MessageFormat;
012: import java.util.Date;
013: import java.util.Enumeration;
014: import java.util.Properties;
015:
016: /**
017: * Provides logging utility functionality. A provider can extend this class and is
018: * specified by the "org.enhydra.dm.util.Log" system property.
019: */
020: public abstract class Log {
021:
022: /**
023: * Logging threshold indicating everything should be logged.
024: */
025: public static final int DEBUG = 0;
026:
027: /**
028: * Logging threshold indicating useful information should be logged.
029: */
030: public static final int INFORMATION = 1;
031:
032: /**
033: * Logging threshold indicating warnings should be logged.
034: */
035: public static final int WARNING = 2;
036:
037: /**
038: * Logging threshold indicating errors should be logged.
039: */
040: public static final int ERROR = 3;
041:
042: /**
043: * Logging threshold indicating critical errors should be logged.
044: */
045: public static final int CRITICAL = 4;
046:
047: /**
048: * Logging threshold indicating nothing should be logged.
049: */
050: public static final int NOTHING = Integer.MAX_VALUE;
051:
052: private static final String RESOURCE = Log.class.getName();
053:
054: private static Log instance = null;
055:
056: private static boolean logFailureDetected = false;
057:
058: private int logThreshold = DEBUG;
059:
060: /**
061: * Constructed provided for subclasses.
062: */
063: protected Log() {
064: }
065:
066: /**
067: * Returns the current logging threshold.
068: *
069: * @return an <code>int</code> containing the current threshold value.
070: */
071: public int getThreshold() {
072: return getInstance().getLogThreshold();
073: }
074:
075: /**
076: * Sets the current logging threshold.
077: *
078: * @param threshold The new logging threshold value.
079: */
080: public void setThreshold(int threshold) {
081: getInstance().setLogThreshold(threshold);
082: }
083:
084: /**
085: * Logs an object for the specified level.
086: *
087: * @param level The logging level.
088: * @param arg The argument object. <code>String</code>s will be logged directly;
089: * <code>Throwable</code>s will log a stack trace.
090: */
091: public void log(int level, Object arg) {
092: getInstance().doLog(level, arg);
093: }
094:
095: /**
096: * Logs a message with an argument object for the specified level.
097: *
098: * @param level The logging level.
099: * @param message The message. This can contain format arguments, i.e. "{0}".
100: * @param arg The argument object. A <code>String</code> will be interpreted as a
101: * single format value. A <code>Throwable</code> will use the associated
102: * stack trace as the format value. A <code>Object[]</code> will be
103: * interpreted as a set of format values (i.e., "{0}", "{1}", etc.).
104: */
105: public void log(int level, String message, Object arg) {
106: getInstance().doLog(level, message, arg);
107: }
108:
109: public static void setLogger(Log logger) {
110: instance = logger;
111: }
112:
113: public static Log getInstance() {
114: if (instance != null)
115: return instance;
116: synchronized (Log.class) {
117: Log log = null;
118: String instanceClass = null;
119: try {
120: instanceClass = System.getProperty(Log.class.getName());
121: if (instanceClass == null) {
122: InputStream resource = Log.class
123: .getResourceAsStream(RESOURCE);
124: if (resource == null) {
125: resource = ClassLoader
126: .getSystemResourceAsStream(RESOURCE);
127: }
128: if (resource != null) {
129: Properties properties = new Properties();
130: properties.load(resource);
131: Enumeration propertyNames = properties
132: .propertyNames();
133: if (propertyNames.hasMoreElements()) {
134: instanceClass = (String) propertyNames
135: .nextElement();
136: }
137: }
138: }
139: } catch (Exception ex) {
140: }
141: if (instanceClass != null) {
142: try {
143: log = (Log) Class.forName(instanceClass)
144: .newInstance();
145: } catch (Exception ex) {
146: log = new DefaultLog();
147: log.doLog(NOTHING, "Invalid Log class!");
148: }
149: }
150: if (log == null)
151: log = new DefaultLog();
152: try {
153: String logThreshold = System.getProperty(Log.class
154: .getName()
155: + ".threshold");
156: if (logThreshold != null) {
157: try {
158: logThreshold = logThreshold.toUpperCase();
159: Integer value = (Integer) Log.class.getField(
160: logThreshold).get(null);
161: log.setLogThreshold(value.intValue());
162: } catch (Exception badConstant) {
163: try {
164: log.setLogThreshold(Integer
165: .parseInt(logThreshold));
166: } catch (Exception badNumber) {
167: log.setLogThreshold(DEBUG);
168: log.doLog(DEBUG, "Invalid Treshold!");
169: }
170: }
171: }
172: } catch (Exception ex) {
173: }
174: return (instance = log);
175: }
176: }
177:
178: /**
179: * Returns the current logging threshold.
180: *
181: * @return an <code>int</code> containing the current threshold value.
182: */
183: protected int getLogThreshold() {
184: return logThreshold;
185: }
186:
187: private void setLogThreshold(int logThreshold) {
188: this .logThreshold = logThreshold;
189: }
190:
191: private void doLog(int level, Object arg) {
192: if (level < getLogThreshold() || arg == null)
193: return;
194: if (!(arg instanceof Throwable)) {
195: doLog(level, String.valueOf(arg), (Object[]) null);
196: return;
197: }
198: Throwable throwable = (Throwable) arg;
199: String message = throwable.getMessage();
200: message = (message != null) ? message + ": {0}" : "{0}";
201: StringWriter sw = new StringWriter();
202: PrintWriter writer = new PrintWriter(sw);
203: throwable.printStackTrace(writer);
204: writer.flush();
205: doLog(level, message, sw);
206: }
207:
208: private void doLog(int level, String message, Object arg) {
209: if (level < getLogThreshold())
210: return;
211: if (arg instanceof Object[]) {
212: doLog(level, message, (Object[]) arg);
213: return;
214: }
215: if (!(arg instanceof Throwable)) {
216: doLog(level, message, new Object[] { arg });
217: return;
218: }
219: Throwable throwable = (Throwable) arg;
220: if (message == null) {
221: if (throwable == null)
222: return;
223: message = throwable.getMessage();
224: message = (message != null) ? message + ": {0}" : "{0}";
225: }
226: if (throwable != null) {
227: StringWriter sw = new StringWriter();
228: PrintWriter writer = new PrintWriter(sw);
229: throwable.printStackTrace(writer);
230: writer.flush();
231: doLog(level, message, new Object[] { sw });
232: } else {
233: doLog(level, message, (Object[]) null);
234: }
235: }
236:
237: private void doLog(int level, String message, Object[] args) {
238: if (level < getLogThreshold() || message == null)
239: return;
240: if (args != null) {
241: try {
242: message = MessageFormat.format(message, args);
243: } catch (Exception ex) {
244: }
245: }
246: try {
247: synchronized (this ) {
248: logMessage(level, message);
249: }
250: } catch (Throwable logFailure) {
251: synchronized (Log.class) {
252: if (logFailureDetected) {
253: throw new IllegalStateException(
254: "Log failure detected!");
255: }
256: logFailureDetected = true;
257: Log log = new DefaultLog();
258: log.setLogThreshold(DEBUG);
259: log.doLog(DEBUG, "Log feilure");// ?
260: instance = log;
261: }
262: }
263: }
264:
265: /**
266: * Logs the specified message at the provided level.
267: *
268: * @param level The logging level.
269: * @param message The message that is to be logged.
270: */
271: protected abstract void logMessage(int level, String message);
272:
273: private static class DefaultLog extends Log {
274:
275: protected void logMessage(int level, String message) {
276: StringBuffer output = new StringBuffer();
277: switch (level) {
278: case DEBUG:
279: output.append("DEBUG [");
280: break;
281: case INFORMATION:
282: output.append("INFORMATION [");
283: break;
284: case WARNING:
285: output.append("WARNING [");
286: break;
287: case ERROR:
288: output.append("ERROR [");
289: break;
290: case CRITICAL:
291: output.append("CRITICAL [");
292: break;
293: default:
294: output.append("UNKNOWN [");
295: }
296: DateFormat format = DateFormat.getDateTimeInstance(
297: DateFormat.SHORT, DateFormat.SHORT);
298: output.append(format.format(new Date())).append("]: ");
299: output.append(message);
300: System.out.println(output);
301: }
302:
303: }
304:
305: }
|