KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jahia > sqlprofiler > gui > LoggerTableModel


1 /*
2  * Copyright (C) The Apache Software Foundation. All rights reserved.
3  *
4  * This software is published under the terms of the Apache Software
5  * License version 1.1, a copy of which has been included with this
6  * distribution in the APACHE.txt file. */

7 package org.jahia.sqlprofiler.gui;
8
9 import java.text.DateFormat JavaDoc;
10 import java.util.ArrayList JavaDoc;
11 import java.util.Comparator JavaDoc;
12 import java.util.Date JavaDoc;
13 import java.util.Iterator JavaDoc;
14 import java.util.List JavaDoc;
15 import java.util.SortedSet JavaDoc;
16 import java.util.TreeSet JavaDoc;
17 import javax.swing.table.AbstractTableModel JavaDoc;
18 import org.apache.log4j.Priority;
19 import org.apache.log4j.Category;
20 import org.jahia.sqlprofiler.QueryStatistics;
21 import java.util.StringTokenizer JavaDoc;
22 import java.util.NoSuchElementException JavaDoc;
23 import org.jahia.sqlprofiler.QueryStatEntry;
24 import java.text.NumberFormat JavaDoc;
25 import java.io.StringWriter JavaDoc;
26 import java.io.PrintWriter JavaDoc;
27 import org.jahia.sqlprofiler.QueryEntry;
28 import java.util.Set JavaDoc;
29 import java.io.FileWriter JavaDoc;
30 import java.util.*;
31 import java.io.IOException JavaDoc;
32 import java.text.SimpleDateFormat JavaDoc;
33
34 /**
35  * Represents a list of <code>EventDetails</code> objects that are sorted on
36  * logging time. Methods are provided to filter the events that are visible.
37  *
38  * @author <a HREF="mailto:oliver@puppycrawl.com">Oliver Burn</a>
39  */

