~ubuntu-branches/ubuntu/quantal/netbeans/quantal

« back to all changes in this revision

Viewing changes to logger/uihandlerlib/src/org/netbeans/lib/uihandler/LogRecords.java

  • Committer: Bazaar Package Importer
  • Author(s): Marek Slama
  • Date: 2008-01-29 14:11:22 UTC
  • Revision ID: james.westby@ubuntu.com-20080129141122-fnzjbo11ntghxfu7
Tags: upstream-6.0.1
ImportĀ upstreamĀ versionĀ 6.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 
3
 *
 
4
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 
5
 *
 
6
 * The contents of this file are subject to the terms of either the GNU
 
7
 * General Public License Version 2 only ("GPL") or the Common
 
8
 * Development and Distribution License("CDDL") (collectively, the
 
9
 * "License"). You may not use this file except in compliance with the
 
10
 * License. You can obtain a copy of the License at
 
11
 * http://www.netbeans.org/cddl-gplv2.html
 
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 
13
 * specific language governing permissions and limitations under the
 
14
 * License.  When distributing the software, include this License Header
 
15
 * Notice in each file and include the License file at
 
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
 
17
 * particular file as subject to the "Classpath" exception as provided
 
18
 * by Sun in the GPL Version 2 section of the License file that
 
19
 * accompanied this code. If applicable, add the following below the
 
20
 * License Header, with the fields enclosed by brackets [] replaced by
 
21
 * your own identifying information:
 
22
 * "Portions Copyrighted [year] [name of copyright owner]"
 
23
 *
 
24
 * Contributor(s):
 
25
 *
 
26
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 
27
 */
 
28
 
 
29
package org.netbeans.lib.uihandler;
 
30
 
 
31
import java.io.ByteArrayInputStream;
 
32
import java.io.IOException;
 
33
import java.io.InputStream;
 
34
import java.io.OutputStream;
 
35
import java.io.PushbackInputStream;
 
36
import java.io.SequenceInputStream;
 
37
import java.util.ArrayList;
 
38
import java.util.Collections;
 
39
import java.util.EnumMap;
 
40
import java.util.Enumeration;
 
41
import java.util.LinkedList;
 
42
import java.util.List;
 
43
import java.util.Map;
 
44
import java.util.MissingResourceException;
 
45
import java.util.Queue;
 
46
import java.util.ResourceBundle;
 
47
import java.util.logging.Formatter;
 
48
import java.util.logging.Handler;
 
49
import java.util.logging.Level;
 
50
import java.util.logging.LogRecord;
 
51
import java.util.logging.Logger;
 
52
import java.util.zip.GZIPInputStream;
 
53
import javax.xml.parsers.ParserConfigurationException;
 
54
import javax.xml.parsers.SAXParser;
 
55
import javax.xml.parsers.SAXParserFactory;
 
56
import org.openide.util.NbBundle;
 
57
import org.xml.sax.Attributes;
 
58
import org.xml.sax.Locator;
 
59
import org.xml.sax.SAXException;
 
60
import org.xml.sax.SAXParseException;
 
61
import org.xml.sax.helpers.DefaultHandler;
 
62
 
 
63
/** Can persist and read log records from streams.
 
64
 *
 
65
 * @author Jaroslav Tulach
 
66
 */
 
