KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > log4j > chainsaw > MyTableModel


1 /*
2  * Copyright 1999-2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.log4j.chainsaw;
17
18 import java.text.DateFormat JavaDoc;
19 import java.util.ArrayList JavaDoc;
20 import java.util.Comparator JavaDoc;
21 import java.util.Date JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.List JavaDoc;
24 import java.util.SortedSet JavaDoc;
25 import java.util.TreeSet JavaDoc;
26 import javax.swing.table.AbstractTableModel JavaDoc;
27 import org.apache.log4j.Priority;
28 import org.apache.log4j.Logger;
29
30 /**
31  * Represents a list of <code>EventDetails</code> objects that are sorted on
32  * logging time. Methods are provided to filter the events that are visible.
33  *
34  * @author <a HREF="mailto:oliver@puppycrawl.com">Oliver Burn</a>
35  */

36 class MyTableModel
37     extends AbstractTableModel JavaDoc
38 {
39
40     /** used to log messages **/
41     private static final Logger LOG = Logger.getLogger(MyTableModel.class);
42
43     /** use the compare logging events **/
44     private static final Comparator JavaDoc MY_COMP = new Comparator JavaDoc()
45     {
46         /** @see Comparator **/
47         public int compare(Object JavaDoc aObj1, Object JavaDoc aObj2) {
48             if ((aObj1 == null) && (aObj2 == null)) {
49                 return 0; // treat as equal
50
} else if (aObj1 == null) {
51                 return -1; // null less than everything
52
} else if (aObj2 == null) {
53                 return 1; // think about it. :->
54
}
55
56             // will assume only have LoggingEvent
57
final EventDetails le1 = (EventDetails) aObj1;
58             final EventDetails le2 = (EventDetails) aObj2;
59
60             if (le1.getTimeStamp() < le2.getTimeStamp()) {
61                 return 1;
62             }
63             // assume not two events are logged at exactly the same time
64
return -1;
65         }
66         };
67
68     /**
69      * Helper that actually processes incoming events.
70      * @author <a HREF="mailto:oliver@puppycrawl.com">Oliver Burn</a>
71      */

72     private class Processor
73         implements Runnable JavaDoc
74     {
75         /** loops getting the events **/
76         public void run() {
77             while (true) {
78                 try {
79                     Thread.sleep(1000);
80                 } catch (InterruptedException JavaDoc e) {
81                     // ignore
82
}
83
84                 synchronized (mLock) {
85                     if (mPaused) {
86                         continue;
87                     }
88
89                     boolean toHead = true; // were events added to head
90
boolean needUpdate = false;
91                     final Iterator JavaDoc it = mPendingEvents.iterator();
92                     while (it.hasNext()) {
93                         final EventDetails event = (EventDetails) it.next();
94                         mAllEvents.add(event);
95                         toHead = toHead && (event == mAllEvents.first());
96                         needUpdate = needUpdate || matchFilter(event);
97                     }
98                     mPendingEvents.clear();
99
100                     if (needUpdate) {
101                         updateFilteredEvents(toHead);
102                     }
103                 }
104             }
105
106         }
107     }
108
109
110     /** names of the columns in the table **/
111     private static final String JavaDoc[] COL_NAMES = {
112         "Time", "Priority", "Trace", "Category", "NDC", "Message"};
113
114     /** definition of an empty list **/
115     private static final EventDetails[] EMPTY_LIST = new EventDetails[] {};
116
117     /** used to format dates **/
118     private static final DateFormat JavaDoc DATE_FORMATTER =
119         DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);
120
121     /** the lock to control access **/
122     private final Object JavaDoc mLock = new Object JavaDoc();
123     /** set of all logged events - not filtered **/
124     private final SortedSet JavaDoc mAllEvents = new TreeSet JavaDoc(MY_COMP);
125     /** events that are visible after filtering **/
126     private EventDetails[] mFilteredEvents = EMPTY_LIST;
127     /** list of events that are buffered for processing **/
128     private final List JavaDoc mPendingEvents = new ArrayList JavaDoc();
129     /** indicates whether event collection is paused to the UI **/
130     private boolean mPaused = false;
131
132     /** filter for the thread **/
133     private String JavaDoc mThreadFilter = "";
134     /** filter for the message **/
135     private String JavaDoc mMessageFilter = "";
136     /** filter for the NDC **/
137     private String JavaDoc mNDCFilter = "";
138     /** filter for the category **/
139     private String JavaDoc mCategoryFilter = "";
140     /** filter for the priority **/
141     private Priority mPriorityFilter = Priority.DEBUG;
142
143
144     /**
145      * Creates a new <code>MyTableModel</code> instance.
146      *
147      */

