org.apache.log4j.lf5.viewer.FilteredLogTableModel Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.lf5.viewer;
import org.apache.log4j.lf5.LogRecord;
import org.apache.log4j.lf5.LogRecordFilter;
import org.apache.log4j.lf5.PassingLogRecordFilter;
import javax.swing.table.AbstractTableModel;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
/**
* A TableModel for LogRecords which includes filtering support.
*
* @author Richard Wan
* @author Brent Sprecher
*/
// Contributed by ThoughtWorks Inc.
public class FilteredLogTableModel
extends AbstractTableModel {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
protected LogRecordFilter _filter = new PassingLogRecordFilter();
protected List _allRecords = new ArrayList();
protected List _filteredRecords;
protected int _maxNumberOfLogRecords = 5000;
protected String[] _colNames = {"Date",
"Thread",
"Message #",
"Level",
"NDC",
"Category",
"Message",
"Location",
"Thrown"};
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
public FilteredLogTableModel() {
super();
}
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
public void setLogRecordFilter(LogRecordFilter filter) {
_filter = filter;
}
public LogRecordFilter getLogRecordFilter() {
return _filter;
}
public String getColumnName(int i) {
return _colNames[i];
}
public int getColumnCount() {
return _colNames.length;
}
public int getRowCount() {
return getFilteredRecords().size();
}
public int getTotalRowCount() {
return _allRecords.size();
}
public Object getValueAt(int row, int col) {
LogRecord record = getFilteredRecord(row);
return getColumn(col, record);
}
public void setMaxNumberOfLogRecords(int maxNumRecords) {
if (maxNumRecords > 0) {
_maxNumberOfLogRecords = maxNumRecords;
}
}
public synchronized boolean addLogRecord(LogRecord record) {
_allRecords.add(record);
if (_filter.passes(record) == false) {
return false;
}
getFilteredRecords().add(record);
fireTableRowsInserted(getRowCount(), getRowCount());
trimRecords();
return true;
}
/**
* Forces the LogTableModel to requery its filters to determine
* which records to display.
*/
public synchronized void refresh() {
_filteredRecords = createFilteredRecordsList();
fireTableDataChanged();
}
public synchronized void fastRefresh() {
_filteredRecords.remove(0);
fireTableRowsDeleted(0, 0);
}
/**
* Clears all records from the LogTableModel
*/
public synchronized void clear() {
_allRecords.clear();
_filteredRecords.clear();
fireTableDataChanged();
}
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
protected List getFilteredRecords() {
if (_filteredRecords == null) {
refresh();
}
return _filteredRecords;
}
protected List createFilteredRecordsList() {
List result = new ArrayList();
Iterator records = _allRecords.iterator();
LogRecord current;
while (records.hasNext()) {
current = (LogRecord) records.next();
if (_filter.passes(current)) {
result.add(current);
}
}
return result;
}
protected LogRecord getFilteredRecord(int row) {
List records = getFilteredRecords();
int size = records.size();
if (row < size) {
return (LogRecord) records.get(row);
}
// a minor problem has happened. JTable has asked for
// a row outside the bounds, because the size of
// _filteredRecords has changed while it was looping.
// return the last row.
return (LogRecord) records.get(size - 1);
}
protected Object getColumn(int col, LogRecord lr) {
if (lr == null) {
return "NULL Column";
}
String date = new Date(lr.getMillis()).toString();
switch (col) {
case 0:
return date + " (" + lr.getMillis() + ")";
case 1:
return lr.getThreadDescription();
case 2:
return new Long(lr.getSequenceNumber());
case 3:
return lr.getLevel();
case 4:
return lr.getNDC();
case 5:
return lr.getCategory();
case 6:
return lr.getMessage();
case 7:
return lr.getLocation();
case 8:
return lr.getThrownStackTrace();
default:
String message = "The column number " + col + "must be between 0 and 8";
throw new IllegalArgumentException(message);
}
}
// We don't want the amount of rows to grow without bound,
// leading to a out-of-memory-exception. Especially not good
// in a production environment :)
// This method & clearLogRecords() are synchronized so we don't
// delete rows that don't exist.
protected void trimRecords() {
if (needsTrimming()) {
trimOldestRecords();
}
}
protected boolean needsTrimming() {
return (_allRecords.size() > _maxNumberOfLogRecords);
}
protected void trimOldestRecords() {
synchronized (_allRecords) {
int trim = numberOfRecordsToTrim();
if (trim > 1) {
List oldRecords =
_allRecords.subList(0, trim);
oldRecords.clear();
refresh();
} else {
_allRecords.remove(0);
fastRefresh();
}
}
}
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
private int numberOfRecordsToTrim() {
return _allRecords.size() - _maxNumberOfLogRecords;
}
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces
//--------------------------------------------------------------------------
}