src/main/java/gchisto/gctrace/RCWithGCTraceCheckpoint.java
public class RCWithGCTraceCheckpoint implements RefresherCallback {

    final private GCTraceCheckpoint checkpoint;
    final private Locker locker;
    final private RCWithGCTraceCheckpointCallback callback;

    public boolean shouldRefresh() {
        return checkpoint.needsCheckpoint();
    }

    public void beforeAddingTask() {
        locker.doWhileLocked(new Runnable() {

            public void run() {
                checkpoint.checkpoint();
            }
        });
    }

    public void refresh() {
        callback.refresh(checkpoint);
    }

    public RCWithGCTraceCheckpoint(
            GCTraceCheckpoint checkpoint,
            Locker locker,
            RCWithGCTraceCheckpointCallback callback) {
        this.checkpoint = checkpoint;
        this.locker = locker;
        this.callback = callback;
    }
}
src/main/java/gchisto/utils/Refresher.java
public class Refresher {

    private class Task implements WorkerTask {

        public void doIt() {
            callback.refresh();
            completeTask();
        }
    }
    final private WorkerThread workerThread;
    final private RefresherCallback callback;
    boolean inProgress = false;
    boolean pending = false;

    private void addTask() {
        inProgress = true;
        callback.beforeAddingTask();
        workerThread.add(new Task());
    }

    synchronized private void completeTask() {
        if (pending) {
            addTask();
            pending = false;
        } else {
            inProgress = false;
        }
    }

    public void possiblyRefresh() {
        if (!pending) {
            possiblyRefreshInternal();
        }
    }

    synchronized public void possiblyRefreshInternal() {
        if (callback.shouldRefresh()) {
            if (!inProgress) {
                addTask();
            } else {
                pending = true;
            }
        }
    }

    public Refresher(
            WorkerThread workerThread,
            RefresherCallback callback) {
        this.workerThread = workerThread;
        this.callback = callback;
    }
}
src/main/java/gchisto/jfreechart/extensions/ChartLocker.java
public class ChartLocker extends Locker implements ChartProgressListener {

    public void chartProgress(ChartProgressEvent event) {
        switch (event.getType()) {
            case ChartProgressEvent.DRAWING_STARTED:
                lock();
                break;
            case ChartProgressEvent.DRAWING_FINISHED:
                unlock();
                break;
        }
    }
}
src/main/java/gchisto/utils/WorkerThread.java
public class WorkerThread extends Thread {
    
    private Queue<WorkerTask> queue = new LinkedList<WorkerTask>();
    
    static final private WorkerThread instance;
    
    static {
        instance = new WorkerThread();
        instance.start();
    }
    
    static public WorkerThread instance() {
        return instance;
    }
    
    public void run() {
        while (true) {
            WorkerTask task;
            synchronized (this) {
                task = queue.poll();
                while (task == null) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                    }
                    task = queue.poll();
                }
            }

            task.doIt();
        }
    }
    
    synchronized public void add(WorkerTask task) {
        queue.offer(task);
        notifyAll();
    }
    
    private WorkerThread() {
    }
    
}
src/main/java/gchisto/gctrace/RCWithGCTraceCheckpointCallback.java
public interface RCWithGCTraceCheckpointCallback {

    public void refresh(GCTraceCheckpoint checkpoint);
    
}
src/main/java/gchisto/gcactivity/GCActivitySet.java
public class GCActivitySet extends ArrayList<GCActivity> {
    
    /**
     * The name of the GC activities in the set. This name is the "kind"
     * of the GC activities in the set.
     *
     * @see #getGCActivityName()
     */
    final private String gcActivityName;
    
    final private NumberSeq numberSeq = new NumberSeq();
    
    /**
     * It adds a new GC activity to the set. After adding it, it will call the
     * <tt>added()</tt> method on the listeners of this set.
     *
     * @param gcActivity The GC activity to be added to the set.
     */
    public void addGCActivity(GCActivity gcActivity) {
        assert gcActivity != null;
        
        add(gcActivity);
        numberSeq.add(gcActivity.getDurationSec());
    }
    
