com.haskins.cloudtrailviewer.feature.MetricsFeature.java Source code

Java tutorial

Introduction

Here is the source code for com.haskins.cloudtrailviewer.feature.MetricsFeature.java

Source

/*    
CloudTrail Viewer, is a Java desktop application for reading AWS CloudTrail logs
files.
    
Copyright (C) 2016  Mark P. Haskins
    
This program is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
    
This program 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 for more details.
    
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.haskins.cloudtrailviewer.feature;

import com.haskins.cloudtrailviewer.utils.DateTimeCrosshairLabelGenerator;
import com.haskins.cloudtrailviewer.application.HelpToolBar;
import com.haskins.cloudtrailviewer.application.StatusBar;
import com.haskins.cloudtrailviewer.components.EventTablePanel;
import com.haskins.cloudtrailviewer.model.Help;
import com.haskins.cloudtrailviewer.model.event.Event;
import com.haskins.cloudtrailviewer.thirdparty.WrapLayout;
import com.haskins.cloudtrailviewer.utils.TableUtils;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JToolBar;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.entity.XYItemEntity;
import org.jfree.chart.panel.CrosshairOverlay;
import org.jfree.chart.plot.Crosshair;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYAreaRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.time.Second;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.ui.RectangleEdge;

/**
 *
 * @author mark.haskins
 */
public class MetricsFeature extends JPanel implements Feature, ActionListener, ChartMouseListener {

    private final static Logger LOGGER = Logger.getLogger("CloudTrail");

    private static final String NAME = "Metrics Feature";

    private static final Map<String, List<Event>> SERVICE_SORTED = new HashMap<>();
    private static final long serialVersionUID = -3462820837131838769L;
    private final Map<Second, List<Event>> secondEvents = new HashMap<>();

    private final Help help = new Help("Metrics Feature", "metrics");

    private final HelpToolBar helpBar;

    private final JToolBar toolbar = new JToolBar();
    private final JPanel chartCards = new JPanel(new CardLayout());

    private final TableUtils tableUtils = new TableUtils();

    private JSplitPane jsp;

    private ChartPanel chartPanel;
    private Crosshair xCrosshair;

    private final EventTablePanel eventTable = new EventTablePanel(EventTablePanel.CHART_EVENT);

    public MetricsFeature(StatusBar sb, HelpToolBar helpBar) {

        this.helpBar = helpBar;

        buildUI();
    }

    ////////////////////////////////////////////////////////////////////////////
    ///// Feature implementation
    ////////////////////////////////////////////////////////////////////////////
    @Override
    public void eventLoadingComplete() {
    }

    @Override
    public boolean showOnToolBar() {
        return true;
    }

    @Override
    public String getIcon() {
        return "Metrics-48.png";
    }

    @Override
    public String getTooltip() {
        return "Metrics Overview";
    }

    @Override
    public String getName() {
        return MetricsFeature.NAME;
    }

    @Override
    public void will_hide() {
        helpBar.setHelp(null);
    }

    @Override
    public void will_appear() {
        helpBar.setHelp(help);
    }

    @Override
    public void showEventsTable(List<Event> events) {
    }

    @Override
    public void reset() {

        eventTable.clearEvents();
        eventTable.setVisible(false);

    }

    ////////////////////////////////////////////////////////////////////////////
    ///// EventDatabaseListener implementation
    ////////////////////////////////////////////////////////////////////////////
    @Override
    public void eventAdded(Event event) {

        List<Event> allEvents = SERVICE_SORTED.get("ALL");
        if (allEvents == null) {
            allEvents = new ArrayList<>();
            addButton("ALL");
        }
        allEvents.add(event);
        SERVICE_SORTED.put("ALL", allEvents);

        String serviceName = tableUtils.getService(event);
        List<Event> events = SERVICE_SORTED.get(serviceName);
        if (events == null) {
            events = new ArrayList<>();
            addButton(serviceName);
        }
        events.add(event);
        SERVICE_SORTED.put(serviceName, events);
    }

    @Override
    public void finishedLoading() {
        showChart("ALL");
    }

    ////////////////////////////////////////////////////////////////////////////
    ///// ActionListener implementation
    ////////////////////////////////////////////////////////////////////////////
    @Override
    public void actionPerformed(ActionEvent e) {
        showChart(e.getActionCommand());
    }

    ////////////////////////////////////////////////////////////////////////////
    ///// ChartListener methods
    //////////////////////////////////////////////////////////////////////////// 
    @Override
    public void chartMouseClicked(ChartMouseEvent cme) {

        try {
            XYItemEntity xyitem = (XYItemEntity) cme.getEntity();
            TimeSeriesCollection dataset = (TimeSeriesCollection) xyitem.getDataset();
            List<TimeSeries> series = dataset.getSeries();
            TimeSeries timeSeries = series.get(xyitem.getSeriesIndex());
            Second second = (Second) timeSeries.getTimePeriod(xyitem.getItem());

            if (!eventTable.isVisible()) {

                jsp.setDividerLocation(0.5);
                jsp.setDividerSize(3);
                eventTable.setVisible(true);
            }

            eventTable.clearEvents();
            eventTable.setEvents(secondEvents.get(second));

        } catch (Exception e) {
            LOGGER.log(Level.WARNING, "Problem responding to Chart click event", e);
        }
    }