40 class LoggerTableModel extends AbstractTableModel JavaDoc {
41
42     /** used to log messages **/
43     private static final Category LOG =
44         Category.getInstance(LoggerTableModel.class);
45
46     /** names of the columns in the table **/
47     private static final String JavaDoc[] COL_NAMES = {
48         "Time", "Priority", "Trace", "Category", "NDC", "Message"};
49
50     /** definition of an empty list **/
51     private static final EventDetails[] EMPTY_LIST = new EventDetails[] {};
52
53     /** used to format dates **/
54     private static final SimpleDateFormat JavaDoc DATE_FORMATTER = new SimpleDateFormat JavaDoc ("yyyy.MM.dd hh:mm:ss.SSS");
55
56     /** the lock to control access **/
57     private final Object JavaDoc mLock = new Object JavaDoc();
58     /** set of all logged events - not filtered **/
59     private final SortedSet JavaDoc mAllEvents = new TreeSet JavaDoc(MY_COMP);
60     /** events that are visible after filtering **/
61     private EventDetails[] mFilteredEvents = EMPTY_LIST;
62     /** list of events that are buffered for processing **/
63     private final List JavaDoc mPendingEvents = new ArrayList JavaDoc();
64     /** indicates whether event collection is paused to the UI **/
65     private boolean mPaused = false;
66
67     /** filter for the thread **/
68     private String JavaDoc mThreadFilter = "";
69     /** filter for the message **/
70     private String JavaDoc mMessageFilter = "";
71     /** filter for the NDC **/
72     private String JavaDoc mNDCFilter = "";
73     /** filter for the category **/
74     private String JavaDoc mCategoryFilter = "";
75     /** filter for the priority **/
76     private Priority mPriorityFilter = Priority.DEBUG;
77
78     private ProfileStatementTableModel profileStatementModel = null;
79
80     private QueryCountChartModel queryCountChartModel = null;
81     private QueryTrafficChartModel queryTrafficChartModel = null;
82
83     /** use the compare logging events **/
84     private static final Comparator JavaDoc MY_COMP = new Comparator JavaDoc() {
85         /** @see Comparator **/
86         public int compare(Object JavaDoc aObj1, Object JavaDoc aObj2) {
87             if ( (aObj1 == null) && (aObj2 == null)) {
88                 return 0; // treat as equal
89
} else if (aObj1 == null) {
90                 return -1; // null less than everything
91
} else if (aObj2 == null) {
92                 return 1; // think about it. :->
93
}
94
95             // will assume only have LoggingEvent
96
final EventDetails le1 = (EventDetails) aObj1;
97             final EventDetails le2 = (EventDetails) aObj2;
98
99             if (le1.getTimeStamp() < le2.getTimeStamp()) {
100                 return 1;
101             }
102             // assume not two events are logged at exactly the same time
103
return -1;
104         }
105     };
106
107     /**
108      * Helper that actually processes incoming events.
109      * @author <a HREF="mailto:oliver@puppycrawl.com">Oliver Burn</a>
110      */

111     private class Processor
112         implements Runnable JavaDoc {
113         /** loops getting the events **/
114         public void run() {
115             while (true) {
116                 try {
117                     Thread.sleep(1000);
118                 } catch (InterruptedException JavaDoc e) {
119                     // ignore
120
}
121
122                 synchronized (mLock) {
123                     if (mPaused) {
124                         continue;
125                     }
126
127                     boolean toHead = true; // were events added to head
128
boolean needUpdate = false;
129                     boolean needUpdateProfiler = false;
130                     final Iterator JavaDoc it = mPendingEvents.iterator();
131                     while (it.hasNext()) {
132                         final EventDetails event = (EventDetails) it.next();
133                         mAllEvents.add(event);
134                         if (event.getCategoryName().equals("p6spy")) {
135                             needUpdateProfiler = true;
136                             if (profileStatementModel != null) {
137                                 profileStatementModel.processP6Event(event.getMessage());
138                             }
139                         }
140                         toHead = toHead && (event == mAllEvents.first());
141                         needUpdate = needUpdate || matchFilter(event);
142                     }
143                     if (queryCountChartModel != null) {
144                         queryCountChartModel.update();
145                     }
146                     if (queryTrafficChartModel != null) {
147                         queryTrafficChartModel.update();
148                     }
149                     if ((profileStatementModel != null) && (needUpdateProfiler)) {
150                         profileStatementModel.sortAndUpdateTable();
151                         profileStatementModel.updateQueryStatsDisplay();
152                     }
153                     mPendingEvents.clear();
154
155                     if (needUpdate) {
156                         updateFilteredEvents(toHead);
157                     }
158                 }
159             }
160
161         }
162     }
163
164
165
166     /**
167      * Creates a new <code>MyTableModel</code> instance.
168      *
169      */

170     LoggerTableModel() {
171         final Thread JavaDoc t = new Thread JavaDoc(new Processor());
172         t.setDaemon(true);
173         t.start();
174     }
175
176     ////////////////////////////////////////////////////////////////////////////
177
// Table Methods
178
////////////////////////////////////////////////////////////////////////////
179

180     /** @see javax.swing.table.TableModel **/
181     public int getRowCount() {
182         synchronized (mLock) {
183             return mFilteredEvents.length;
184         }
185     }
186
187     /** @see javax.swing.table.TableModel **/
188     public int getColumnCount() {
189         // does not need to be synchronized
190
return COL_NAMES.length;
191     }
192
193     /** @see javax.swing.table.TableModel **/
194     public String JavaDoc getColumnName(int aCol) {
195         // does not need to be synchronized
196
return COL_NAMES[aCol];
197     }
198
199     /** @see javax.swing.table.TableModel **/
200     public Class JavaDoc getColumnClass(int aCol) {
201         // does not need to be synchronized
202
return (aCol == 2) ? Boolean JavaDoc.class : Object JavaDoc.class;
203     }
204
205     /** @see javax.swing.table.TableModel **/
206     public Object JavaDoc getValueAt(int aRow, int aCol) {
207         synchronized (mLock) {
208             final EventDetails event = mFilteredEvents[aRow];
209
210             if (aCol == 0) {
211                 return DATE_FORMATTER.format(new Date JavaDoc(event.getTimeStamp()));
212             } else if (aCol == 1) {
213                 return event.getPriority();
214             } else if (aCol == 2) {
215                 return (event.getThrowableStrRep() == null)
216                     ? Boolean.FALSE : Boolean.TRUE;
217             } else if (aCol == 3) {
218                 return event.getCategoryName();
219             } else if (aCol == 4) {
220                 return event.getNDC();
221             }
222             return event.getMessage();
223         }
224     }
225
226     ////////////////////////////////////////////////////////////////////////////
227
// Public Methods
228
////////////////////////////////////////////////////////////////////////////
229

230     /**
231      * Sets the priority to filter events on. Only events of equal or higher
232      * property are now displayed.
233      *
234      * @param aPriority the priority to filter on
235      */

236     public void setPriorityFilter(Priority aPriority) {
237         synchronized (mLock) {
238             mPriorityFilter = aPriority;
239             updateFilteredEvents(false);
240         }
241     }
242
243     /**
244      * Set the filter for the thread field.
245      *
246      * @param aStr the string to match
247      */

248     public void setThreadFilter(String JavaDoc aStr) {
249         synchronized (mLock) {
250             mThreadFilter = aStr.trim();
251             updateFilteredEvents(false);
252         }
253     }
254
255     /**
256      * Set the filter for the message field.
257      *
258      * @param aStr the string to match
259      */

260     public void setMessageFilter(String JavaDoc aStr) {
261         synchronized (mLock) {
262             mMessageFilter = aStr.trim();
263             updateFilteredEvents(false);
264         }
265     }
266
267     /**
268      * Set the filter for the NDC field.
269      *
270      * @param aStr the string to match
271      */

272     public void setNDCFilter(String JavaDoc aStr) {
273         synchronized (mLock) {
274             mNDCFilter = aStr.trim();
275             updateFilteredEvents(false);
276         }
277     }
278
279     /**
280      * Set the filter for the category field.
281      *
282      * @param aStr the string to match
283      */

284     public void setCategoryFilter(String JavaDoc aStr) {
285         synchronized (mLock) {
286             mCategoryFilter = aStr.trim();
287             updateFilteredEvents(false);
288         }
289     }
290
291     /**
292      * Add an event to the list.
293      *
294      * @param aEvent a <code>EventDetails</code> value
295      */

296     public void addEvent(EventDetails aEvent) {
297         synchronized (mLock) {
298             mPendingEvents.add(aEvent);
299         }
300     }
301
302     /**
303      * Clear the list of all events.
304      */

305     public void clear() {
306         synchronized (mLock) {
307             mAllEvents.clear();
308             mFilteredEvents = new EventDetails[0];
309             mPendingEvents.clear();
310             if (profileStatementModel != null) {
311                 profileStatementModel.clear();
312                 profileStatementModel.fireTableDataChanged();
313             }
314             fireTableDataChanged();
315         }
316     }
317
318     /** Toggle whether collecting events **/
319     public void toggle() {
320         synchronized (mLock) {
321             mPaused = !mPaused;
322             if (mPaused) {
323                 if (profileStatementModel != null) {
324                     profileStatementModel.displayOccurenceStats(false);
325                 }
326             }
327         }
328     }
329
330     /** @return whether currently paused collecting events **/
331     public boolean isPaused() {
332         synchronized (mLock) {
333             return mPaused;
334         }
335     }
336
337     /**
338      * Get the throwable information at a specified row in the filtered events.
339      *
340      * @param aRow the row index of the event
341      * @return the throwable information
342      */

343     public EventDetails getEventDetails(int aRow) {
344         synchronized (mLock) {
345             return mFilteredEvents[aRow];
346         }
347     }
348
349     public void setProfileStatementModel(ProfileStatementTableModel profileStatementModel) {
350         this.profileStatementModel = profileStatementModel;
351     }
352
353     public void setQueryCountChartModel(QueryCountChartModel queryCountChartModel) {
354         this.queryCountChartModel = queryCountChartModel;
355     }
356
357     public void setQueryTrafficChartModel(QueryTrafficChartModel queryTrafficChartModel) {
358         this.queryTrafficChartModel = queryTrafficChartModel;
359     }
360
361     ////////////////////////////////////////////////////////////////////////////
362
// Private methods
363
////////////////////////////////////////////////////////////////////////////
364

365     /**
366      * Update the filtered events data structure.
367      * @param aInsertedToFront indicates whether events were added to front of
368          * the events. If true, then the current first event must still exist
369      * in the list after the filter is applied.
370      */

371     private void updateFilteredEvents(boolean aInsertedToFront) {
372         final long start = System.currentTimeMillis();
373         final List JavaDoc filtered = new ArrayList JavaDoc();
374         final int size = mAllEvents.size();
375         final Iterator JavaDoc allEventIter = mAllEvents.iterator();
376
377         while (allEventIter.hasNext()) {
378             final EventDetails event = (EventDetails) allEventIter.next();
379             if (matchFilter(event)) {
380                 filtered.add(event);
381             }
382         }
383
384         final EventDetails lastFirst = (mFilteredEvents.length == 0)
385             ? null
386             : mFilteredEvents[0];
387         mFilteredEvents = (EventDetails[]) filtered.toArray(EMPTY_LIST);
388
389         if (aInsertedToFront && (lastFirst != null)) {
390             final int index = filtered.indexOf(lastFirst);
391             if (index < 1) {
392                 LOG.warn("In strange state");
393                 fireTableDataChanged();
394             } else {
395                 fireTableRowsInserted(0, index - 1);
396             }
397         } else {
398             fireTableDataChanged();
399         }
400
401         final long end = System.currentTimeMillis();
402         LOG.debug("Total time [ms]: " + (end - start)
403                   + " in update, size: " + size);
404     }
405
406     /**
407      * Returns whether an event matches the filters.
408      *
409      * @param aEvent the event to check for a match
410      * @return whether the event matches
411      */

412     private boolean matchFilter(EventDetails aEvent) {
413         if (aEvent.getPriority().isGreaterOrEqual(mPriorityFilter) &&
414             (aEvent.getThreadName().indexOf(mThreadFilter) >= 0) &&
415             (aEvent.getCategoryName().indexOf(mCategoryFilter) >= 0) &&
416             ( (mNDCFilter.length() == 0) ||
417              ( (aEvent.getNDC() != null) &&
418               (aEvent.getNDC().indexOf(mNDCFilter) >= 0)))) {
419             final String JavaDoc rm = aEvent.getMessage();
420             if (rm == null) {
421                 // only match if we have not filtering in place
422
return (mMessageFilter.length() == 0);
423             } else {
424                 return (rm.indexOf(mMessageFilter) >= 0);
425             }
426         }
427
428         return false; // by default not match
429
}
430
431
432 }
Popular Tags