    /**
     * It returns the name of the GC activities in the set. This name is 
     * the "kind" of the GC activities in the set.
     *
     * @return The name of the GC activities in the set.
     */
    public String getGCActivityName() {
        return gcActivityName;
    }
    
    public NumberSeq getNumberSeq() {
        return numberSeq;
    }
    
    /**
     * It verifies the correctness of the contents in the set.
     */
    public void verify() {
        throw new NotImplementedException();
    }
    
    /**
     * It creates a new GC activity set instance.
     * 
     * @param gcActivityName The name of the GC activites in the set. This
     * name is the "kind" of the GC activities in the set.
     */
    public GCActivitySet(String gcActivityName) {
        this.gcActivityName = gcActivityName;
    }
    
}
src/main/java/gchisto/gcactivity/GCActivity.java
public class GCActivity {
    
    private String name;
    
    /**
     * The time stamp of the start of the GC activity, in seconds.
     *
     * @see #getStartSec()
     */
    private double startSec;
    
    /**
     * The duration of the GC activity, in seconds.
     *
     * @see #getDurationSec()
     */
    private double durationSec;
    
    /**
     * It indicates whether the GC activity is stop-the-world (true),
     * or concurrent (false).
     *
     * @see #isSTW()
     */
    private boolean stw;
    
    /**
     * The overhead percentage of the GC activity.
     *
     * @see #getOverheadPerc()
     */
    private double overheadPerc;
    
    public String getName() {
        return name;
    }
    
    /**
     * It returns the time stamp of the start of the GC activity, in seconds. 
     *
     * @return The time stamp of the start of the GC activity, in seconds. 
     */
    public double getStartSec() {
        return startSec;
    }
    
    /**
     * It returns the time stamp of the end of the GC activity, in seconds. 
     *
     * @return The time stamp of the end of the GC activity, in seconds. 
     */
    public double getEndSec() {
        return startSec + durationSec;
    }
    
    /**
     * It returns the duration of the GC activity, in seconds. 
     *
     * @return The duration of the GC activity, in seconds. 
     */
    public double getDurationSec() {
        return durationSec;
    }
    
    /**
     * It returns whether the GC activity is stop-the-world.
     *
     * @return Whether the GC activity is stop-the-world.
     */
    public boolean isSTW() {
        return stw;
    }
    
    /**
     * It returns whether the GC activity is concurrent.
     *
     * @return Whether the GC activity is concurrent.
     */
    public boolean isConcurrent() {
        return !stw;
    }
    
    /**
     * It returns the overhead percentage of the GC activity.
     *
     * @return The overhead percentage of the GC activity.
     */
    public double getOverheadPerc() {
        return overheadPerc;
    }
    
    /**
     * It creates a new GC activity instance. This version should be used for
     * stop-the-world GC activities.
     *
     * @param startSec The time stamp of the start of the GC activity, in
     * seconds.
     * @param durationSec The duration of the GC activity, in seconds.
     */
    public GCActivity(
            String name,
            double startSec,
            double durationSec) {
        this(name, startSec, durationSec, true, 100.0);
    }
    
    /**
     * It creates a new GC activity instance. This version should be used for
     * concurrent GC activities.
     *
     * @param startSec The time stamp of the start of the GC activity, in
     * seconds.
     * @param durationSec The duration of the GC activity, in seconds.
     * @param overheadPerc The concurrent overhead of the GC activity.
     */
    public GCActivity(
            String name,
            double startSec,
            double durationSec,
            double overheadPerc) {
        this(name, startSec, durationSec, false, overheadPerc);
    }
    
