org.gridchem.client.gui.charts.UsageChart.java Source code

Java tutorial

Introduction

Here is the source code for org.gridchem.client.gui.charts.UsageChart.java

Source

/*Copyright (c) 2004,University of Illinois at Urbana-Champaign.  All rights reserved.
 * 
 * Created on Feb 27, 2007
 * 
 * Developed by: CCT, Center for Computation and Technology, 
 *             NCSA, University of Illinois at Urbana-Champaign
 *             OSC, Ohio Supercomputing Center
 *             TACC, Texas Advanced Computing Center
 *             UKy, University of Kentucky
 * 
 * https://www.gridchem.org/
 * 
 * Permission is hereby granted, free of charge, to any person 
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal with the Software without 
 * restriction, including without limitation the rights to use, 
 * copy, modify, merge, publish, distribute, sublicense, and/or 
 * sell copies of the Software, and to permit persons to whom 
 * the Software is furnished to do so, subject to the following conditions:
 * 1. Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimers.
 * 2. Redistributions in binary form must reproduce the above copyright notice, 
 *    this list of conditions and the following disclaimers in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the names of Chemistry and Computational Biology Group , NCSA, 
 *    University of Illinois at Urbana-Champaign, nor the names of its contributors 
 *    may be used to endorse or promote products derived from this Software without 
 *    specific prior written permission.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  
 * IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS WITH THE SOFTWARE.
*/

package org.gridchem.client.gui.charts;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;

import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerListModel;
import javax.swing.SpinnerModel;

import org.gridchem.client.GridChem;
import org.gridchem.client.util.GMS3;
import org.gridchem.service.beans.CollaboratorBean;
import org.gridchem.service.beans.ComputeBean;
import org.gridchem.service.beans.ProjectBean;
import org.gridchem.service.beans.UsageBean;
import org.gridchem.service.beans.UserBean;
import org.gridchem.service.model.enumeration.AccessType;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.general.DefaultPieDataset;

/**
 * Simple Pie chart displaying user's relative usage load.
 * 
 * @author Rion Dooley < dooley [at] tacc [dot] utexas [dot] edu >
 *
 */
public class UsageChart extends JPanel {
    public enum ChartType {
        PROJECT("project"), JOB("job"), RESOURCE("resource"), USER("user");

        String value;

        private ChartType(String value) {
            this.value = value;
        }

        public String value() {
            return value;
        }

        public ChartType next() {
            ChartType[] values = this.values();
            int i;

            for (i = 0; i < values.length; i++) {
                if (value.equals(values[i].value())) {
                    if (i == values.length - 1) {
                        i = 0;
                        break;
                    } else {
                        i++;
                        break;
                    }
                }
            }

            return values[i];
        }

        public ChartType previous() {
            ChartType[] values = this.values();
            int i;

            for (i = 0; i < values.length; i++) {
                if (value.equals(values[i].value())) {
                    if (i == 0) {
                        i = values.length - 1;
                        break;
                    } else {
                        i--;
                        break;
                    }
                }
            }

            return values[i];
        }
    }

    protected static ChartType CURRENT_CHARTTYPE;
    protected static Hashtable<ProjectBean, List<CollaboratorBean>> projectCollabTable;
    protected JPanel navPanel;

    private JSpinner chartTypeSpinner;
    private CyclingSpinnerListModel chartTypeListModel;

    private JFreeChart chart = null;
    private ChartPanel chartPanel = null;
    protected DefaultPieDataset dataset = null;

    private Dimension size = new Dimension(200, 200);

    private int defaultProjectIndex = 0;

    private static CollaboratorBean collab = null;

    public UsageChart(Hashtable<ProjectBean, List<CollaboratorBean>> projectTable) {
        super();

        UsageChart.projectCollabTable = projectTable;

        CURRENT_CHARTTYPE = ChartType.PROJECT;

        navPanel = createSelectionBar();

        init();

    }

    public UsageChart(Hashtable<ProjectBean, List<CollaboratorBean>> projectTable, ChartType type) {
        super();

        this.projectCollabTable = projectTable;

        CURRENT_CHARTTYPE = type;

        navPanel = createSelectionBar();

        init();

    }