    @Override
    public void chartMouseMoved(ChartMouseEvent event) {

        Rectangle2D dataArea = this.chartPanel.getScreenDataArea();
        JFreeChart chart = event.getChart();
        XYPlot plot = (XYPlot) chart.getPlot();
        ValueAxis xAxis = plot.getDomainAxis();

        double x = xAxis.java2DToValue(event.getTrigger().getX(), dataArea, RectangleEdge.BOTTOM);

        this.xCrosshair.setValue(x);
    }

    ////////////////////////////////////////////////////////////////////////////
    ///// private methods
    //////////////////////////////////////////////////////////////////////////// 
    private void buildUI() {

        // toolbar
        toolbar.setLayout(new WrapLayout(FlowLayout.CENTER, 1, 1));
        toolbar.setFloatable(false);
        toolbar.setBackground(Color.white);
        toolbar.setBorder(BorderFactory.createMatteBorder(1, 0, 1, 0, Color.black));

        eventTable.setVisible(false);

        jsp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, chartCards, eventTable);
        jsp.setDividerSize(0);
        jsp.setResizeWeight(1);
        jsp.setDividerLocation(jsp.getSize().height - jsp.getInsets().bottom - jsp.getDividerSize());
        jsp.setBorder(BorderFactory.createEmptyBorder(1, 0, 0, 0));

        this.setLayout(new BorderLayout());
        this.add(toolbar, BorderLayout.PAGE_START);
        this.add(jsp, BorderLayout.CENTER);
    }

    private void showChart(String service) {

        final TimeSeriesCollection chartData = generateTimeSeriesData(service);

        JFreeChart chart = ChartFactory.createTimeSeriesChart(service, "Time", "Calls", chartData, false, true,
                false);

        // draw outter line
        XYLineAndShapeRenderer lineAndShapeRenderer = new XYLineAndShapeRenderer();
        lineAndShapeRenderer.setPaint(new Color(64, 168, 228, 75));
        lineAndShapeRenderer.setSeriesShape(0, new Ellipse2D.Double(-3, -3, 6, 6));
        lineAndShapeRenderer.setSeriesShapesFilled(0, true);
        lineAndShapeRenderer.setSeriesShapesVisible(0, true);
        lineAndShapeRenderer.setUseOutlinePaint(true);
        lineAndShapeRenderer.setUseFillPaint(true);

        // draw filled area
        XYAreaRenderer renderer = new XYAreaRenderer();
        renderer.setPaint(new Color(64, 168, 228, 50));

        // configure Plot
        final XYPlot plot = chart.getXYPlot();
        plot.setBackgroundPaint(Color.WHITE);
        plot.setOutlineVisible(false);

        plot.setDataset(0, chartData);
        plot.setDataset(1, chartData);

        plot.setRenderer(0, lineAndShapeRenderer);
        plot.setRenderer(1, renderer);

        plot.getDomainAxis().setLowerMargin(0);
        plot.getDomainAxis().setUpperMargin(0);

        // format chart title
        TextTitle t = chart.getTitle();
        t.setFont(new Font("Arial", Font.BOLD, 14));

        // Cross Hairs
        xCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(0f));
        xCrosshair.setLabelVisible(true);
        xCrosshair.setLabelGenerator(new DateTimeCrosshairLabelGenerator());

        CrosshairOverlay crosshairOverlay = new CrosshairOverlay();
        crosshairOverlay.addDomainCrosshair(xCrosshair);

        // Create the panel
        chartPanel = new ChartPanel(chart);
        chartPanel.setMinimumDrawWidth(0);
        chartPanel.setMaximumDrawWidth(Integer.MAX_VALUE);
        chartPanel.setMinimumDrawHeight(0);
        chartPanel.setMaximumDrawHeight(Integer.MAX_VALUE);
        chartPanel.setMouseZoomable(true, false);
        chartPanel.setDomainZoomable(true);
        chartPanel.setRangeZoomable(false);
        chartPanel.addChartMouseListener(this);
        chartPanel.addOverlay(crosshairOverlay);

        // update the display
        chartCards.removeAll();
        chartCards.add(chartPanel, "");
        chartCards.revalidate();
    }

    private TimeSeriesCollection generateTimeSeriesData(String service) {

        List<Event> serviceEvents = SERVICE_SORTED.get(service);

        Map<Long, List<Event>> tickEvents = new HashMap<>();
        for (Event event : serviceEvents) {

            long second = event.getTimestamp();
            List<Event> events = tickEvents.get(second);
            if (events == null) {
                events = new ArrayList<>();
            }
            events.add(event);
            tickEvents.put(second, events);
        }

        TimeSeries series = new TimeSeries(service);

        for (Map.Entry<Long, List<Event>> entry : tickEvents.entrySet()) {

            Second secondPeriod = new Second(new Date(entry.getKey()));
            secondEvents.put(secondPeriod, entry.getValue());
            series.add(secondPeriod, entry.getValue().size());
        }

        TimeSeriesCollection tsc = new TimeSeriesCollection();
        tsc.addSeries(series);

        return tsc;
    }

    private void addButton(String service) {

        JButton btn = new JButton(service);
        btn.addActionListener(this);
        btn.setActionCommand(service);

        toolbar.add(btn);
    }
}