148     MyTableModel() {
149         final Thread JavaDoc t = new Thread JavaDoc(new Processor());
150         t.setDaemon(true);
151         t.start();
152     }
153
154
155     ////////////////////////////////////////////////////////////////////////////
156
// Table Methods
157
////////////////////////////////////////////////////////////////////////////
158

159     /** @see javax.swing.table.TableModel **/
160     public int getRowCount() {
161         synchronized (mLock) {
162             return mFilteredEvents.length;
163         }
164     }
165
166     /** @see javax.swing.table.TableModel **/
167     public int getColumnCount() {
168         // does not need to be synchronized
169
return COL_NAMES.length;
170     }
171
172     /** @see javax.swing.table.TableModel **/
173     public String JavaDoc getColumnName(int aCol) {
174         // does not need to be synchronized
175
return COL_NAMES[aCol];
176     }
177
178     /** @see javax.swing.table.TableModel **/
179     public Class JavaDoc getColumnClass(int aCol) {
180         // does not need to be synchronized
181
return (aCol == 2) ? Boolean JavaDoc.class : Object JavaDoc.class;
182     }
183
184     /** @see javax.swing.table.TableModel **/
185     public Object JavaDoc getValueAt(int aRow, int aCol) {
186         synchronized (mLock) {
187             final EventDetails event = mFilteredEvents[aRow];
188
189             if (aCol == 0) {
190                 return DATE_FORMATTER.format(new Date JavaDoc(event.getTimeStamp()));
191             } else if (aCol == 1) {
192                 return event.getPriority();
193             } else if (aCol == 2) {
194                 return (event.getThrowableStrRep() == null)
195                     ? Boolean.FALSE : Boolean.TRUE;
196             } else if (aCol == 3) {
197                 return event.getCategoryName();
198             } else if (aCol == 4) {
199                 return event.getNDC();
200             }
201             return event.getMessage();
202         }
203     }
204
205     ////////////////////////////////////////////////////////////////////////////
206
// Public Methods
207
////////////////////////////////////////////////////////////////////////////
208

209     /**
210      * Sets the priority to filter events on. Only events of equal or higher
211      * property are now displayed.
212      *
213      * @param aPriority the priority to filter on
214      */

215     public void setPriorityFilter(Priority aPriority) {
216         synchronized (mLock) {
217             mPriorityFilter = aPriority;
218             updateFilteredEvents(false);
219         }
220     }
221
222     /**
223      * Set the filter for the thread field.
224      *
225      * @param aStr the string to match
226      */

227     public void setThreadFilter(String JavaDoc aStr) {
228         synchronized (mLock) {
229             mThreadFilter = aStr.trim();
230             updateFilteredEvents(false);
231         }
232     }
233
234     /**
235      * Set the filter for the message field.
236      *
237      * @param aStr the string to match
238      */

239     public void setMessageFilter(String JavaDoc aStr) {
240         synchronized (mLock) {
241             mMessageFilter = aStr.trim();
242             updateFilteredEvents(false);
243         }
244     }
245
246     /**
247      * Set the filter for the NDC field.
248      *
249      * @param aStr the string to match
250      */

251     public void setNDCFilter(String JavaDoc aStr) {
252         synchronized (mLock) {
253             mNDCFilter = aStr.trim();
254             updateFilteredEvents(false);
255         }
256     }
257
258     /**
259      * Set the filter for the category field.
260      *
261      * @param aStr the string to match
262      */