    /**
     * It creates a new GC activity instance. This is a private constructor
     * for use by the public ones.
     *
     * @param startSec The time stamp of the start of the GC activity, in
     * seconds.
     * @param durationSec The duration of the GC activity, in seconds.
     * @param stw It indicates whether the GC activity is stop-the-world (true),
     * or concurrent (false).
     * @param overheadPerc The concurrent overhead of the GC activity.
     */
    private GCActivity(
            String name,
            double startSec,
            double durationSec,
            boolean stw,
            double overheadPerc) {
        ArgumentChecking.lowerBound(startSec, 0.0, "startSec");
        ArgumentChecking.lowerBound(durationSec, 0.0, "durationSec");
        ArgumentChecking.withinBounds(overheadPerc, 0.0, 100.0, "oveheadPerc");
        
        this.name = name;
        this.startSec = startSec;
        this.durationSec = durationSec;
        this.stw = stw;
        this.overheadPerc = overheadPerc;
    }
    
}
src/main/java/gchisto/gui/utils/AbstractChartPanel.java
abstract public class AbstractChartPanel extends javax.swing.JPanel {
    
    /**
     * The title of the panel.
     */
    private String title;
    
    /**
     * The optional unit name of the data shown in the panel. If it is
     * <tt>null</tt>, the unit name is ignored.
     */
    private String unitName;
    
    /**
     * It returns the title of the panel which optionally has the unit name
     * as its suffix.
     *
     * @return The title of the panel.
     */
    public String getTitle() {
        return title + unitSuffix();
    }
    
    /**
     * It returns the optional suffix of the title, which includes the
     * unit name in round brackets. If the unitName name is <tt>null</tt>,
     * it returns an empty string.
     *
     * @return The title suffix, or an empty string if the unitName name
     * is <tt>null</tt>.
     */
    public String unitSuffix() {
        return (unitName != null) ? " (" + unitName + ")" : "";
    }
    
    /**
     * It returns the panel it which the chart should be added. The layout
     * of the panel is <tt>BorderLayout</tt>.
     *
     * @return The panel in which the chart should be added.
     *
     * @see java.awt.BorderLayout
     */
    protected JPanel mainPanel() {
        return mainPanel;
    }
    
    /**
     * It creates a new instance of the chart panel and associates with 
     * it the given title and no unit name.
     *
     * @param title The title to be associated with the new chart panel.
     */
    protected AbstractChartPanel(String title) {
        this(title, null);
    }
    
    /**
     * It creates a new instance of the chart panel and associates with
     * it the given title and unit name.
     *
     * @param title The title to be associated with the new chart panel.
     * @param unitName The unit name to be associated with the new chart panel.
     */
    protected AbstractChartPanel(String title, String unitName) {
        ArgumentChecking.notNull(title, "title");
        
        initComponents();
        
        this.title = title;
        this.unitName = unitName;
    }
    
    /**
     * Private constructor with no arguments so that it is not called.
     */
    private AbstractChartPanel() {
        initComponents();
    }
    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
    private void initComponents() {
        mainPanel = new javax.swing.JPanel();

        mainPanel.setLayout(new java.awt.BorderLayout());

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(mainPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(mainPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addContainerGap())
        );
    }// </editor-fold>//GEN-END:initComponents
    
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JPanel mainPanel;
    // End of variables declaration//GEN-END:variables
    
}
src/main/java/gchisto/gui/utils/GroupActivatingPanel.java
public class GroupActivatingPanel extends javax.swing.JPanel {

    /**
     * The column header names.
     *
     * @see Model
     */
    static private final String COLUMN_NAMES[] = {"Name", "Active"};
    /**
     * The classes of the cells in each column.
     *
     * @see Model
     */
    static private final Class COLUMN_CLASSES[] = {String.class, Boolean.class};
    /**
     * Whether the cells in each column are editable.
     *
     * @see Model
     */
    static private final boolean COLUMN_EDITABLE[] = {false, true};
    /**
     * The active dataset which will be notified when groups are activated
     * or de-activated.
     */
    final private DatasetWithGroups dataset;
    final private Locker locker;
    final private Model model;

