001: package org.esupportail.cas.server.util.log;
002:
003: import java.io.UnsupportedEncodingException;
004: import java.net.URLDecoder;
005: import java.util.LinkedList;
006: import java.util.List;
007:
008: import org.apache.log4j.Logger;
009: import org.apache.log4j.BasicConfigurator;
010:
011: import org.apache.log4j.Category;
012: import org.apache.log4j.xml.DOMConfigurator;
013: import org.esupportail.cas.server.GenericHandler;
014:
015: //---------------------------------------------------------
016:
017: /**
018: * This abstract class offers a clear debug log
019: *
020: * @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>
021: */
022: public final class Log {
023:
024: /**
025: * Constructor (no instanciation).
026: */
027: private Log() {
028: }
029:
030: /**
031: * Logging object.
032: */
033: private static Category log = null;
034:
035: /**
036: * A list to store the names of the classes used for logging.
037: */
038: private static List logClasses;
039:
040: /**
041: * The height of the stack not to watch to indent output.
042: */
043: private static int baseStackLevel = 0;
044:
045: /**
046: * The config filename of the logger
047: */
048: private static String confilename = null;
049:
050: /**
051: * Initialize the logger (done only once).
052: */
053: public static void init() {
054: if (log == null) {
055: System.err
056: .println("initializing CAS GenericHandler Logger...");
057: String loggerXmlFileName = getConfigLogFileName("/../LoggerConf.xml");
058: if (loggerXmlFileName == null) {
059: System.err
060: .println("CAS GenericHandler Logger configuration file is missing, "
061: + "setting default configuration...");
062: BasicConfigurator.configure();
063: log = Logger.getLogger("CASGH");
064: } else {
065: // decode string to allow paths with spaces (since version 2.0.4)
066: // J-Louis.RENAUD at univ-bpclermont.fr
067: String str = null;
068: try {
069: str = URLDecoder.decode(loggerXmlFileName, "UTF-8");
070: DOMConfigurator.configureAndWatch(str);
071: log = Category.getRoot();
072: } catch (UnsupportedEncodingException e) {
073: System.err
074: .println("CAS GenericHandler Logger configuration filename could "
075: + "not be decoded, setting default configuration...");
076: BasicConfigurator.configure();
077: log = Logger.getLogger("CASGH");
078: }
079: }
080: // set the names of the classes that should be skipped in the execution stack
081: logClasses = new LinkedList();
082: logClasses.add("org.esupportail.cas.server.util.log.Log");
083: logClasses.add("org.esupportail.cas.server.util.log.Debug");
084: // get the base stack lvel
085: baseStackLevel = getCallingStackLevel();
086: System.err.println("done.");
087: }
088: }
089:
090: /**
091: * Retrieve the absolute filename of the file storing the configuration of Logger.
092: *
093: * @param filename the name of the configuration file (resource-dependent)
094: *
095: * @return a string.
096: */
097: private static String getConfigLogFileName(final String filename) {
098: java.net.URL resourceURL;
099:
100: if (confilename == null) {
101: try {
102: resourceURL = GenericHandler.class
103: .getResource(filename);
104: // if configuration file is missing an exception is thrown and the cas server crashes
105: confilename = resourceURL.getFile();
106: } catch (NullPointerException e) {
107: // resourceURL was null
108: System.err
109: .println("configuration file LoggerConf.xml is missing!");
110: return null;
111: }
112: }
113: return confilename;
114: }
115:
116: /**
117: * Retrieve the level of the calling method in the execution stack.
118: *
119: * @return an integer.
120: */
121: private static int getCallingStackLevel() {
122: StackTraceElement[] stack = new Exception().getStackTrace();
123:
124: String className = null;
125: String methodName = null;
126: String fileName = null;
127: int lineNumber = 0;
128: for (int i = 0; i < stack.length; i++) {
129: StackTraceElement ste = stack[i];
130: if (logClasses.contains(ste.getClassName())) {
131: continue;
132: }
133: return stack.length - i;
134: }
135: return -1;
136: }
137:
138: /**
139: * Retrieve the stack element corresponding to the calling method.
140: *
141: * @return a StackTraceElement instance.
142: */
143: private static StackTraceElement getCallingStackElement() {
144: StackTraceElement[] stack = new Exception().getStackTrace();
145:
146: String className = null;
147: String methodName = null;
148: String fileName = null;
149: int lineNumber = 0;
150: for (int i = 0; i < stack.length; i++) {
151: StackTraceElement ste = stack[i];
152: if (logClasses.contains(ste.getClassName())) {
153: continue;
154: }
155: return ste;
156: }
157: return null;
158: }
159:
160: /**
161: * Output a string as an information (INFO).
162: *
163: * @param str a string
164: */
165: public static void info(final String str) {
166: init();
167: log.info(str);
168: }
169:
170: /**
171: * Output a string as a warning (WARN).
172: *
173: * @param str a string
174: */
175: public static void warn(final String str) {
176: init();
177: log.warn(str);
178: }
179:
180: /**
181: * Output a string as an error (SEVERE).
182: *
183: * @param str a string
184: */
185: public static void error(final String str) {
186: init();
187: log.error(str);
188: }
189:
190: /**
191: * Get indentation prefix (depends on the current stack).
192: *
193: * @return a string.
194: */
195: private static String getIndentPrefix() {
196: return getIndentPrefix(0);
197: }
198:
199: /**
200: * Get indentation prefix (depends on the current stack), modifying the level.
201: *
202: * @param level 0 to set normal indentation, -1 to remove one level, ...
203: *
204: * @return a string.
205: */
206: private static String getIndentPrefix(final int level) {
207: StringBuffer buf = new StringBuffer();
208: int localLevel = getCallingStackLevel() - baseStackLevel
209: + level;
210: for (int i = 0; i < localLevel; i++) {
211: buf.append("| ");
212: }
213: return buf.toString();
214: }
215:
216: /**
217: * Output a string as a trace (DEBUG).
218: *
219: * @param str a string
220: */
221: public static void debug(final String str) {
222: debug(str, 0);
223: }
224:
225: /**
226: * Output a string as a trace (DEBUG), modifying the indentation.
227: *
228: * @param str a string
229: * @param level 0 to set normal indentation, -1 to remove one level, ...
230: */
231: public static void debug(final String str, final int level) {
232: init();
233: log.debug(getIndentPrefix(level) + str);
234: }
235:
236: /**
237: * Debugging (beginning of the execution of a method).
238: */
239: public static void traceBegin() {
240: StackTraceElement ste = getCallingStackElement();
241: String[] classNameElements = ste.getClassName().split("\\.");
242: String classBaseName = classNameElements[classNameElements.length - 1];
243: StringBuffer buf = new StringBuffer("=> " + classBaseName
244: + "::" + ste.getMethodName() + "()");
245: if (ste.getFileName() != null) {
246: buf.append(" [" + ste.getFileName() + ":"
247: + String.valueOf(ste.getLineNumber()) + "]");
248: }
249: debug(buf.toString(), -1);
250: }
251:
252: /**
253: * Debugging (a string at the end of the execution of a method).
254: *
255: * @param str a string
256: */
257: public static void traceEnd(final String str) {
258: debug("<= " + str, -1);
259: }
260:
261: }
|