263     public void setCategoryFilter(String JavaDoc aStr) {
264         synchronized (mLock) {
265             mCategoryFilter = aStr.trim();
266             updateFilteredEvents(false);
267         }
268     }
269
270     /**
271      * Add an event to the list.
272      *
273      * @param aEvent a <code>EventDetails</code> value
274      */

275     public void addEvent(EventDetails aEvent) {
276         synchronized (mLock) {
277             mPendingEvents.add(aEvent);
278         }
279     }
280
281     /**
282      * Clear the list of all events.
283      */

284     public void clear() {
285         synchronized (mLock) {
286             mAllEvents.clear();
287             mFilteredEvents = new EventDetails[0];
288             mPendingEvents.clear();
289             fireTableDataChanged();
290         }
291     }
292
293     /** Toggle whether collecting events **/
294     public void toggle() {
295         synchronized (mLock) {
296             mPaused = !mPaused;
297         }
298     }
299
300     /** @return whether currently paused collecting events **/
301     public boolean isPaused() {
302         synchronized (mLock) {
303             return mPaused;
304         }
305     }
306
307     /**
308      * Get the throwable information at a specified row in the filtered events.
309      *
310      * @param aRow the row index of the event
311      * @return the throwable information
312      */

313     public EventDetails getEventDetails(int aRow) {
314         synchronized (mLock) {
315             return mFilteredEvents[aRow];
316         }
317     }
318
319     ////////////////////////////////////////////////////////////////////////////
320
// Private methods
321
////////////////////////////////////////////////////////////////////////////
322

323     /**
324      * Update the filtered events data structure.
325      * @param aInsertedToFront indicates whether events were added to front of
326      * the events. If true, then the current first event must still exist
327      * in the list after the filter is applied.
328      */

329     private void updateFilteredEvents(boolean aInsertedToFront) {
330         final long start = System.currentTimeMillis();
331         final List JavaDoc filtered = new ArrayList JavaDoc();
332         final int size = mAllEvents.size();
333         final Iterator JavaDoc it = mAllEvents.iterator();
334
335         while (it.hasNext()) {
336             final EventDetails event = (EventDetails) it.next();
337             if (matchFilter(event)) {
338                 filtered.add(event);
339             }
340         }
341
342         final EventDetails lastFirst = (mFilteredEvents.length == 0)
343             ? null
344             : mFilteredEvents[0];
345         mFilteredEvents = (EventDetails[]) filtered.toArray(EMPTY_LIST);
346
347         if (aInsertedToFront && (lastFirst != null)) {
348             final int index = filtered.indexOf(lastFirst);
349             if (index < 1) {
350                 LOG.warn("In strange state");
351                 fireTableDataChanged();
352             } else {
353                 fireTableRowsInserted(0, index - 1);
354             }
355         } else {
356             fireTableDataChanged();
357         }
358
359         final long end = System.currentTimeMillis();
360         LOG.debug("Total time [ms]: " + (end - start)
361                   + " in update, size: " + size);
362     }
363
364     /**
365      * Returns whether an event matches the filters.
366      *
367      * @param aEvent the event to check for a match
368      * @return whether the event matches
369      */

370     private boolean matchFilter(EventDetails aEvent) {
371         if (aEvent.getPriority().isGreaterOrEqual(mPriorityFilter) &&
372             (aEvent.getThreadName().indexOf(mThreadFilter) >= 0) &&
373             (aEvent.getCategoryName().indexOf(mCategoryFilter) >= 0) &&
374             ((mNDCFilter.length() == 0) ||
375              ((aEvent.getNDC() != null) &&
376               (aEvent.getNDC().indexOf(mNDCFilter) >= 0))))
377         {
378             final String JavaDoc rm = aEvent.getMessage();
379             if (rm == null) {
380                 // only match if we have not filtering in place
381
return (mMessageFilter.length() == 0);
382             } else {
383                 return (rm.indexOf(mMessageFilter) >= 0);
384             }
385         }
386
387         return false; // by default not match
388
}
389 }
390
Popular Tags