    /**
     * A string renderer for the table. Right now, it's only used for the
     * row headers.
     */
    private class StringRenderer implements TableCellRenderer {

        /**
         * It returns a new label for a particular table cell.
         *
         * @param table The table in which the label will be included.
         * @param value A string representing the text for the label.
         * @param isSelected Whether the label is selected or not; currently
         * this is ignored.
         * @param hasFocus Whether the label has focus or not; currently
         * this is ignored.
         * @param row The row in which the label will be added.
         * @param col The column in which the label will be added.
         * @return A new label for a particular table cell.
         */
        public Component getTableCellRendererComponent(
                JTable table,
                Object value,
                boolean isSelected,
                boolean hasFocus,
                int row,
                int col) {
            assert col == 0;
            assert value instanceof String;

            String str = (String) value;
            JLabel label = GUIUtilities.createJLabelForTable(str);
            GUIUtilities.setTableHeader(label);
            return label;
        }
    }

    /**
     * A boolean renderer for the table. Right now, it is only used for the
     * check boxes which active / de-activate each group.
     */
    private class BooleanRenderer implements TableCellRenderer {

        /**
         * It returns a new check box for a particular table cell.
         *
         * @param table The table in which the check box will be included.
         * @param value A boolean representing whether the check box should
         * be selected or not.
         * @param isSelected Whether the check box is selected or not;
         * currently this is ignored.
         * @param hasFocus Whether the check box has focus or not; currently
         * this is ignored.
         * @param row The row in which the check box will be added.
         * @param col The column in which the check box will be added.
         * @return A new check box for a particular table cell.
         */
        public Component getTableCellRendererComponent(
                JTable table,
                Object value,
                boolean isSelected,
                boolean hasFocus,
                int row,
                int col) {
            assert col == 1 : "row =" + row + " col = " + col;
            assert value instanceof Boolean;

            boolean selected = ((Boolean) value).booleanValue();
            JCheckBox checkBox = GUIUtilities.createJCheckBoxForTable(selected);
            return checkBox;
        }
    }

    /**
     * The model for the table. The values for the cells it returns are the
     * following:
     * <ul>
     * <li> column 0 (<tt>String</tt>): the name of the row
     * <li> column 1 (<tt>Boolean</tt>): whether the corresponding name is
     * active or not
     * </ul>
     */
    private class Model extends AbstractTableModel {

        /**
         * It returns the number of rows in the table.
         *
         * @return The number of rows in the table.
         */
        public int getRowCount() {
            return dataset.getGroupCount();
        }

        /**
         * It returns the number of columns in the table.
         *
         * @return The number of columns in the table.
         */
        public int getColumnCount() {
            return COLUMN_NAMES.length;
        }

        /**
         * It returns the column name for the specified column.
         *
         * @param columnIndex The index of the column whose header will
         * be returned.
         * @return The column name for the specified column.
         */
        public String getColumnName(int columnIndex) {
            return COLUMN_NAMES[columnIndex];
        }

        /**
         * It returns the class of the table cells in the specified column.
         *
         * @param columnIndex The index of the column whose content class
         * will be returned.
         * @return The class of the table cells in the specified column.
         */
        public Class<?> getColumnClass(int columnIndex) {
            return COLUMN_CLASSES[columnIndex];
        }

        /**
         * It determines whether the specified table cell is editable.
         *
         * @param rowIndex The row index of the specified table cell.
         * @param columnIndex The column index of the specified table cell.
         * @return Whether the specified table cell is editable.
         */
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return COLUMN_EDITABLE[columnIndex];
        }

