org.pentaho.di.ui.spoon.trans.StepPerformanceSnapShotDialog.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.di.ui.spoon.trans.StepPerformanceSnapShotDialog.java

Source

/*! ******************************************************************************
 *
 * Pentaho Data Integration
 *
 * Copyright (C) 2002-2013 by Pentaho : http://www.pentaho.com
 *
 *******************************************************************************
 *
 * Licensed 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.pentaho.di.ui.spoon.trans;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Dialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.data.category.DefaultCategoryDataset;
import org.pentaho.di.core.Const;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.trans.performance.StepPerformanceSnapShot;
import org.pentaho.di.ui.core.PropsUI;
import org.pentaho.di.ui.core.gui.GUIResource;
import org.pentaho.di.ui.spoon.Spoon;
import org.pentaho.di.ui.util.ImageUtil;

public class StepPerformanceSnapShotDialog extends Dialog {

    private static Class<?> PKG = Spoon.class; // for i18n purposes, needed by Translator2!!

    private static final int DATA_CHOICE_WRITTEN = 0;
    private static final int DATA_CHOICE_READ = 1;
    private static final int DATA_CHOICE_INPUT = 2;
    private static final int DATA_CHOICE_OUTPUT = 3;
    private static final int DATA_CHOICE_UPDATED = 4;
    private static final int DATA_CHOICE_REJECTED = 5;
    private static final int DATA_CHOICE_INPUT_BUFFER_SIZE = 6;
    private static final int DATA_CHOICE_OUTPUT_BUFFER_SIZE = 7;

    private static String[] dataChoices = new String[] {
            BaseMessages.getString(PKG, "StepPerformanceSnapShotDialog.Written"),
            BaseMessages.getString(PKG, "StepPerformanceSnapShotDialog.Read"),
            BaseMessages.getString(PKG, "StepPerformanceSnapShotDialog.Input"),
            BaseMessages.getString(PKG, "StepPerformanceSnapShotDialog.Output"),
            BaseMessages.getString(PKG, "StepPerformanceSnapShotDialog.Updated"),
            BaseMessages.getString(PKG, "StepPerformanceSnapShotDialog.Rejected"),
            BaseMessages.getString(PKG, "StepPerformanceSnapShotDialog.InputBufferSize"),
            BaseMessages.getString(PKG, "StepPerformanceSnapShotDialog.OutputBufferSize"), };

    private Shell parent, shell;
    private Map<String, List<StepPerformanceSnapShot>> stepPerformanceSnapShots;
    private Display display;
    private String[] steps;
    private PropsUI props;
    private org.eclipse.swt.widgets.List stepsList;
    private Canvas canvas;
    private Image image;
    private long timeDifference;
    private String title;
    private org.eclipse.swt.widgets.List dataList;

    public StepPerformanceSnapShotDialog(Shell parent, String title,
            Map<String, List<StepPerformanceSnapShot>> stepPerformanceSnapShots, long timeDifference) {
        super(parent);
        this.parent = parent;
        this.display = parent.getDisplay();
        this.props = PropsUI.getInstance();
        this.timeDifference = timeDifference;
        this.title = title;
        this.stepPerformanceSnapShots = stepPerformanceSnapShots;

        Set<String> stepsSet = stepPerformanceSnapShots.keySet();
        steps = stepsSet.toArray(new String[stepsSet.size()]);
        Arrays.sort(steps);
    }

    public void open() {

        shell = new Shell(parent, SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MAX | SWT.MIN);
        props.setLook(shell);
        shell.setText(BaseMessages.getString(PKG, "StepPerformanceSnapShotDialog.Title"));
        shell.setImage(GUIResource.getInstance().getImageLogoSmall());

        FormLayout formLayout = new FormLayout();
        formLayout.marginWidth = Const.FORM_MARGIN;
        formLayout.marginHeight = Const.FORM_MARGIN;

        shell.setLayout(formLayout);

        // Display 2 lists with the data types and the steps on the left side.
        // Then put a canvas with the graph on the right side
        //
        dataList = new org.eclipse.swt.widgets.List(shell,
                SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.LEFT | SWT.BORDER);
        props.setLook(dataList);
        dataList.setItems(dataChoices);
        dataList.addSelectionListener(new SelectionAdapter() {

            public void widgetSelected(SelectionEvent event) {

                // If there are multiple selections here AND there are multiple selections in the steps list, we only take the
                // first step in the selection...
                //
                if (dataList.getSelectionCount() > 1 && stepsList.getSelectionCount() > 1) {
                    stepsList.setSelection(stepsList.getSelectionIndices()[0]);
                }

                updateGraph();
            }
        });
        FormData fdDataList = new FormData();
        fdDataList.left = new FormAttachment(0, 0);
        fdDataList.right = new FormAttachment(props.getMiddlePct() / 2, Const.MARGIN);
        fdDataList.top = new FormAttachment(0, 0);
        fdDataList.bottom = new FormAttachment(30, 0);
        dataList.setLayoutData(fdDataList);

        stepsList = new org.eclipse.swt.widgets.List(shell,
                SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.LEFT | SWT.BORDER);
        props.setLook(stepsList);
        stepsList.setItems(steps);
        stepsList.addSelectionListener(new SelectionAdapter() {

            public void widgetSelected(SelectionEvent event) {

                // If there are multiple selections here AND there are multiple selections in the data list, we only take the
                // first data item in the selection...
                //
                if (dataList.getSelectionCount() > 1 && stepsList.getSelectionCount() > 1) {
                    dataList.setSelection(dataList.getSelectionIndices()[0]);
                }

                updateGraph();
            }
        });
        FormData fdStepsList = new FormData();
        fdStepsList.left = new FormAttachment(0, 0);
        fdStepsList.right = new FormAttachment(props.getMiddlePct() / 2, Const.MARGIN);
        fdStepsList.top = new FormAttachment(dataList, Const.MARGIN);
        fdStepsList.bottom = new FormAttachment(100, Const.MARGIN);
        stepsList.setLayoutData(fdStepsList);

        canvas = new Canvas(shell, SWT.NONE);
        props.setLook(canvas);
        FormData fdCanvas = new FormData();
        fdCanvas.left = new FormAttachment(props.getMiddlePct() / 2, 0);
        fdCanvas.right = new FormAttachment(100, 0);
        fdCanvas.top = new FormAttachment(0, 0);
        fdCanvas.bottom = new FormAttachment(100, 0);
        canvas.setLayoutData(fdCanvas);

        shell.addControlListener(new ControlAdapter() {
            public void controlResized(ControlEvent event) {
                updateGraph();
            }
        });

        shell.addDisposeListener(new DisposeListener() {
            public void widgetDisposed(DisposeEvent event) {
                if (image != null) {
                    image.dispose();
                }
            }
        });

        canvas.addPaintListener(new PaintListener() {

            public void paintControl(PaintEvent event) {
                if (image != null) {
                    event.gc.drawImage(image, 0, 0);
                }
            }
        });

        // Refresh automatically every 5 seconds as well.
        //
        Timer timer = new Timer("step performance snapshot dialog Timer");
        timer.schedule(new TimerTask() {
            public void run() {
                updateGraph();
            }
        }, 0, 5000);

        shell.open();

        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
    }

    private void updateGraph() {

        display.asyncExec(new Runnable() {

            public void run() {
                if (!shell.isDisposed() && !canvas.isDisposed()) {
                    updateCanvas();
                }
            }

        });
    }

    private void updateCanvas() {
        Rectangle bounds = canvas.getBounds();
        if (bounds.width <= 0 || bounds.height <= 0) {
            return;
        }

        // The list of snapshots : convert to JFreeChart dataset
        //
        DefaultCategoryDataset dataset = new DefaultCategoryDataset();

        String[] selectedSteps = stepsList.getSelection();
        if (selectedSteps == null || selectedSteps.length == 0) {
            selectedSteps = new String[] { steps[0], }; // first step
            stepsList.select(0);
        }
        int[] dataIndices = dataList.getSelectionIndices();
        if (dataIndices == null || dataIndices.length == 0) {
            dataIndices = new int[] { DATA_CHOICE_WRITTEN, };
            dataList.select(0);
        }

        boolean multiStep = stepsList.getSelectionCount() > 1;
        boolean multiData = dataList.getSelectionCount() > 1;
        boolean calcMoving = !multiStep && !multiData; // A single metric shown for a single step
        List<Double> movingList = new ArrayList<Double>();
        int movingSize = 10;
        double movingTotal = 0;
        int totalTimeInSeconds = 0;

        for (int t = 0; t < selectedSteps.length; t++) {

            String stepNameCopy = selectedSteps[t];

            List<StepPerformanceSnapShot> snapShotList = stepPerformanceSnapShots.get(stepNameCopy);
            if (snapShotList != null && snapShotList.size() > 1) {
                totalTimeInSeconds = (int) Math
                        .round(((double) (snapShotList.get(snapShotList.size() - 1).getDate().getTime()
                                - snapShotList.get(0).getDate().getTime())) / 1000);
                for (int i = 0; i < snapShotList.size(); i++) {
                    StepPerformanceSnapShot snapShot = snapShotList.get(i);
                    if (snapShot.getTimeDifference() != 0) {

                        double factor = (double) 1000 / (double) snapShot.getTimeDifference();

                        for (int d = 0; d < dataIndices.length; d++) {

                            String dataType;
                            if (multiStep) {
                                dataType = stepNameCopy;
                            } else {
                                dataType = dataChoices[dataIndices[d]];
                            }
                            String xLabel = Integer.toString(Math.round(i * timeDifference / 1000));
                            Double metric = null;
                            switch (dataIndices[d]) {
                            case DATA_CHOICE_INPUT:
                                metric = snapShot.getLinesInput() * factor;
                                break;
                            case DATA_CHOICE_OUTPUT:
                                metric = snapShot.getLinesOutput() * factor;
                                break;
                            case DATA_CHOICE_READ:
                                metric = snapShot.getLinesRead() * factor;
                                break;
                            case DATA_CHOICE_WRITTEN:
                                metric = snapShot.getLinesWritten() * factor;
                                break;
                            case DATA_CHOICE_UPDATED:
                                metric = snapShot.getLinesUpdated() * factor;
                                break;
                            case DATA_CHOICE_REJECTED:
                                metric = snapShot.getLinesRejected() * factor;
                                break;
                            case DATA_CHOICE_INPUT_BUFFER_SIZE:
                                metric = (double) snapShot.getInputBufferSize();
                                break;
                            case DATA_CHOICE_OUTPUT_BUFFER_SIZE:
                                metric = (double) snapShot.getOutputBufferSize();
                                break;
                            default:
                                break;
                            }
                            if (metric != null) {
                                dataset.addValue(metric, dataType, xLabel);

                                if (calcMoving) {
                                    movingTotal += metric;
                                    movingList.add(metric);
                                    if (movingList.size() > movingSize) {
                                        movingTotal -= movingList.get(0);
                                        movingList.remove(0);
                                    }
                                    double movingAverage = movingTotal / movingList.size();
                                    dataset.addValue(movingAverage, dataType + "(Avg)", xLabel);
                                    // System.out.println("moving average = "+movingAverage+", movingTotal="+movingTotal+", m");
                                }
                            }
                        }
                    }
                }
            }
        }
        String chartTitle = title;
        if (multiStep) {
            chartTitle += " (" + dataChoices[dataIndices[0]] + ")";
        } else {
            chartTitle += " (" + selectedSteps[0] + ")";
        }
        final JFreeChart chart = ChartFactory.createLineChart(chartTitle, // chart title
                BaseMessages.getString(PKG, "StepPerformanceSnapShotDialog.TimeInSeconds.Label",
                        Integer.toString(totalTimeInSeconds), Long.toString(timeDifference)), // domain axis label
                BaseMessages.getString(PKG, "StepPerformanceSnapShotDialog.RowsPerSecond.Label"), // range axis label
                dataset, // data
                PlotOrientation.VERTICAL, // orientation
                true, // include legend
                true, // tooltips
                false); // urls       
        chart.setBackgroundPaint(Color.white);
        CategoryPlot plot = (CategoryPlot) chart.getPlot();
        plot.setBackgroundPaint(Color.white);
        plot.setForegroundAlpha(0.5f);
        plot.setRangeGridlinesVisible(true);

        NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());

        CategoryAxis domainAxis = plot.getDomainAxis();
        domainAxis.setTickLabelsVisible(false);

        // Customize the renderer...
        //
        LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot.getRenderer();
        renderer.setBaseShapesVisible(true);
        renderer.setDrawOutlines(true);
        renderer.setUseFillPaint(true);
        renderer.setBaseFillPaint(Color.white);
        renderer.setSeriesStroke(0, new BasicStroke(1.5f));
        renderer.setSeriesOutlineStroke(0, new BasicStroke(1.5f));
        renderer.setSeriesStroke(1, new BasicStroke(2.5f));
        renderer.setSeriesOutlineStroke(1, new BasicStroke(2.5f));
        renderer.setSeriesShape(0, new Ellipse2D.Double(-3.0, -3.0, 6.0, 6.0));

        BufferedImage bufferedImage = chart.createBufferedImage(bounds.width, bounds.height);
        ImageData imageData = ImageUtil.convertToSWT(bufferedImage);

        // dispose previous image...
        //
        if (image != null) {
            image.dispose();
        }
        image = new Image(display, imageData);

        // Draw the image on the canvas...
        //
        canvas.redraw();
    }

    /**
     * @return the shell
     */
    public Shell getShell() {
        return parent;
    }

    /**
     * @param shell
     *          the shell to set
     */
    public void setShell(Shell shell) {
        this.parent = shell;
    }

    /**
     * @return the stepPerformanceSnapShots
     */
    public Map<String, List<StepPerformanceSnapShot>> getStepPerformanceSnapShots() {
        return stepPerformanceSnapShots;
    }

    /**
     * @param stepPerformanceSnapShots
     *          the stepPerformanceSnapShots to set
     */
    public void setStepPerformanceSnapShots(Map<String, List<StepPerformanceSnapShot>> stepPerformanceSnapShots) {
        this.stepPerformanceSnapShots = stepPerformanceSnapShots;
    }

}