001: /*
002: * Created on 17.05.2005 for PIROL
003: *
004: * SVN header information:
005: * $Author: javamap $
006: * $Rev: 856 $
007: * $Date: 2007-06-18 21:15:27 -0700 (Mon, 18 Jun 2007) $
008: * $Id: GenericDebugLogger.java 856 2007-06-19 04:15:27Z javamap $
009: */
010: package de.fho.jump.pirol.utilities.debugOutput;
011:
012: import java.io.File;
013: import java.io.FileNotFoundException;
014: import java.io.FileOutputStream;
015: import java.io.IOException;
016: import java.io.PrintStream;
017: import java.util.Calendar;
018:
019: import de.fho.jump.pirol.utilities.Properties.PropertiesHandler;
020: import de.fho.jump.pirol.utilities.settings.PirolPlugInSettings;
021:
022: /**
023: * Class to handle debugging outputs. It is a singleton and keeps track of local debug settings and personal log levels.
024: * Configuration changes should not be done at runtime, but in the properties file ("debugging.properties") in the
025: * "[HOME]/.OpenJump_PIROL/config" directory. This file will be created when the logger is used the first time and filled
026: * with default values. For information on these values, please see commenting in the java source code.
027: *
028: * @author Ole Rahn, Stefan Ostermann
029: * <br>
030: * <br>FH Osnabrück - University of Applied Sciences Osnabrück,
031: * <br>Project: PIROL (2005),
032: * <br>Subproject: Daten- und Wissensmanagement
033: *
034: * @version $Rev: 856 $
035: *
036: * @see de.fhOsnabrueck.jump.pirol.PirolPlugInSettings
037: * @see PersonalLogger
038: */
039: public final class GenericDebugLogger {
040:
041: private static GenericDebugLogger logger = null;
042:
043: /**
044: * user Id for the logger object -> messages from this user are always displayed
045: */
046: private final static String loggerUserId = "GenericDebugLogger";
047:
048: /**
049: * Prefix for the username to store/read from the properties file
050: */
051: private final static String userFlagPrefix = "showMessagesOf_";
052:
053: protected PropertiesHandler properties = null;
054: protected static final String propertiesFile = "debugging.properties";
055:
056: // default values: only the most important messages will be put out
057: /**
058: * The logLevel specifies which kinds of messages will be put out. A message will
059: * be put out, if its severity is greater or equal to the log level (or if the user's
060: * log messages are enabled)
061: * <pre>
062: * logLevel severity sheme:
063: * 0 - debug - just an output for debugging purposes
064: * 1 - warning - something that might not be good happened
065: * 2 - minor error - an error that won't have influence on the results occured
066: * 3 - error - an error that may invalidate the current results occured
067: * 4 - severe error - an error that may invalidate the current and future results or may crash the VM, etc.
068: * </pre>
069: */
070: protected int logLevel = 1; // errors with effect on the results, only //sstein: set from 3 to 1
071: protected final static String KEY_LOGLEVEL = "logLevel";
072: /**Constant {@link #logLevel} for debugging purposes.*/
073: public final static int SEVERITY_DEBUG = 0;
074: /**Constant {@link #logLevel} for something that might not be good
075: * happened.*/
076: public final static int SEVERITY_WARNING = 1;
077: /**Constant {@link #logLevel} for an error that won't have influence on
078: * the results occured.*/
079: public final static int SEVERITY_MINORERROR = 2;
080: /**Constant {@link #logLevel} for an error that may invalidate the
081: * current results occured.*/
082: public final static int SEVERITY_ERROR = 3;
083: /**Constant {@link #logLevel} for an error that may invalidate the
084: * current and future results or may crash the VM, etc..*/
085: public final static int SEVERITY_SEVEREERROR = 4;
086:
087: protected final static String[] severityLevels = new String[] {
088: "DEBUG", "WARNING", "MIN.ERROR", "ERROR", "SEV.ERROR" };
089:
090: /**
091: * format the output string so that eclipse supports jumping into the
092: * correct file and line number when clicking on the output.
093: */
094: protected boolean eclipseFriendlyOutput = true;
095: protected final static String KEY_ECLIPSEFRIENDLYOUTPUT = "eclipseFriendlyOutput";
096:
097: /**
098: * wether or not to print time stamps in the messages
099: */
100: protected boolean printTimeStamp = false;
101: protected final static String KEY_PRINTTIMESTAMPS = "printTimeStamps";
102:
103: /**
104: * wether or not to print file name and line number in code
105: */
106: protected boolean printFileAndLine = true;
107: protected final static String KEY_PRINTFILEANDLINE = "printFileAndLineNumber";
108:
109: /**
110: * print additional line break before output of new messages?
111: */
112: protected boolean printNewLineFirst = false;
113: protected final static String KEY_PRINTNEWLINEFIRST = "printNewLineFirst";
114:
115: /**
116: * print short class names instead of class name plus the whole package path?
117: */
118: protected boolean printShortClassNames = true;
119: protected final static String KEY_PRINTSHORTCLASSNAMES = "printShortClassNames";
120:
121: /**
122: * print user names with every message?
123: */
124: protected boolean printUserNames = false;
125: protected final static String KEY_PRINTUSERNAMES = "printUserNames";
126:
127: protected PrintStream stdOut;
128: protected PrintStream stdErr;
129:
130: protected File logFile = null;
131: /**
132: * use a log file instead of printing messages to the console?
133: */
134: protected boolean useLogFile = true;
135: protected final static String KEY_USELOGFILE = "useLogFile";
136:
137: /**
138: * constructor is private, since we use the singleton pattern.
139: */
140: private GenericDebugLogger() {
141: this .setOutputStream(System.out);
142: this .setErrorStream(System.err);
143:
144: try {
145: this .loadProperties();
146: } catch (FileNotFoundException e) {
147: this .printMinorError(GenericDebugLogger.loggerUserId, e
148: .getMessage());
149: } catch (IOException e) {
150: this .printMinorError(GenericDebugLogger.loggerUserId, e
151: .getMessage());
152: }
153:
154: if (this .useLogFile) {
155: this .logFile = new File(PirolPlugInSettings.tempDirectory()
156: .getPath()
157: + File.separator + "session.log");
158: FileOutputStream fos = null;
159: try {
160: if (!logFile.exists()) {
161: try {
162: logFile.createNewFile();
163: } catch (IOException e) {
164: e.printStackTrace();
165: }
166: }
167: fos = new FileOutputStream(logFile);
168: PrintStream logFileStream = new PrintStream(fos);
169:
170: this .setOutputStream(logFileStream);
171: this .setErrorStream(logFileStream);
172: } catch (FileNotFoundException e) {
173: this .printWarning(GenericDebugLogger.loggerUserId,
174: "Problems using a log file: " + e.getMessage());
175: }
176:
177: }
178: }
179:
180: /**
181: * load local configuration file, to check if there are saved directorties for
182: * debugging outputs.
183: * @throws IOException if the file with the given file name could not be accessed
184: */
185: protected final void loadProperties() throws IOException {
186:
187: this .properties = new PropertiesHandler(
188: GenericDebugLogger.propertiesFile);
189: this .properties.load();
190:
191: this .logLevel = this .properties.getPropertyAsInt(
192: GenericDebugLogger.KEY_LOGLEVEL, this .logLevel);
193: this .printTimeStamp = this .properties.getPropertyAsBoolean(
194: GenericDebugLogger.KEY_PRINTTIMESTAMPS,
195: this .printTimeStamp);
196: this .printFileAndLine = this .properties.getPropertyAsBoolean(
197: GenericDebugLogger.KEY_PRINTFILEANDLINE,
198: this .printFileAndLine);
199: this .printNewLineFirst = this .properties.getPropertyAsBoolean(
200: GenericDebugLogger.KEY_PRINTNEWLINEFIRST,
201: this .printNewLineFirst);
202: this .printShortClassNames = this .properties
203: .getPropertyAsBoolean(
204: GenericDebugLogger.KEY_PRINTSHORTCLASSNAMES,
205: this .printShortClassNames);
206: this .printUserNames = this .properties.getPropertyAsBoolean(
207: GenericDebugLogger.KEY_PRINTUSERNAMES,
208: this .printUserNames);
209: this .useLogFile = this .properties.getPropertyAsBoolean(
210: GenericDebugLogger.KEY_USELOGFILE, this .useLogFile);
211: this .eclipseFriendlyOutput = this .properties
212: .getPropertyAsBoolean(
213: GenericDebugLogger.KEY_ECLIPSEFRIENDLYOUTPUT,
214: this .eclipseFriendlyOutput);
215:
216: this .properties.store(null);
217:
218: }
219:
220: /**
221: * check if the properties contain information on how to treat messages
222: * from this user
223: *@param user user id to check
224: *@return true, if Properties contain information on this user that allow posting his/her messages
225: */
226: protected final boolean showMessagesOfUser(String user) {
227: if (user.equals(GenericDebugLogger.loggerUserId))
228: return true;
229:
230: String userString = GenericDebugLogger.userFlagPrefix
231: + user.toLowerCase();
232: boolean allowMessagesFromUser = false;
233: allowMessagesFromUser = this .properties.getPropertyAsBoolean(
234: userString, allowMessagesFromUser);
235: try {
236: this .properties.store();
237: } catch (IOException e) {
238: this .printMinorError(GenericDebugLogger.loggerUserId, e
239: .getMessage());
240: }
241: return allowMessagesFromUser;
242: }
243:
244: /**
245: * THE method to get an instance of this class
246: *@return the logger
247: */
248: static final GenericDebugLogger getInstance() {
249: if (GenericDebugLogger.logger == null)
250: GenericDebugLogger.logger = new GenericDebugLogger();
251:
252: return GenericDebugLogger.logger;
253: }
254:
255: protected final void printMessage(String user, int severity,
256: String message) {
257: if (this .properties == null) {
258: try {
259: this .loadProperties();
260: } catch (IOException e) {
261: this .printError(GenericDebugLogger.loggerUserId,
262: "still can not load properties!");
263: return;
264: }
265: }
266: if (severity >= this .logLevel || this .showMessagesOfUser(user)) {
267: String outputString = this .printUserNames ? "(" + user
268: + ") " : "";
269:
270: outputString += GenericDebugLogger.severityLevels[severity]
271: + " in " + this .getCallerString(new Throwable());
272:
273: if (this .printTimeStamp == true) {
274: Calendar date = Calendar.getInstance();
275: outputString += "(" + date.get(Calendar.HOUR_OF_DAY)
276: + ":" + date.get(Calendar.MINUTE) + ":"
277: + date.get(Calendar.SECOND) + ","
278: + date.get(Calendar.MILLISECOND) + ")";
279: }
280:
281: outputString += ": "
282: + ((this .eclipseFriendlyOutput) ? "\n\t" : "")
283: + message;
284:
285: if (this .printNewLineFirst == true)
286: this .stdOut.println("---");
287:
288: if (severity < GenericDebugLogger.SEVERITY_MINORERROR)
289: this .stdOut.println(outputString);
290: else
291: this .stdErr.println(outputString);
292: }
293: }
294:
295: protected final String getCallerString(Throwable t) {
296: String caller = "";
297: String FileAndNumberSep = ":";
298: StackTraceElement[] elements = t.getStackTrace();
299:
300: for (int i = 0; i < elements.length; i++) {
301: if (elements[i].getClassName().equals(
302: GenericDebugLogger.class.getName()))
303: continue;
304: if (elements[i].getClassName().equals(
305: PersonalLogger.class.getName()))
306: continue;
307:
308: if (this .printShortClassNames
309: && elements[i].getClassName().indexOf(".") > -1
310: && !this .eclipseFriendlyOutput) {
311: caller = elements[i].getClassName()
312: .substring(
313: elements[i].getClassName().lastIndexOf(
314: ".") + 1);
315: } else {
316: caller = elements[i].getClassName();
317: }
318: // fill in method name
319: caller += "." + elements[i].getMethodName();// + "()";
320: if (!this .eclipseFriendlyOutput) {
321: caller += "()";
322: FileAndNumberSep = ",";
323: }
324:
325: if (this .printFileAndLine == true
326: || this .eclipseFriendlyOutput) {
327: caller += "(" + elements[i].getFileName()
328: + FileAndNumberSep
329: + elements[i].getLineNumber() + ") ";
330: }
331:
332: break;
333: }
334:
335: if (caller.length() == 0)
336: caller = "???";
337:
338: return caller;
339: }
340:
341: protected final void printDebug(String user, String message) {
342: this .printMessage(user, GenericDebugLogger.SEVERITY_DEBUG,
343: message);
344: }
345:
346: protected final void printWarning(String user, String message) {
347: this .printMessage(user, GenericDebugLogger.SEVERITY_WARNING,
348: message);
349: }
350:
351: protected final void printMinorError(String user, String message) {
352: this .printMessage(user, GenericDebugLogger.SEVERITY_MINORERROR,
353: message);
354: }
355:
356: protected final void printError(String user, String message) {
357: this .printMessage(user, GenericDebugLogger.SEVERITY_ERROR,
358: message);
359: }
360:
361: protected final void printSevereError(String user, String message) {
362: this .printMessage(user,
363: GenericDebugLogger.SEVERITY_SEVEREERROR, message);
364: }
365:
366: /**
367: *
368: *@return current log level
369: */
370: public final int getLogLevel() {
371: return logLevel;
372: }
373:
374: /**
375: *
376: * @param logLevel
377: */
378: public final void setLogLevel(int logLevel) {
379: this .logLevel = logLevel;
380: this .properties.setProperty(GenericDebugLogger.KEY_LOGLEVEL,
381: new Integer(logLevel).toString());
382: try {
383: this .properties.store();
384: } catch (IOException e) {
385: this .printError(GenericDebugLogger.loggerUserId, e
386: .getMessage());
387: }
388: }
389:
390: /**
391: *
392: * @return true or false //TODO specify the return value
393: */
394: public final boolean isPrintFileAndLine() {
395: return printFileAndLine;
396: }
397:
398: /**
399: *
400: * @return true or false //TODO specify the return value
401: */
402: public final boolean isPrintNewLineFirst() {
403: return printNewLineFirst;
404: }
405:
406: /**
407: *
408: * @return true or false //TODO specify the return value
409: */
410: public final boolean isPrintTimeStamp() {
411: return printTimeStamp;
412: }
413:
414: /**
415: *@return File name of the file where logger configuration is stored
416: */
417: public final String getPropertiesFile() {
418: return propertiesFile;
419: }
420:
421: /**
422: * Set the stream, where messages with a loglevel < SEVERITY_MINORERROR are put out.
423: *@param out stream for debugging output
424: */
425: public final void setOutputStream(PrintStream out) {
426: this .stdOut = out;
427: this .stdOut.print("\n");
428: }
429:
430: /**
431: * Set the stream, where messages with a loglevel >= SEVERITY_MINORERROR are put out.
432: *@param err stream for debugging output
433: */
434: public final void setErrorStream(PrintStream err) {
435: this .stdErr = err;
436: this .stdErr.print("\n");
437: }
438: }
|