        /**
         * It returns the value of the specified table cell.
         *
         * @param rowIndex The row index of the specified table cell.
         * @param columnIndex The column index of the specified table cell.
         * @return The value of the specified table cell.
         */
        public Object getValueAt(int rowIndex, int columnIndex) {
            switch (columnIndex) {
                case 0:
                    return dataset.getGroupName(rowIndex);
                case 1:
                    return dataset.isGroupActive(rowIndex);
                default:
                    throw new ShouldNotReachHereException();
            }
        }

        /**
         * It sets a new value for a particular table cell.
         *
         * @param value The new value for the specified table cell.
         * @param rowIndex The row index of the specified table cell.
         * @param columnIndex The column index of the specified table cell.
         */
        public void setValueAt(Object value, final int rowIndex, int columnIndex) {
            assert columnIndex == 1;
            assert COLUMN_EDITABLE[columnIndex];
            assert value instanceof Boolean;

            final boolean active = ((Boolean) value).booleanValue();
            locker.doWhileLocked(new Runnable() {

                public void run() {
                    dataset.setGroupActive(rowIndex, active);
                }
            });
        }
    }

    public void groupAdded() {
        model.fireTableStructureChanged();
    }
    
    /**
     * It creates a new instance of the group activating / de-acticating panel.
     *
     * @param dataset The dataset that holds whether the groups are
     * activated / de-activated and that will be notified when changes
     * are made.
     */
    public GroupActivatingPanel(DatasetWithGroups dataset, Locker locker) {
        this.dataset = dataset;
        this.locker = locker;
        this.model = new Model();

        initComponents();

        table.setDefaultRenderer(String.class, new StringRenderer());
        table.setDefaultRenderer(Boolean.class, new BooleanRenderer());

        JTableHeader header = table.getTableHeader();
        header.setReorderingAllowed(false);
        GUIUtilities.setTableHeader(header);

        table.setModel(model);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
    private void initComponents() {
        tableScrollPane = new javax.swing.JScrollPane();
        table = new javax.swing.JTable();

        table.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null}
            },
            new String [] {
                "Title 1", "Title 2", "Title 3", "Title 4"
            }
        ));
        tableScrollPane.setViewportView(table);

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(tableScrollPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(tableScrollPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
        );
    }// </editor-fold>//GEN-END:initComponents
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JTable table;
    private javax.swing.JScrollPane tableScrollPane;
    // End of variables declaration//GEN-END:variables
}
src/main/java/gchisto/gctrace/GCTrace.java
public abstract class GCTrace extends ArrayList<GCActivitySet> {

    /**
     * The name that is associated with this GC trace. This is unique across
     * all the GC traces that are included in a single GC trace set.
     *
     * @see #getName()
     * @see #setName(String)
     * @see gchisto.gctraceset.GCTraceSet#createUniqueGCTraceName(File)
     */
    private String name;
    /**
     * The date/time when this GC trace was populated.
     *
     * @see #getAddedDate()
     * @see #setAddedDate(Date)
     *
     * TODO
     */
    private Date addedDate;
    /**
     * A map of the GC activity names that appear in this GC trace.
     */
    final private GCActivityNames gcActivityNames = new GCActivityNames();
    /**
     * TODO
     */
    final private GCTraceListenerSet listeners = new GCTraceListenerSet();
    final private Object hashCodeObject = new Object();
    final private GCActivitySet allGCActivities = new GCActivitySet("All");
    private double lastTimeStampSec;

    /**
     * TODO
     */
    abstract public String getSuggestedName();

    /**
     * TODO
     */
    abstract public String getInfoString();

    public boolean equals(Object gcTrace) {
        assert gcTrace instanceof GCTrace;
        return ((GCTrace) gcTrace).hashCodeObject == hashCodeObject;
    }

    public int hashCode() {
        return hashCodeObject.hashCode();
    }

    /**
     * It returns the name that is associated with this GC trace. This is
     * unique across all the GC traces that are included in a single GC trace
     * set.
     *
     * @return The name that is associated with this GC trace. This is
     * unique across all the GC traces that are included in a single GC trace
     * set.
     *
     * @see #setName(String)
     * @see gchisto.gctraceset.GCTraceSet#createUniqueGCTraceName(File)
     */
    public String getName() {
        return name;
    }
    
