1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.log4j.chainsaw;
18
19 import java.util.StringTokenizer;
20 import org.apache.log4j.Level;
21 import org.xml.sax.Attributes;
22 import org.xml.sax.SAXException;
23 import org.xml.sax.helpers.DefaultHandler;
24
25 /**
26 * A content handler for document containing Log4J events logged using the
27 * XMLLayout class. It will create events and add them to a supplied model.
28 *
29 * @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
30 * @version 1.0
31 */
32 class XMLFileHandler
33 extends DefaultHandler
34 {
35 /** represents the event tag **/
36 private static final String TAG_EVENT = "log4j:event";
37 /** represents the message tag **/
38 private static final String TAG_MESSAGE = "log4j:message";
39 /** represents the ndc tag **/
40 private static final String TAG_NDC = "log4j:NDC";
41 /** represents the throwable tag **/
42 private static final String TAG_THROWABLE = "log4j:throwable";
43 /** represents the location info tag **/
44 private static final String TAG_LOCATION_INFO = "log4j:locationInfo";
45
46 /** where to put the events **/
47 private final MyTableModel mModel;
48 /** the number of events in the document **/
49 private int mNumEvents;
50
51 /** the time of the event **/
52 private long mTimeStamp;
53 /** the priority (level) of the event **/
54 private Level mLevel;
55 /** the category of the event **/
56 private String mCategoryName;
57 /** the NDC for the event **/
58 private String mNDC;
59 /** the thread for the event **/
60 private String mThreadName;
61 /** the msg for the event **/
62 private String mMessage;
63 /** the throwable details the event **/
64 private String[] mThrowableStrRep;
65 /** the location details for the event **/
66 private String mLocationDetails;
67 /** buffer for collecting text **/
68 private final StringBuffer mBuf = new StringBuffer();
69
70 /**
71 * Creates a new <code>XMLFileHandler</code> instance.
72 *
73 * @param aModel where to add the events
74 */
75 XMLFileHandler(MyTableModel aModel) {
76 mModel = aModel;
77 }
78
79 /** @see DefaultHandler **/
80 public void startDocument()
81 throws SAXException
82 {
83 mNumEvents = 0;
84 }
85
86 /** @see DefaultHandler **/
87 public void characters(char[] aChars, int aStart, int aLength) {
88 mBuf.append(String.valueOf(aChars, aStart, aLength));
89 }
90
91 /** @see DefaultHandler **/
92 public void endElement(String aNamespaceURI,
93 String aLocalName,
94 String aQName)
95 {
96 if (TAG_EVENT.equals(aQName)) {
97 addEvent();
98 resetData();
99 } else if (TAG_NDC.equals(aQName)) {
100 mNDC = mBuf.toString();
101 } else if (TAG_MESSAGE.equals(aQName)) {
102 mMessage = mBuf.toString();
103 } else if (TAG_THROWABLE.equals(aQName)) {
104 final StringTokenizer st =
105 new StringTokenizer(mBuf.toString(), "\n\t");
106 mThrowableStrRep = new String[st.countTokens()];
107 if (mThrowableStrRep.length > 0) {
108 mThrowableStrRep[0] = st.nextToken();
109 for (int i = 1; i < mThrowableStrRep.length; i++) {
110 mThrowableStrRep[i] = "\t" + st.nextToken();
111 }
112 }
113 }
114 }
115
116 /** @see DefaultHandler **/
117 public void startElement(String aNamespaceURI,
118 String aLocalName,
119 String aQName,
120 Attributes aAtts)
121 {
122 mBuf.setLength(0);
123
124 if (TAG_EVENT.equals(aQName)) {
125 mThreadName = aAtts.getValue("thread");
126 mTimeStamp = Long.parseLong(aAtts.getValue("timestamp"));
127 mCategoryName = aAtts.getValue("logger");
128 mLevel = Level.toLevel(aAtts.getValue("level"));
129 } else if (TAG_LOCATION_INFO.equals(aQName)) {
130 mLocationDetails = aAtts.getValue("class") + "."
131 + aAtts.getValue("method")
132 + "(" + aAtts.getValue("file") + ":" + aAtts.getValue("line")
133 + ")";
134 }
135 }
136
137 /** @return the number of events in the document **/
138 int getNumEvents() {
139 return mNumEvents;
140 }
141
142 ////////////////////////////////////////////////////////////////////////////
143 // Private methods
144 ////////////////////////////////////////////////////////////////////////////
145
146 /** Add an event to the model **/
147 private void addEvent() {
148 mModel.addEvent(new EventDetails(mTimeStamp,
149 mLevel,
150 mCategoryName,
151 mNDC,
152 mThreadName,
153 mMessage,
154 mThrowableStrRep,
155 mLocationDetails));
156 mNumEvents++;
157 }
158
159 /** Reset the data for an event **/
160 private void resetData() {
161 mTimeStamp = 0;
162 mLevel = null;
163 mCategoryName = null;
164 mNDC = null;
165 mThreadName = null;
166 mMessage = null;
167 mThrowableStrRep = null;
168 mLocationDetails = null;
169 }
170 }