    public UsageChart(ProjectBean project, List<CollaboratorBean> collabs, ChartType type) {

        super();

        CURRENT_CHARTTYPE = type;

        projectCollabTable = new Hashtable<ProjectBean, List<CollaboratorBean>>();

        HashSet<ProjectBean> projects = new HashSet<ProjectBean>();
        projects.add(project);

        projectCollabTable.put(project, collabs);

        navPanel = createSelectionBar();

        init();

    }

    private void init() {

        removeAll();
        String title = "";

        if (CURRENT_CHARTTYPE.equals(ChartType.JOB)) {
            //            dataset = createJobDataset(projectTable);
            dataset = new DefaultPieDataset();
        } else if (CURRENT_CHARTTYPE.equals(ChartType.PROJECT)) {
            dataset = createProjectDataset(projectCollabTable);
            title = "CCG Utilization by Project";
        } else if (CURRENT_CHARTTYPE.equals(ChartType.RESOURCE)) {
            dataset = createResourceDataset(projectCollabTable);
            title = "CCG Utilization by Resource";
        } else if (CURRENT_CHARTTYPE.equals(ChartType.USER)) {
            dataset = createUserDataset(projectCollabTable);
            title = "CCG Utilization by User";
        }

        chart = ChartFactory.createPieChart(title, // chart title
                dataset, // data
                false, // include legend
                true, // tooltips?
                false // URLs?
        );

        if (projectCollabTable.size() == 1) {
            ProjectBean project = projectCollabTable.keySet().iterator().next();
            chart.addSubtitle(
                    new TextTitle("Project " + project.getName() + " expires on " + project.getEndDate()));
        }

        ((PiePlot) chart.getPlot()).setCircular(true);

        //        ((PiePlot)chart.getPlot()).setExplodePercent(new Integer(defaultProjectIndex), 25);

        if (CURRENT_CHARTTYPE.equals(ChartType.JOB)) {
            chart.getPlot().setNoDataMessage("Comprehensive job information is not currently available.");
        }

        chartPanel = new ChartPanel(chart);
        chartPanel.setPreferredSize(size);

        setLayout(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        c.weightx = 1.0;
        c.weighty = 1.0;
        c.gridx = 0;
        c.gridy = 0;
        c.fill = GridBagConstraints.BOTH;
        add(chartPanel, c);

        GridBagConstraints c1 = new GridBagConstraints();
        c1.weightx = 0;
        c1.weighty = 0;
        c1.gridx = 0;
        c1.gridy = 1;
        c1.fill = GridBagConstraints.BOTH;
        add(navPanel, c1);
        revalidate();

        //        setPreferredSize(size);

    }

    private void init(CollaboratorBean collab) {

        removeAll();

        // TODO: Add title and footer with expiration date to chart
        String title = "";
        ProjectBean project = projectCollabTable.keySet().iterator().next();
        //        
        if (CURRENT_CHARTTYPE.equals(ChartType.JOB)) {
            //          dataset = createJobDataset(project);
            dataset = new DefaultPieDataset();
        } else if (CURRENT_CHARTTYPE.equals(ChartType.PROJECT)) {
            dataset = createProjectDataset(projectCollabTable, collab);
            title = "Overall Utilization of Project " + project.getName() + " by " + collab.getFirstName() + " "
                    + collab.getLastName();
            ;
        } else if (CURRENT_CHARTTYPE.equals(ChartType.RESOURCE)) {
            dataset = createResourceDataset(projectCollabTable, collab);
            title = "CCG Resource Utilization for Project " + project.getName() + " by " + collab.getFirstName()
                    + " " + collab.getLastName();
            ;
        } else if (CURRENT_CHARTTYPE.equals(ChartType.USER)) {
            dataset = createUserDataset(projectCollabTable, collab);
            title = "User Utilization of Project " + project.getName() + " by " + collab.getFirstName() + " "
                    + collab.getLastName();
        }

        JFreeChart chart = ChartFactory.createPieChart(title, // chart title
                dataset, // data
                false, // include legend
                true, // tooltips?
                false // URLs?
        );

        chart.addSubtitle(new TextTitle("Project " + project.getName() + " expires on " + project.getEndDate()));

        if (CURRENT_CHARTTYPE.equals(ChartType.JOB)) {
            chart.getPlot().setNoDataMessage("Comprehensive job information is not currently available.");
        }

        ((PiePlot) chart.getPlot()).setCircular(true);

        //        ((PiePlot)chart.getPlot()).setToolTipGenerator(new PieToolTipGenerator() {
        //
        //            public String generateToolTip(PieDataset ds, Comparable arg1) {
        //                // TODO Auto-generated method stub
        //                return ";
        //            }
        //            
        //        });

        chartPanel = new ChartPanel(chart);
        chartPanel.setPreferredSize(size);

        setLayout(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        c.weightx = 1.0;
        c.weighty = 1.0;
        c.gridx = 0;
        c.gridy = 0;
        c.fill = GridBagConstraints.BOTH;
        add(chartPanel, c);

        GridBagConstraints c1 = new GridBagConstraints();
        c1.weightx = 0;
        c1.weighty = 0;
        c1.gridx = 0;
        c1.gridy = 1;
        c1.fill = GridBagConstraints.BOTH;
        add(navPanel, c1);
        revalidate();
    }

    private JPanel createSelectionBar() {

        chartTypeListModel = new CyclingSpinnerListModel(ChartType.values());
        chartTypeSpinner = new JSpinner(chartTypeListModel);

        JFormattedTextField ftf = ((JSpinner.DefaultEditor) chartTypeSpinner.getEditor()).getTextField();
        ftf.setColumns(6); //specify more width than we need
        ftf.setHorizontalAlignment(JTextField.CENTER);
        ftf.setEditable(false);

        JLabel spinnerLabel = new JLabel("Chart Type");
        spinnerLabel.setLabelFor(chartTypeSpinner);

        JPanel buttonPanel = new JPanel();
        buttonPanel.add(spinnerLabel, BorderLayout.CENTER);
        buttonPanel.add(chartTypeSpinner, BorderLayout.LINE_END);

        return buttonPanel;
    }

    /**
     * Return a dataset representing all jobs run across the given
     * projects and their associated costs in SU's.  This is currently 
     * not implemented due to the cost of such a computation and data
     * transfer.
     * @param projectTable
     * @return
     */
    private DefaultPieDataset createJobDataset(Hashtable<AccessType, HashSet<ProjectBean>> projectTable) {

        DefaultPieDataset pds = new DefaultPieDataset();

        // add job summary info
        //pds.setValue("Used", hpc.getLoad().getQueue());

        return pds;
    }

    /**
     * Returns a dataset representing the relative usage of the given
     * projects against the given collaborator.
     * 
     * @param projectCollabTable
     * @return
     */
    private DefaultPieDataset createProjectDataset(
            Hashtable<ProjectBean, List<CollaboratorBean>> projectCollabTable, CollaboratorBean collab) {

        DefaultPieDataset pds = new DefaultPieDataset();

        // add project summary info

        for (ProjectBean project : projectCollabTable.keySet()) {
            CollaboratorBean collabBean = projectCollabTable.get(project)
                    .get(projectCollabTable.get(project).indexOf(collab));
            if (collabBean != null) {
                pds.setValue(project.getName() + " Used", new Double(collabBean.getTotalUsage().getUsed()));
                pds.setValue(project.getName() + " Avail.", new Double(collabBean.getTotalUsage().getBalance()));
                // keep track of the current project so we can explode that piece
                // of the pie.
                if (project.equals(GridChem.project)) {
                    defaultProjectIndex = pds.getItemCount() - 1;
                }
            }
        }

        return pds;
    }

    /**
     * Returns a dataset representing the cumulative resource usage across all
     * projects.
     * 
     * @param projectCollabTable
     * @return
     */
    @SuppressWarnings("unused")
    private DefaultPieDataset createResourceDataset(
            Hashtable<ProjectBean, List<CollaboratorBean>> projectCollabTable, CollaboratorBean collab) {

        DefaultPieDataset pds = new DefaultPieDataset();

        Hashtable<String, Double> resourceUsageTable = new Hashtable<String, Double>();

        // for each project find the collaborator's usage on each resource
        for (ProjectBean project : projectCollabTable.keySet()) {

            List<CollaboratorBean> collabs = projectCollabTable.get(project);

            if (projectCollabTable.get(project).contains(collab)) {

                CollaboratorBean projectCollab = projectCollabTable.get(project)
                        .get(projectCollabTable.get(project).indexOf(collab));

                for (String systemName : projectCollab.getUsageTable().keySet()) {

                    if (resourceUsageTable.containsKey(systemName)) {
                        double previousUsage = resourceUsageTable.get(systemName).doubleValue();
                        resourceUsageTable.remove(systemName);
                        resourceUsageTable.put(systemName, new Double(
                                previousUsage + projectCollab.getUsageTable().get(systemName).getUsed()));
                    } else {
                        resourceUsageTable.put(systemName,
                                new Double(projectCollab.getUsageTable().get(systemName).getUsed()));
                    }
                }
            }
        }

        // now put the tallies in the dataset
        for (String systemName : resourceUsageTable.keySet()) {
            pds.setValue(systemName, resourceUsageTable.get(systemName).doubleValue());
        }

        return pds;
    }

    /**
     * Returns a dataset representing the cumulative usage of each user
     * across the set of projects.  
     * 
     * @param projectCollabTable
     * @return
     */
    private DefaultPieDataset createUserDataset(Hashtable<ProjectBean, List<CollaboratorBean>> usageTable,
            CollaboratorBean collab) {

        DefaultPieDataset pds = new DefaultPieDataset();

        Hashtable<String, Double> userUsageTable = new Hashtable<String, Double>();

        // for every project 
        for (ProjectBean project : usageTable.keySet()) {
            // if the user is part of this project
            if (usageTable.get(project).contains(collab)) {
                userUsageTable.put(project.getName(), usageTable.get(project)
                        .get(usageTable.get(project).indexOf(collab)).getTotalUsage().getUsed());
            }
        }

        // now put the tallies in the dataset
        for (String userName : userUsageTable.keySet()) {
            pds.setValue(userName, userUsageTable.get(userName).doubleValue());
        }

        return pds;
    }

    /**
     * Return a dataset representing all jobs run under this project
     * and their associated costs in SU's.  This is currently not
     * implemented due to the cost of such a computation and data
     * transfer.
     * 
     * @param project
     * @return
     */
    private DefaultPieDataset createJobDataset(ProjectBean project) {

        DefaultPieDataset pds = new DefaultPieDataset();

        return pds;
    }

    /**
     * Returns a dataset representing the current usage of this project
     * and the unused portion of the allocation.
     * 
     * @param project
     * @return
     */
    private DefaultPieDataset createProjectDataset(
            Hashtable<ProjectBean, List<CollaboratorBean>> projectUsageTable) {

        DefaultPieDataset pds = new DefaultPieDataset();
        // for every project 
        for (ProjectBean project : projectUsageTable.keySet()) {
            pds.setValue("Used", new Double(project.getUsage().getUsed()));
            //           pds.setValue("Available", new Double((project.getUsage().getAllocated() 
            //                - project.getUsage().getUsed())));
        }
        return pds;
    }

    /**
     * Returns a dataset representing the normalized usage of this project
     * on each resource in the CCG.  The values shown will be the current
     * usage on each resource, however, in terms of display, they will
     * appear as relative to each other.
     * 
     * @param project
     * @return
     */
    private DefaultPieDataset createResourceDataset(
            Hashtable<ProjectBean, List<CollaboratorBean>> projectCollabTable) {

        DefaultPieDataset pds = new DefaultPieDataset();

        Hashtable<String, Double> resourceUsageTable = new Hashtable<String, Double>();

        for (ProjectBean project : projectCollabTable.keySet()) {
            List<CollaboratorBean> collabs = projectCollabTable.get(project);

            for (CollaboratorBean collab : collabs) {

                for (String systemName : collab.getUsageTable().keySet()) {
                    UsageBean usage = collab.getUsageTable().get(systemName);

                    if (resourceUsageTable.containsKey(systemName)) {
                        double previousUsage = resourceUsageTable.get(systemName).doubleValue();
                        resourceUsageTable.remove(systemName);
                        resourceUsageTable.put(systemName, new Double(previousUsage + usage.getUsed()));
                    } else {
                        resourceUsageTable.put(systemName, new Double(usage.getUsed()));
                    }
                }
            }
        }

        // now put the tallies in the dataset
        for (String systemName : resourceUsageTable.keySet()) {
            pds.setValue(systemName, resourceUsageTable.get(systemName).doubleValue());
        }

        return pds;

        //        System.out.println("found specified collaborator " + collab.getLastName() + 
        //                " with " + collab.getUsageTable().size() + " resource records.");
        //        
        //        for(String key: collab.getUsageTable().keySet()) {
        //            pds.setValue(key, collab.getUsageTable().get(key).getUsed());
        //        }
        //        
        //        return pds;
    }

    /**
     * Returns a dataset representing the consumption of this project's
     * allocation by each collaborator including the current user.
     * 
     * @param project
     * @return
     */
    private DefaultPieDataset createUserDataset(Hashtable<ProjectBean, List<CollaboratorBean>> projectCollabTable) {

        DefaultPieDataset pds = new DefaultPieDataset();

        Hashtable<String, Double> userUsageTable = new Hashtable<String, Double>();

        for (ProjectBean project : projectCollabTable.keySet()) {
            List<CollaboratorBean> collabs = projectCollabTable.get(project);

            for (CollaboratorBean collab : collabs) {
                String key = collab.getFirstName() + " " + collab.getLastName();
                if (userUsageTable.containsKey(key)) {
                    double oldVal = userUsageTable.get(key).doubleValue();
                    userUsageTable.remove(key);
                    userUsageTable.put(key, new Double(oldVal + collab.getTotalUsage().getUsed()));
                } else {
                    userUsageTable.put(key, new Double(collab.getTotalUsage().getUsed()));
                }
            }
        }

        // now put the tallies in the dataset
        for (String key : userUsageTable.keySet()) {
            pds.setValue(key, userUsageTable.get(key).doubleValue());
        }

        return pds;
    }

    public void clear() {
        this.removeAll();
        this.projectCollabTable.clear();
    }

    public void setProjects(Hashtable<ProjectBean, List<CollaboratorBean>> projectCollabTable) {

        this.projectCollabTable = projectCollabTable;

        init();

    }

    public void setProject(ProjectBean project, CollaboratorBean collab) {

        UsageChart.collab = collab;

        projectCollabTable.clear();

        projectCollabTable.put(project, Arrays.asList(collab));

        init(collab);

    }

    public void setProject(ProjectBean project, List<CollaboratorBean> collabs) {

        collab = null;

        projectCollabTable.clear();

        projectCollabTable.put(project, collabs);

        init();

    }

    public void setChartType(ProjectBean project, List<CollaboratorBean> collabs, ChartType type) {

        CURRENT_CHARTTYPE = type;

        projectCollabTable.clear();

        projectCollabTable.put(project, collabs);

        if (collab == null) {
            init();
        } else {
            init(collab);
        }
    }

    public void setChartType(ChartType type) {

        CURRENT_CHARTTYPE = type;

        if (collab == null) {
            init();
        } else {
            init(collab);
        }
    }

    public class CyclingSpinnerListModel extends SpinnerListModel {
        Object firstValue, lastValue;
        SpinnerModel linkedModel = null;

        public CyclingSpinnerListModel(ChartType[] values) {
            super(values);
            firstValue = values[0];
            lastValue = values[values.length - 1];
        }

        public void setLinkedModel(SpinnerModel linkedModel) {
            this.linkedModel = linkedModel;
        }

        public Object getNextValue() {
            Object value = super.getNextValue();
            if (value == null) {
                value = firstValue;
                if (linkedModel != null) {
                    linkedModel.setValue(linkedModel.getNextValue());
                }
            }

            System.out.println("Changing type to " + (ChartType) value);

            setChartType((ChartType) value);

            return value;
        }

        public Object getPreviousValue() {
            Object value = super.getPreviousValue();
            if (value == null) {
                value = lastValue;
                if (linkedModel != null) {
                    linkedModel.setValue(linkedModel.getPreviousValue());
                }
            }
            System.out.println("Changing type to " + (ChartType) value);

            setChartType((ChartType) value);

            return value;
        }
    }

}