    public String getLongName() {
        return getName();
    }

    /**
     * It returns the date/time when this GC trace was populated.
     *
     * @return The date/time when this GC trace was populated.
     * @see #setAddedDate(Date)
     *
     * TODO
     */
    public Date getAddedDate() {
        return addedDate;
    }

    /**
     * It returns a map of the GC activity names that appear in this GC trace.
     *
     * @return A map of the GC activity names that appear in this GC trace.
     */
    public GCActivityNames getGCActivityNames() {
        return gcActivityNames;
    }

    public GCActivitySet getAllGCActivities() {
        return allGCActivities;
    }

    public double getLastTimeStampSec() {
        return lastTimeStampSec;
    }
    
    /**
     * It returns an array containing the GC activity names that appear in
     * this GC trace.
     *
     * @return An array containing the GC activity names that appear in this
     * GC trace.
     */
    public String[] getGCActivityNamesArray() {
        return gcActivityNames.getNames();
    }

    /**
     * It sets the name of this GC trace.
     *
     * @param name The new name of this GC trace.
     *
     * @see #getName()
     * @see gchisto.gctraceset.GCTraceSet#createUniqueGCTraceName(File)
     */
    public void setName(String name) {
        ArgumentChecking.notNull(name, "name");

        this.name = name;
    }

    /**
     * It sets the read date/time of this GC trace.
     *
     *
     * @param addedDate The new read date/time of this GC trace.
     * @see #getAddedDate()
     *
     * TODO
     */
    public void setAddedDate(Date addedDate) {
        ArgumentChecking.notNull(addedDate, "addedDate");

        this.addedDate = addedDate;
    }

    /**
     * It adds a new GC activity to this GC trace. The GC activity will be added
     * to the GC activity set that corresponds to the given GC activity name.
     * If a GC activity set does not exist in this GC trace for this GC activity
     * name, it will be created. This version should be used for concurrent
     * GC activities.
     *
     * @param gcActivityName The name of the GC activity to be added.
     * @param startSec The time stamp of the start of the GC activity to
     * be added, in seconds.
     * @param durationSec The duration of the GC activity, in seconds.
     */
    public void addGCActivity(
            int id,
            double startSec,
            double durationSec) {
        ArgumentChecking.withinBounds(id, 0, size() - 1, "id");

        String gcActivityName = gcActivityNames.get(id);
        addGCActivity(id,
                new GCActivity(gcActivityName, startSec, durationSec));
    }

    /**
     * It adds a new GC activity to this GC trace. The GC activity will be added
     * to the GC activity set that corresponds to the given GC activity name.
     * If a GC activity set does not exist in this GC trace for this GC activity
     * name, it will be created. This version should be used for stop-the-world
     * GC activities.
     *
     * @param gcActivityName The name of the GC activity to be added.
     * @param startSec The time stamp of the start of the GC activity to
     * be added, in seconds.
     * @param durationSec The duration of the GC activity, in seconds.
     * @param overheadPerc The concurrent overhead of the GC activity to
     * be added.
     */
    public void addGCActivity(
            int id,
            double startSec,
            double durationSec,
            double overheadPerc) {
        ArgumentChecking.withinBounds(id, 0, size() - 1, "id");

        String gcActivityName = gcActivityNames.get(id);
        addGCActivity(id, new GCActivity(
                gcActivityName,
                startSec, durationSec,
                overheadPerc));
    }