67
public final class LogRecords {
 
68
    private LogRecords() {
 
69
    }
 
70
 
 
71
    private static final Logger LOG = Logger.getLogger(LogRecords.class.getName());
 
72
    
 
73
    private static final Formatter FORMATTER = new LogFormatter();
 
74
  
 
75
    /** Inspects the log record and decorates its content.
 
76
     * @param r the log record
 
77
     * @param d callback to be called with inspected values
 
78
     */
 
79
    public static void decorate(LogRecord r, Decorable d) {
 
80
        Decorations.decorate(r, d);
 
81
    }
 
82
    
 
83
    public static void write(OutputStream os, LogRecord rec) throws IOException {           
 
84
        String formated = FORMATTER.format(rec);
 
85
        byte[] arr = formated.getBytes("utf-8");
 
86
        os.write(arr);
 
87
    }
 
88
 
 
89
    public static void scan(InputStream is, Handler h) throws IOException {
 
90
        PushbackInputStream wrap = new PushbackInputStream(is, 32);
 
91
        byte[] arr = new byte[5];
 
92
        int len = wrap.read(arr);
 
93
        if (len == -1) {
 
94
            return;
 
95
        }
 
96
        wrap.unread(arr, 0, len);
 
97
        if (arr[0] == 0x1f && arr[1] == -117) {
 
98
            wrap = new PushbackInputStream(new GZIPInputStream(wrap), 32);
 
99
            len = wrap.read(arr);
 
100
            if (len == -1) {
 
101
                return;
 
102
            }
 
103
            wrap.unread(arr, 0, len);
 
104
        }
 
105
        
 
106
        if (arr[0] == '<' &&
 
107
            arr[1] == '?' &&
 
108
            arr[2] == 'x' &&
 
109
            arr[3] == 'm' &&
 
110
            arr[4] == 'l'
 
111
        ) {
 
112
            is = wrap;
 
113
        } else {
 
114
            ByteArrayInputStream header = new ByteArrayInputStream(
 
115
    "<?xml version='1.0' encoding='UTF-8'?><uigestures version='1.0'>".getBytes()
 
116
            );
 
117
            ByteArrayInputStream footer = new ByteArrayInputStream(
 
118
                "</uigestures>".getBytes()
 
119
            );
 
120
            is = new SequenceInputStream(
 
121
                new SequenceInputStream(header, wrap),
 
122
                footer
 
123
            );
 
124
        }
 
125
        
 
126
        SAXParserFactory f = SAXParserFactory.newInstance();
 
127
        f.setValidating(false);
 
128
        SAXParser p;
 
129
        try {
 
130
            f.setFeature("http://apache.org/xml/features/continue-after-fatal-error", true); // NOI18N
 
131
            p = f.newSAXParser();
 
132
        } catch (ParserConfigurationException ex) {
 
133
            LOG.log(Level.SEVERE, null, ex);
 
134
            throw (IOException)new IOException(ex.getMessage()).initCause(ex);
 
135
        } catch (SAXException ex) {
 
136
            LOG.log(Level.SEVERE, null, ex);
 
137
            throw (IOException)new IOException(ex.getMessage()).initCause(ex);
 
138
        }
 
139
        
 
140
        Parser parser = new Parser(h);
 
141
        try {
 
142
            p.parse(is, parser);
 
143
        } catch (SAXException ex) {
 
144
            LOG.log(Level.WARNING, null, ex);
 
145
            throw (IOException)new IOException(ex.getMessage()).initCause(ex);
 
146
        } catch (InternalError error){
 
147
            LOG.log(Level.WARNING, "INPUT FILE CORRUPTION", error);
 
148
        } catch (IOException ex) {
 
149
            throw ex;
 
150
        } catch (RuntimeException ex) {
 
151
            LOG.log(Level.WARNING, "INPUT FILE CORRUPTION", ex);
 
152
        }
 
153
    }   
 
154
 
 
155
    static Level parseLevel(String lev) {
 
156
        return "USER".equals(lev) ? Level.SEVERE : Level.parse(lev);
 
157
    }
 
158
    
 
159
    private static final class Parser extends DefaultHandler {
 
160
        private Handler callback;
 
161
        private static enum Elem {
 
162
            UIGESTURES, RECORD, DATE, MILLIS, SEQUENCE, LEVEL, THREAD,
 
163
            MESSAGE, KEY, PARAM, FRAME, CLASS, METHOD, LOGGER, EXCEPTION, LINE,
 
164
            CATALOG, MORE, FILE;
 
165
            
 
166
            public String parse(Map<Elem,String> values) {
 
167
                String v = values.get(this);
 
168
                return v;
 
169
            }
 
170
        }
 
171
        private Map<Elem,String> values = new EnumMap<Elem,String>(Elem.class);
 
172
        private Elem current;
 
173
        private FakeException currentEx;
 
174
        private Queue<FakeException> exceptions;
 
175
        private List<String> params;
 
176
        private StringBuilder chars = new StringBuilder();
 
177
        private int fatalErrors;
 
178
        
 
179
        public Parser(Handler c) {
 
180
            this.callback = c;
 
181
        }
 
182
        
 
183
        
 
184
        public void setDocumentLocator(Locator locator) {
 
185
        }
 
186
 
 
187
        public void startDocument() throws SAXException {
 
188
        }
 
189
 
 
190
        public void endDocument() throws SAXException {
 
191
            callback.flush();
 
192
        }
 
193
 
 
194
        public void startPrefixMapping(String prefix, String uri) throws SAXException {
 
195
        }
 
196
 
 
197
        public void endPrefixMapping(String prefix) throws SAXException {
 
198
        }
 
199
 
 
200
        public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
 
201
            if (LOG.isLoggable(Level.FINEST)) {
 
202
                LOG.log(Level.FINEST, "uri: {0} localName: {1} qName: {2} atts: {3}", new Object[] { uri, localName, qName, atts });
 
203
            }
 
204
 
 
205
            try {
 
206
                current = Elem.valueOf(qName.toUpperCase());
 
207
                if (current == Elem.EXCEPTION) {
 
208
                    currentEx = new FakeException(new EnumMap<Elem,String>(values));
 
209
                }
 
210
            } catch (IllegalArgumentException ex) {
 
211
                LOG.log(Level.FINE, "Uknown tag " + qName, ex);
 
212
                current = null;
 
213
            }
 
214
            chars = new StringBuilder();
 
215
        }
 
216
        
 
217
        public void endElement(String uri, String localName, String qName) throws SAXException {
 
218
            if (current != null) {
 
219
                String v = chars.toString();
 
220
                values.put(current, v);
 
221
                if (current == Elem.PARAM) {
 
222
                    if (params == null) {
 
223
                        params = new ArrayList<String>();
 
224
                    }
 
225
                    params.add(v);
 
226
                    if (params.size() > 1500) {
 
227
                        LOG.severe("Too long params when reading a record. Deleting few. Msg: " + Elem.MESSAGE.parse(values)); // NOI18N
 
228
                        for (String p : params) {
 
229
                            LOG.fine(p);
 
230
                        }
 
231
                        params.clear();
 
232
                    }
 
233
                }
 
234
            }
 
235
            current = null;
 
236
            chars = new StringBuilder();
 
237
            
 
238
            if (currentEx != null && currentEx.values != null) {
 
239
                if ("frame".equals(qName)) { // NOI18N
 
240
                    String line = Elem.LINE.parse(values);
 
241
                    StackTraceElement elem = new StackTraceElement(
 
242
                            Elem.CLASS.parse(values),
 
243
                            Elem.METHOD.parse(values),
 
244
                            Elem.FILE.parse(values),
 
245
                            line == null ? -1 : Integer.parseInt(line)
 
246
                            );
 
247
                    currentEx.trace.add(elem);
 
248
                    values.remove(Elem.CLASS);
 
249
                    values.remove(Elem.METHOD);
 
250
                    values.remove(Elem.LINE);
 
251
                }
 
252
                if ("exception".equals(qName)) {
 
253
                    currentEx.message = values.get(Elem.MESSAGE);
 
254
                    String more = values.get(Elem.MORE);
 
255
                    if (more != null) currentEx.more = Integer.parseInt(more);
 
256
                    if (exceptions == null){
 
257
                        exceptions = new LinkedList<FakeException>();
 
258
                    }
 
259
                    exceptions.add(currentEx);
 
260
                    values = currentEx.values;
 
261
                    currentEx = null;
 
262
                }
 
263
                return;
 
264
            }
 
265
            
 
266
            if ("record".equals(qName)) { // NOI18N
 
267
                String millis = Elem.MILLIS.parse(values);
 
268
                String seq = Elem.SEQUENCE.parse(values);
 
269
                String lev = Elem.LEVEL.parse(values);
 
270
                String thread = Elem.THREAD.parse(values);
 
271
                String msg = Elem.MESSAGE.parse(values);
 
272
                String key = Elem.KEY.parse(values);
 
273
                String catalog = Elem.CATALOG.parse(values);
 
274
                
 
275
                if (lev != null) {
 
276
                    LogRecord r = new LogRecord(parseLevel(lev), key != null && catalog != null ? key : msg);
 
277
                    try {
 
278
                        r.setThreadID(Integer.parseInt(thread));
 
279
                    } catch (NumberFormatException ex) {
 
280
                        LOG.log(Level.WARNING, ex.getMessage(), ex);
 
281
                    }
 
282
                    r.setSequenceNumber(Long.parseLong(seq));
 
283
                    r.setMillis(Long.parseLong(millis));
 
284
                    r.setResourceBundleName(key);
 
285
                    if (catalog != null && key != null) {
 
286
                        r.setResourceBundleName(catalog);
 
287
                        if (!"<null>".equals(catalog)) { // NOI18N
 
288
                            try {
 
289
                                ResourceBundle b = NbBundle.getBundle(catalog);
 
290
                                b.getObject(key);
 
291
                                // ok, the key is there
 
292
                                r.setResourceBundle(b);
 
293
                            } catch (MissingResourceException e) {
 
294
                                LOG.log(Level.CONFIG, "Cannot find resource bundle {0} for key {1}", new Object[] { catalog, key });
 
295
                                r.setResourceBundle(new FakeBundle(key, msg));
 
296
                            }
 
297
                        } else {
 
298
                            LOG.log(Level.CONFIG, "Cannot find resource bundle <null> for key {1}", key);
 
299
                        }
 
300
                    }
 
301
                    if (params != null) {
 
302
                        r.setParameters(params.toArray());
 
303
                    }
 
304
                    if (exceptions != null) {
 
305
                        r.setThrown(createThrown(null));
 
306
                        // exceptions = null;  should be empty after poll
 
307
                    }
 
308
 
 
309
                    callback.publish(r);
 
310
                }
 
311
 
 
312
                currentEx = null;
 
313
                params = null;
 
314
                values.clear();
 
315
            }
 
316
            
 
317
        }
 
318
        
 
319
        /** set first element of exceptions as a result of this calling and
 
320
         * recursively fill it's cause
 
321
         */
 
322
        private FakeException createThrown(FakeException last){
 
323
            if (exceptions.size()==0) {
 
324
                return null;
 
325
            }
 
326
            FakeException result = exceptions.poll();
 
327
            if ((result!= null) && (result.getMore()!= 0)){
 
328
                assert last != null : "IF MORE IS NOT 0, LAST MUST BE SET NOT NULL";
 
329
                StackTraceElement[] trace = last.getStackTrace();
 
330
                for (int i = trace.length - result.getMore(); i < trace.length; i++){
 
331
                    result.trace.add(trace[i]);// fill the rest of stacktrace
 
332
                }
 
333
            }
 
334
            FakeException cause = createThrown(result);
 
335
            result.initCause(cause);
 
336
            return result;
 
337
        }
 
338
        
 
339
        public void characters(char[] ch, int start, int length) throws SAXException {
 
340
            chars.append(ch, start, length);
 
341
        }
 
342
 
 
343
        public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
 
344
        }
 
