View Javadoc

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.lf5.viewer;
18  
19  import org.apache.log4j.lf5.LogRecord;
20  import org.apache.log4j.lf5.LogRecordFilter;
21  import org.apache.log4j.lf5.PassingLogRecordFilter;
22  
23  import javax.swing.table.AbstractTableModel;
24  import java.util.ArrayList;
25  import java.util.Date;
26  import java.util.Iterator;
27  import java.util.List;
28  
29  
30  /**
31   * A TableModel for LogRecords which includes filtering support.
32   *
33   * @author Richard Wan
34   * @author Brent Sprecher
35   */
36  
37  // Contributed by ThoughtWorks Inc.
38  
39  public class FilteredLogTableModel
40      extends AbstractTableModel {
41    //--------------------------------------------------------------------------
42    //   Constants:
43    //--------------------------------------------------------------------------
44  
45    //--------------------------------------------------------------------------
46    //   Protected Variables:
47    //--------------------------------------------------------------------------
48  
49    protected LogRecordFilter _filter = new PassingLogRecordFilter();
50    protected List _allRecords = new ArrayList();
51    protected List _filteredRecords;
52    protected int _maxNumberOfLogRecords = 5000;
53    protected String[] _colNames = {"Date",
54                                    "Thread",
55                                    "Message #",
56                                    "Level",
57                                    "NDC",
58                                    "Category",
59                                    "Message",
60                                    "Location",
61                                    "Thrown"};
62  
63    //--------------------------------------------------------------------------
64    //   Private Variables:
65    //--------------------------------------------------------------------------
66  
67    //--------------------------------------------------------------------------
68    //   Constructors:
69    //--------------------------------------------------------------------------
70  
71    public FilteredLogTableModel() {
72      super();
73    }
74  
75    //--------------------------------------------------------------------------
76    //   Public Methods:
77    //--------------------------------------------------------------------------
78  
79    public void setLogRecordFilter(LogRecordFilter filter) {
80      _filter = filter;
81    }
82  
83    public LogRecordFilter getLogRecordFilter() {
84      return _filter;
85    }
86  
87    public String getColumnName(int i) {
88      return _colNames[i];
89    }
90  
91    public int getColumnCount() {
92      return _colNames.length;
93    }
94  
95    public int getRowCount() {
96      return getFilteredRecords().size();
97    }
98  
99    public int getTotalRowCount() {
100     return _allRecords.size();
101   }
102 
103   public Object getValueAt(int row, int col) {
104     LogRecord record = getFilteredRecord(row);
105     return getColumn(col, record);
106   }
107 
108   public void setMaxNumberOfLogRecords(int maxNumRecords) {
109     if (maxNumRecords > 0) {
110       _maxNumberOfLogRecords = maxNumRecords;
111     }
112 
113   }
114 
115   public synchronized boolean addLogRecord(LogRecord record) {
116 
117     _allRecords.add(record);
118 
119     if (_filter.passes(record) == false) {
120       return false;
121     }
122     getFilteredRecords().add(record);
123     fireTableRowsInserted(getRowCount(), getRowCount());
124     trimRecords();
125     return true;
126   }
127 
128   /**
129    * Forces the LogTableModel to requery its filters to determine
130    * which records to display.
131    */
132   public synchronized void refresh() {
133     _filteredRecords = createFilteredRecordsList();
134     fireTableDataChanged();
135   }
136 
137   public synchronized void fastRefresh() {
138     _filteredRecords.remove(0);
139     fireTableRowsDeleted(0, 0);
140   }
141 
142 
143   /**
144    * Clears all records from the LogTableModel
145    */
146   public synchronized void clear() {
147     _allRecords.clear();
148     _filteredRecords.clear();
149     fireTableDataChanged();
150   }
151 
152   //--------------------------------------------------------------------------
153   //   Protected Methods:
154   //--------------------------------------------------------------------------
155 
156   protected List getFilteredRecords() {
157     if (_filteredRecords == null) {
158       refresh();
159     }
160     return _filteredRecords;
161   }
162 
163   protected List createFilteredRecordsList() {
164     List result = new ArrayList();
165     Iterator records = _allRecords.iterator();
166     LogRecord current;
167     while (records.hasNext()) {
168       current = (LogRecord) records.next();
169       if (_filter.passes(current)) {
170         result.add(current);
171       }
172     }
173     return result;
174   }
175 
176   protected LogRecord getFilteredRecord(int row) {
177     List records = getFilteredRecords();
178     int size = records.size();
179     if (row < size) {
180       return (LogRecord) records.get(row);
181     }
182     // a minor problem has happened. JTable has asked for
183     // a row outside the bounds, because the size of
184     // _filteredRecords has changed while it was looping.
185     // return the last row.
186     return (LogRecord) records.get(size - 1);
187 
188   }
189 
190   protected Object getColumn(int col, LogRecord lr) {
191     if (lr == null) {
192       return "NULL Column";
193     }
194     String date = new Date(lr.getMillis()).toString();
195     switch (col) {
196       case 0:
197         return date + " (" + lr.getMillis() + ")";
198       case 1:
199         return lr.getThreadDescription();
200       case 2:
201         return new Long(lr.getSequenceNumber());
202       case 3:
203         return lr.getLevel();
204       case 4:
205         return lr.getNDC();
206       case 5:
207         return lr.getCategory();
208       case 6:
209         return lr.getMessage();
210       case 7:
211         return lr.getLocation();
212       case 8:
213         return lr.getThrownStackTrace();
214       default:
215         String message = "The column number " + col + "must be between 0 and 8";
216         throw new IllegalArgumentException(message);
217     }
218   }
219 
220   // We don't want the amount of rows to grow without bound,
221   // leading to a out-of-memory-exception.  Especially not good
222   // in a production environment :)
223 
224   // This method & clearLogRecords() are synchronized so we don't
225   // delete rows that don't exist.
226   protected void trimRecords() {
227     if (needsTrimming()) {
228       trimOldestRecords();
229     }
230   }
231 
232   protected boolean needsTrimming() {
233     return (_allRecords.size() > _maxNumberOfLogRecords);
234   }
235 
236   protected void trimOldestRecords() {
237     synchronized (_allRecords) {
238       int trim = numberOfRecordsToTrim();
239       if (trim > 1) {
240         List oldRecords =
241             _allRecords.subList(0, trim);
242         oldRecords.clear();
243         refresh();
244       } else {
245         _allRecords.remove(0);
246         fastRefresh();
247       }
248     }
249 
250   }
251 
252   //--------------------------------------------------------------------------
253   //   Private Methods:
254   //--------------------------------------------------------------------------
255   private int numberOfRecordsToTrim() {
256     return _allRecords.size() - _maxNumberOfLogRecords;
257   }
258 
259   //--------------------------------------------------------------------------
260   //   Nested Top-Level Classes or Interfaces
261   //--------------------------------------------------------------------------
262 }
263