    /**
     * It adds a new GC activity to this GC trace. This is a private method
     * that is used by all the public ones.
     *
     * @param gcActivityName The name of the GC activity to be added.
     * @param gcActivity The GC activity to be added.
     */
    synchronized private void addGCActivity(
            int id,
            GCActivity gcActivity) {
        assert 0 <= id && id < size();
        assert 0 <= id && id < gcActivityNames.size();
        assert gcActivityNames.get(id).equals(gcActivity.getName());

        GCActivitySet gcActivitySet = get(id);
        gcActivitySet.addGCActivity(gcActivity);
        allGCActivities.addGCActivity(gcActivity);
        lastTimeStampSec = gcActivity.getEndSec();

        listeners.callGCActivityAdded(this, gcActivitySet, gcActivity);
    }

    public void addGCActivityName(int id, String gcActivityName) {
        assert gcActivityNames.size() == id;
        gcActivityNames.add(id, gcActivityName);
        assert gcActivityNames.size() == id + 1;

        assert size() == id;
        GCActivitySet gcActivitySet = new GCActivitySet(gcActivityName);
        add(id, gcActivitySet);
        assert size() == id + 1;

        listeners.callGCActivityNameAdded(this, id, gcActivityName);
    }

    /**
     * TODO
     */
    synchronized public void addListener(GCTraceListener listener) {
        ArgumentChecking.notNull(listener, "listener");

        listeners.add(listener);
    }

    /**
     * TODO
     */
    synchronized public void removeListener(GCTraceListener listener) {
        ArgumentChecking.notNull(listener, "listener");

        listeners.remove(listener);
    }

    /**
     * TODO
     */
    public void afterAddingToGCTraceSet() {
    // do nothing, unless overriden
    }

    /**
     * TODO
     */
    public void beforeRemovingFromGCTraceSet() {
    // do nothing, unless overriden
    // this has to return before the GC trace is removed from the GC trace set
    }

    /**
     * It creates a new GC trace instance.
     *
     * @param file The file associated with the new GC trace.
     * @param lastModifiedDate The last modified date/time of the new GC trace.
     * @param addedDate Thenew read date/time of the new GC trace.
     *
     * TODO
     */
    public GCTrace() {
    }
}
src/main/java/gchisto/gctrace/GCTraceCheckpoint.java
public class GCTraceCheckpoint {

    private GCTrace gcTrace;
    private int gcTraceSize;
    private List<Integer> prevCheckpointedSizes = new ArrayList<Integer>();
    private List<Integer> checkpointedSizes = new ArrayList<Integer>();
    private int prevAllSize;
    private int allSize;

    synchronized public void checkpoint() {
        assert prevCheckpointedSizes.size() == gcTraceSize;
        assert checkpointedSizes.size() == gcTraceSize;

        for (int i = 0; i < gcTraceSize; ++i) {
            int size = checkpointedSizes.get(i);
            prevCheckpointedSizes.set(i, size);
        }
        prevAllSize = allSize;

        for (int i = 0; i < gcTraceSize; ++i) {
            int size = gcTrace.get(i).size();
            checkpointedSizes.set(i, size);
        }
        allSize = gcTrace.getAllGCActivities().size();
    }

    public int gcTraceSize() {
        return gcTraceSize;
    }

    public int prevSize(int index) {
        return prevCheckpointedSizes.get(index);
    }

    public int size(int index) {
        return checkpointedSizes.get(index);
    }

    public int prevAllGCActivitiesSize() {
        return prevAllSize;
    }

    public int allGCActivitiesSize() {
        return allSize;
    }

    public boolean needsCheckpoint() {
        for (int i = 0; i < gcTraceSize; ++i) {
            if (checkpointedSizes.get(i) != gcTrace.get(i).size()) {
                return true;
            }
        }
        if (allSize != gcTrace.getAllGCActivities().size()) {
            return true;
        }
        return false;
    }

    public void extend(int id) {
        assert id == gcTraceSize;
        int newGCTraceSize = gcTraceSize + 1;
        assert prevCheckpointedSizes.size() == newGCTraceSize - 1;
        assert checkpointedSizes.size() == newGCTraceSize - 1;
        prevCheckpointedSizes.add(id, 0);
        checkpointedSizes.add(id, 0);
        assert prevCheckpointedSizes.size() == newGCTraceSize;
        assert checkpointedSizes.size() == newGCTraceSize;
        gcTraceSize = newGCTraceSize;
    }

