001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
027: */
028:
029: package org.netbeans.lib.uihandler;
030:
031: import java.awt.Component;
032: import java.io.File;
033: import java.net.MalformedURLException;
034: import java.net.URL;
035: import java.util.Arrays;
036: import java.util.Calendar;
037: import java.util.Collections;
038: import java.util.Date;
039: import java.util.GregorianCalendar;
040: import java.util.Iterator;
041: import java.util.List;
042: import java.util.ResourceBundle;
043: import java.util.logging.Level;
044: import java.util.logging.LogRecord;
045: import java.util.logging.Logger;
046: import java.util.logging.XMLFormatter;
047: import javax.swing.AbstractButton;
048: import javax.swing.Action;
049: import javax.swing.JMenuItem;
050: import org.openide.util.Lookup;
051: import static java.util.Calendar.*;
052:
053: /**this class uses most of XML Formater code, but it adds cause of throwable
054: *
055: * @author Jindrich Sedek
056: */
057: class LogFormatter extends XMLFormatter {
058: private String javaHome;
059: private String userHome;
060: private String netbeansUserDir;
061: private String netbeansHome;
062: private List<String> installDirs;
063:
064: /** Creates a new instance of LogFormatter */
065: public LogFormatter() {
066: javaHome = convert(System.getProperty("java.home", ""));// NOI18N
067: userHome = convert(System.getProperty("user.home", ""));// NOI18N
068: netbeansUserDir = convert(System.getProperty("netbeans.user",
069: ""));// NOI18N
070: netbeansHome = convert(System.getProperty("netbeans.home", ""));// NOI18N
071: String nbdirsStr = System.getProperty("netbeans.dirs");// NOI18N
072: if (nbdirsStr != null) {
073: String[] fields = nbdirsStr.split(File.pathSeparator);
074: for (int i = 0; i < fields.length; i++) {
075: fields[i] = convert(fields[i]);
076: }
077: installDirs = Arrays.asList(fields);
078: } else {
079: installDirs = Collections.emptyList();
080: }
081: }
082:
083: private String convert(String str) {
084: try {
085: return new File(str).toURI().toURL().toString();
086: } catch (MalformedURLException exc) {
087: Logger.getLogger(LogFormatter.class.getName()).log(
088: Level.INFO, "unaccessible file", exc);// NOI18N
089: }
090: return "";
091: }
092:
093: private void a2(StringBuffer sb, int x) {
094: if (x < 10) {
095: sb.append('0');
096: }
097: sb.append(x);
098: }
099:
100: private void escape(StringBuffer sb, String text) {
101: if (text == null) {
102: text = "<null>";// NOI18N
103: }
104: for (int i = 0; i < text.length(); i++) {
105: char ch = text.charAt(i);
106: if (ch == '<') {
107: sb.append("<");// NOI18N
108: } else if (ch == '>') {
109: sb.append(">");// NOI18N
110: } else if (ch == '&') {
111: sb.append("&");// NOI18N
112: } else if (ch < 0x20 && ch != '\t' && ch != '\r'
113: && ch != '\n') { // #119820
114: sb.append('^').append((char) (ch + 0x40));
115: } else {
116: sb.append(ch);
117: }
118: }
119: }
120:
121: private void printFrame(StackTraceElement frame, StringBuffer sb) {
122: sb.append(" <frame>\n");// NOI18N
123: sb.append(" <class>");// NOI18N
124: escape(sb, frame.getClassName());
125: sb.append("</class>\n");// NOI18N
126: sb.append(" <method>");// NOI18N
127: escape(sb, frame.getMethodName());
128: sb.append("</method>\n");// NOI18N
129: // Check for a line number.
130: if (frame.getLineNumber() >= 0) {
131: sb.append(" <line>");// NOI18N
132: sb.append(frame.getLineNumber());
133: sb.append("</line>\n");// NOI18N
134: }
135: sb.append(" <file>");// NOI18N
136: ClassLoader loader = Lookup.getDefault().lookup(
137: ClassLoader.class);
138: Class clazz = null;
139: URL jarName = null;
140: String fileName = null;
141: try {
142: clazz = loader.loadClass(frame.getClassName());
143: } catch (Throwable exc) {
144: Logger.getLogger(LogFormatter.class.getName()).log(
145: Level.FINE, "Class loading error", exc);// NOI18N
146: }
147: if (clazz != null) {
148: String[] fields = clazz.getName().split("\\.");// NOI18N
149: if (fields.length > 0) {
150: jarName = clazz.getResource(fields[fields.length - 1]
151: + ".class");// NOI18N
152: }
153: if (jarName != null) {
154: fileName = jarName.toString();
155: int index = fileName.indexOf("!");// NOI18N
156: if (index != -1) {
157: fileName = fileName.substring(0, index);
158: }
159: fileName = fileName.replace("jar:", "");// NOI18N
160: if (javaHome.length() > 0) {
161: fileName = fileName.replace(javaHome,
162: "${java.home}");// NOI18N
163: }
164: if (netbeansHome.length() > 0) {
165: fileName = fileName.replace(netbeansHome,
166: "${netbeans.home}");// NOI18N
167: }
168: if (netbeansUserDir.length() > 0) {
169: fileName = fileName.replace(netbeansUserDir,
170: "${user.dir}");// NOI18N
171: }
172: for (Iterator<String> it = installDirs.iterator(); it
173: .hasNext();) {
174: String nextDir = it.next();
175: fileName = fileName.replace(nextDir,
176: "${netBeansDir}");// NOI18N
177: }
178: if (userHome.length() > 0) {
179: fileName = fileName.replace(userHome,
180: "${user.home}");// NOI18N
181: }
182: fileName = fileName.replace("file:", "");// NOI18N
183: fileName = fileName.replace("nbjcl:", "");// NOI18N
184: escape(sb, fileName);
185: }
186: }
187: sb.append("</file>\n");// NOI18N
188: sb.append(" </frame>\n");// NOI18N
189: }
190:
191: private void printCause(Throwable th, StringBuffer sb,
192: StackTraceElement[] causedTrace) {
193: sb.append(" <exception>\n");// NOI18N
194: sb.append(" <message>");// NOI18N
195: escape(sb, th.toString());
196: sb.append("</message>\n");// NOI18N
197: StackTraceElement[] trace = th.getStackTrace();
198: int m = trace.length - 1;
199: int n = causedTrace.length - 1;
200: while (m >= 0 && n >= 0 && trace[m].equals(causedTrace[n])) {
201: m--;
202: n--;
203: }
204: int framesInCommon = trace.length - 1 - m;
205:
206: for (int i = 0; i <= m; i++) {
207: printFrame(trace[i], sb);
208: }
209: sb.append(" <more>");// NOI18N
210: sb.append(framesInCommon);
211: sb.append("</more>\n");// NOI18N
212: sb.append(" </exception>\n");// NOI18N
213: if (th.getCause() != null) {
214: printCause(th.getCause(), sb, trace);
215: }
216: }
217:
218: // Report on the state of the throwable.
219: private void printThrown(Throwable th, StringBuffer sb) {
220: sb.append(" <exception>\n");// NOI18N
221: sb.append(" <message>");// NOI18N
222: escape(sb, th.toString());
223: sb.append("</message>\n");// NOI18N
224: StackTraceElement trace[] = th.getStackTrace();
225: for (int i = 0; i < trace.length; i++) {
226: printFrame(trace[i], sb);
227: }
228: sb.append(" </exception>\n");// NOI18N
229: if (th.getCause() != null) {
230: printCause(th.getCause(), sb, trace);
231: }
232: }
233:
234: // Append the time and date in ISO 8601 format
235: private void appendISO8601(StringBuffer sb, long millis) {
236: Date date = new Date(millis);
237: Calendar calendar = new GregorianCalendar();
238: calendar.setTime(date);
239: sb.append(calendar.get(YEAR));
240: sb.append('-');
241: a2(sb, calendar.get(MONTH) + 1);
242: sb.append('-');
243: a2(sb, calendar.get(DAY_OF_MONTH));
244: sb.append('T');
245: a2(sb, calendar.get(HOUR_OF_DAY));
246: sb.append(':');
247: a2(sb, calendar.get(MINUTE));
248: sb.append(':');
249: a2(sb, calendar.get(SECOND));
250: }
251:
252: /**
253: * Format the given message to XML.
254: * @param record the log record to be formatted.
255: * @return a formatted log record
256: */
257: public @Override
258: String format(LogRecord record) {
259: StringBuffer sb = new StringBuffer(1000);
260: sb.append("<record>\n");// NOI18N
261:
262: sb.append(" <date>");// NOI18N
263: appendISO8601(sb, record.getMillis());
264: sb.append("</date>\n");// NOI18N
265:
266: sb.append(" <millis>");// NOI18N
267: sb.append(record.getMillis());
268: sb.append("</millis>\n");// NOI18N
269:
270: sb.append(" <sequence>");// NOI18N
271: sb.append(record.getSequenceNumber());
272: sb.append("</sequence>\n");// NOI18N
273:
274: String name = record.getLoggerName();
275: if (name != null) {
276: sb.append(" <logger>");// NOI18N
277: escape(sb, name);
278: sb.append("</logger>\n");// NOI18N
279: }
280:
281: sb.append(" <level>");// NOI18N
282: escape(sb, record.getLevel().toString());
283: sb.append("</level>\n");// NOI18N
284:
285: if (record.getSourceClassName() != null) {
286: sb.append(" <class>");// NOI18N
287: escape(sb, record.getSourceClassName());
288: sb.append("</class>\n");// NOI18N
289: }
290:
291: if (record.getSourceMethodName() != null) {
292: sb.append(" <method>");// NOI18N
293: escape(sb, record.getSourceMethodName());
294: sb.append("</method>\n");// NOI18N
295: }
296:
297: sb.append(" <thread>");// NOI18N
298: sb.append(record.getThreadID());
299: sb.append("</thread>\n");// NOI18N
300:
301: // Format the message string and its accompanying parameters.
302: String message = formatMessage(record);
303: if (record.getMessage() != null) {
304: sb.append(" <message>");// NOI18N
305: escape(sb, message);
306: sb.append("</message>\n");// NOI18N
307: }
308:
309: // If the message is being localized, output the key, resource
310: // bundle name, and params.
311: ResourceBundle bundle = record.getResourceBundle();
312: try {
313: if (bundle != null
314: && bundle.getString(record.getMessage()) != null) {
315: sb.append(" <key>");// NOI18N
316: escape(sb, record.getMessage());
317: sb.append("</key>\n");// NOI18N
318: sb.append(" <catalog>");// NOI18N
319: escape(sb, record.getResourceBundleName());
320: sb.append("</catalog>\n");// NOI18N
321: }
322: } catch (Exception exc) {
323: // The message is not in the catalog. Drop through.
324: Logger.getLogger(LogFormatter.class.getName()).log(
325: Level.FINE, "Catalog loading error", exc);// NOI18N
326: }
327:
328: Object parameters[] = record.getParameters();
329: // Check to see if the parameter was not a messagetext format
330: // or was not null or empty
331: if (parameters != null && parameters.length != 0
332: && record.getMessage().indexOf("{") == -1) {
333: for (int i = 0; i < parameters.length; i++) {
334: sb.append(" <param>");// NOI18N
335: try {
336: escape(sb, paramToString(parameters[i]));
337: } catch (Exception ex) {
338: sb.append("???");// NOI18N
339: }
340: sb.append("</param>\n");// NOI18N
341: }
342: }
343:
344: if (record.getThrown() != null) {
345: printThrown(record.getThrown(), sb);
346: }
347:
348: sb.append("</record>\n");// NOI18N
349: return sb.toString();
350: }
351:
352: private static String paramToString(Object obj) {
353: if (obj == null) {
354: return "null"; // NOI18N
355: }
356:
357: if (obj instanceof JMenuItem) {
358: JMenuItem ab = (JMenuItem) obj;
359: Action a = ab.getAction();
360: if (a == null) {
361: // fall thru to AbstractButton
362: } else {
363: return ab.getClass().getName() + '[' + paramToString(a)
364: + ']';
365: }
366: }
367: if (obj instanceof AbstractButton) {
368: AbstractButton ab = (AbstractButton) obj;
369: return ab.getClass().getName() + '[' + ab.getText() + ']';
370: }
371: if (obj instanceof Action) {
372: Action a = (Action) obj;
373: if (a.getClass().getName().endsWith("$DelegateAction") && // NOI18N
374: a.getClass().getName().startsWith("org.openide") // NOI18N
375: ) {
376: return a.toString().replaceAll("@[0-9a-fA-F]*",
377: "," + a.getValue(Action.NAME)); // NOI18N
378: }
379: return a.getClass().getName() + '['
380: + a.getValue(Action.NAME) + ']';
381: }
382: if (obj instanceof Component) {
383: Component c = (Component) obj;
384: return c.getClass().getName() + '[' + c.getName() + ']'; // NOI18N
385: }
386:
387: return obj.toString();
388: }
389: }
|