/*
* HistogramTableModel.java
*
* Thread Dump Analysis Tool, parses Thread Dump input and displays it as tree
*
* This file is part of TDA - Thread Dump Analysis Tool.
*
* TDA is free software; you can redistribute it and/or modify
* it under the terms of the Lesser GNU General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* TDA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Lesser GNU General Public License for more details.
*
* You should have received a copy of the Lesser GNU General Public License
* along with TDA; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* $Id: HistogramTableModel.java,v 1.9 2006-05-02 14:22:31 irockel Exp $
*/
package com.pironet.tda.utils;
import java.util.Vector;
import javax.swing.table.AbstractTableModel;
/**
* Provides table data model for the display of class histograms.
*
* @author irockel
*/
public class HistogramTableModel extends AbstractTableModel {
private static int DEFINED_ROWS = 3;
private Vector elements = new Vector();
private Vector filteredElements = null;
private String[] columnNames = {"class name",
"instance count",
"#bytes"};
private boolean oom;
private long bytes;
private long instances;
private String filter;
private boolean ignoreCase = false;
private boolean showHotspotClasses = false;
private boolean incomplete = false;
/**
* Creates a new instance of HistogramTableModel
*/
public HistogramTableModel() {
}
public void addEntry(String className, int instanceCount, int bytes) {
elements.addElement(new Entry(className, instanceCount, bytes));
}
public Object getValueAt(int rowIndex, int columnIndex) {
if(filteredElements != null) {
return(getValueAt(filteredElements, rowIndex, columnIndex));
} else {
return(getValueAt(elements, rowIndex, columnIndex));
}
}
private Object getValueAt(Vector elements, int rowIndex, int columnIndex) {
switch(columnIndex) {
case 0 : {
return ((Entry) elements.elementAt(rowIndex)).className;
}
case 1 : {
return new Integer(((Entry) elements.elementAt(rowIndex)).bytes);
}
case 2 : {
return new Integer(((Entry) elements.elementAt(rowIndex)).instanceCount);
}
}
return null;
}
public String getColumnName(int col) {
return columnNames[col];
}
public int getRowCount() {
if(filteredElements != null) {
return filteredElements.size();
} else {
return elements.size();
}
}
public int getColumnCount() {
return DEFINED_ROWS;
}
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
private void setOOM(boolean value) {
oom = value;
}
public boolean isOOM() {
return (oom);
}
public void setBytes(long value) {
bytes = value;
}
public long getBytes() {
return(bytes);
}
public void setInstances(long value) {
instances = value;
}
public long getInstances() {
return(instances);
}
public void setIncomplete(boolean value) {
incomplete = value;
}
public boolean isIncomplete() {
return(incomplete);
}
/**
* set filter to the value and revalidate model, model saves original data,
* so it can be refiltered.
* @param value the filter string
*/
public void setFilter(String value) {
filter = value;
if(isIgnoreCase()) {
value = value.toLowerCase();
}
if(((value) == null || value.equals("")) && isShowHotspotClasses()) {
filteredElements = null;
} else {
filteredElements = new Vector();
for(int i = 0; i < elements.size(); i++) {
if(isIgnoreCase()) {
if(((Entry)elements.get(i)).className.toLowerCase().indexOf(value) >= 0) {
filteredElements.add(elements.get(i));
}
} else {
if(isNotHotspotClass(((Entry)elements.get(i)).className) && (value.equals("") || (((Entry)elements.get(i)).className.indexOf(value) >= 0))) {
filteredElements.add(elements.get(i));
}
}
}
}
}
/**
* check if the className is an internal hotspot class
* @param className the name of the class
*/
private boolean isNotHotspotClass(String className) {
//System.out.println("className" + className + " eval=" + (!isShowHotspotClasses() && className.startsWith("<")));
return(isShowHotspotClasses() || !(className.indexOf("[internal HotSpot]") >= 0));
}
public void setShowHotspotClasses(boolean value) {
if(showHotspotClasses != value) {
showHotspotClasses = value;
setFilter(getFilter());
}
}
private boolean isShowHotspotClasses() {
return(showHotspotClasses);
}
public String getFilter() {
return(filter);
}
public void setIgnoreCase(boolean value) {
if(ignoreCase != value) {
ignoreCase = value;
// revalidate
setFilter(getFilter());
}
}
public boolean isIgnoreCase() {
return(ignoreCase);
}
public class Entry {
private String className;
private int instanceCount;
private int bytes;
public Entry(String className, int instanceCount, int bytes) {
this.className = parseClassName(className);
this.instanceCount = instanceCount;
this.bytes = bytes;
}
/**
* resolve classname to something more human readable.
*/
private String parseClassName(String className) {
String result = className;
if(className.trim().endsWith("[I")) {
result = "<html><body><b>int[]</b></body></html>";
} else if (className.trim().endsWith("[B")) {
result = "<html><body><b>byte[]</b></body></html>";
} else if (className.trim().endsWith("[C")) {
result = "<html><body><b>char[]</b></body></html>";
} else if (className.trim().endsWith("[L")) {
result = "<html><body><b>long[]</b></body></html>";
} else if (className.trim().startsWith("<")) {
className = className.replaceAll("<", "<");
className = className.replaceAll(">", ">");
result = "<html><body><i><b>" + className + "</i></b> [internal HotSpot]</i></body></html>";
} else if (className.lastIndexOf('.') > 0) {
/*if(className.indexOf("OutOfMemory") >= 0) {
setOOM(true);
}*/ // that doesn't work this way
result = "<html><body>" + className.substring(0, className.lastIndexOf('.')+1) + "<b>" +
className.substring(className.lastIndexOf('.')+1) + "</b></body></html>";
}
if(className.trim().startsWith("[[")) {
result = result.replaceAll("\\[\\]", "[][]");
}
return(result);
}
}
}