    private void extendSizes() {
        assert gcTraceSize == 0;
        
        int newGCTraceSize = gcTrace.size();
        for (int i = 0; i < newGCTraceSize; ++i) {
            extend(i);
        }
        
        assert gcTraceSize == newGCTraceSize;
    }

    public GCTraceCheckpoint(GCTrace gcTrace) {
        this.gcTrace = gcTrace;
        this.gcTraceSize = 0;
        this.prevAllSize = 0;
        this.allSize = 0;

        extendSizes();
    }
}
src/main/java/gchisto/gctrace/GCTraceListener.java
public interface GCTraceListener {

    /**
     * TODO
     */
    public void gcActivityAdded(
            GCTrace gcTrace,
            GCActivitySet gcActivitySet,
            GCActivity gcActivity);

    public void gcActivityNameAdded(
            GCTrace gcTrace,
            int id,
            String gcActivityName);
}


Question: import gchisto.gcactivity.GCActivity;
import gchisto.gcactivity.GCActivitySet;
import gchisto.gctrace.GCTrace;
import gchisto.gctrace.GCTraceCheckpoint;
import gchisto.gctrace.GCTraceListener;
import gchisto.gctrace.RCWithGCTraceCheckpoint;
import gchisto.gctrace.RCWithGCTraceCheckpointCallback;
import gchisto.gui.utils.AbstractChartPanel;
import gchisto.gui.utils.GroupActivatingPanel;
import gchisto.jfreechart.extensions.ChartLocker;
import gchisto.utils.Refresher;
import gchisto.utils.WorkerThread;
import java.awt.BorderLayout;
import javax.swing.JSplitPane;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
/*
 * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code 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 GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 *
 */
package gchisto.gui.panels.gcdistribution;


/**
 * A panel that contains a bar chart that shows the GC pause time distribution.
 * Each such panel will be added to the tabbed pane of the main GC distribution
 * panel.
 *
 * @author Tony Printezis
 */
public class ChartPanelSingle extends AbstractChartPanel
        implements GCTraceListener, RCWithGCTraceCheckpointCallback {

    final private Dataset dataset;
    final private Refresher refresher;
    final private ChartLocker locker = new ChartLocker();
    final private GCTraceCheckpoint checkpoint;
    private GroupActivatingPanel groupActivatingPanel;

    /**
     * It creates a chart for the given dataset and adds the chart to the panel.
     *
     * @param dataset The dataset that will provide the values for the chart.
     */
    private void addChart() {
        JFreeChart chart = ChartFactory.createXYBarChart(getTitle(),
                "Buckets (sec)", false, "Count",
                dataset, PlotOrientation.VERTICAL, true, true, false);
        chart.addProgressListener(locker);
        XYPlot plot = (XYPlot) chart.getPlot();
        XYItemRenderer renderer = plot.getRenderer();
        renderer.setToolTipGenerator(dataset);

        groupActivatingPanel = new GroupActivatingPanel(dataset, locker);

        org.jfree.chart.ChartPanel chartPanel =
                new org.jfree.chart.ChartPanel(chart);
        JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
                groupActivatingPanel,chartPanel);
        splitPane.setDividerLocation(200);
        mainPanel().add(BorderLayout.CENTER, splitPane);
    }

    public void refresh(GCTraceCheckpoint checkpoint) {
        locker.doWhileLocked(new Runnable() {

            public void run() {
                dataset.updateBuckets();
                dataset.datasetChanged();
            }
        });
    }

    public void possiblyRefresh() {
        refresher.possiblyRefresh();
    }

    public void gcActivityAdded(
            GCTrace gcTrace,
Answer:             GCActivitySet gcActivitySet,