345
 
 
346
        public void processingInstruction(String target, String data) throws SAXException {
 
347
        }
 
348
 
 
349
        public void skippedEntity(String name) throws SAXException {
 
350
        }
 
351
 
 
352
        public void fatalError(SAXParseException e) throws SAXException {
 
353
            if (fatalErrors++ > 1000) {
 
354
                throw e;
 
355
            }
 
356
        }
 
357
        
 
358
    }
 
359
    
 
360
    private static final class FakeBundle extends ResourceBundle {
 
361
        private String key;
 
362
        private String value;
 
363
         
 
364
        public FakeBundle(String key, String value) {
 
365
            this.key = key;
 
366
            this.value = value;
 
367
        }
 
368
 
 
369
    
 
370
        protected Object handleGetObject(String arg0) {
 
371
            if (key.equals(arg0)) {
 
372
                return value;
 
373
            } else {
 
374
                return null;
 
375
            }
 
376
        }
 
377
 
 
378
        public Enumeration<String> getKeys() {
 
379
            return Collections.enumeration(Collections.singleton(key));
 
380
        }
 
381
    } // end of FakeBundle
 
382
    
 
383
    private static final class FakeException extends Exception {
 
384
        final List<StackTraceElement> trace = new ArrayList<StackTraceElement>();
 
385
        Map<Parser.Elem,String> values;
 
386
        String message;
 
387
        int more;
 
388
        
 
389
        public FakeException(Map<Parser.Elem,String> values) {
 
390
            this.values = values;
 
391
            more = 0;
 
392
        }
 
393
       
 
394
        public StackTraceElement[] getStackTrace() {
 
395
            return trace.toArray(new StackTraceElement[0]);
 
396
        }
 
397
 
 
398
        public String getMessage() {
 
399
            return message;
 
400
        }
 
401
        
 
402
        public int getMore(){
 
403
            return more;
 
404
        }
 
405
        
 
406
        /**
 
407
         * org.netbeans.lib.uihandler.LogRecords$FakeException: NullPointerException ...
 
408
         * is not the best message - it's better to suppress FakeException
 
409
         */
 
410
        public String toString(){
 
411
            return message;
 
412
        }
 
413
        
 
414
    } // end of FakeException
 
415
}