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