com.skysql.manager.ui.components.ChartsLayout.java Source code

Java tutorial

Introduction

Here is the source code for com.skysql.manager.ui.components.ChartsLayout.java

Source

/*
 * This file is distributed as part of the MariaDB Manager.  It 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,
 * version 2.
 *
 * 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, write to the Free Software Foundation, Inc., 51
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Copyright 2012-2014 SkySQL Corporation Ab
 */

package com.skysql.manager.ui.components;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.skysql.manager.ChartMappings;
import com.skysql.manager.ClusterComponent;
import com.skysql.manager.DateConversion;
import com.skysql.manager.ManagerUI;
import com.skysql.manager.MonitorRecord;
import com.skysql.manager.UserChart;
import com.skysql.manager.api.ChartProperties;
import com.skysql.manager.api.MonitorData;
import com.skysql.manager.api.Monitors;
import com.skysql.manager.api.SystemInfo;
import com.vaadin.addon.charts.Chart;
import com.vaadin.addon.charts.model.Configuration;
import com.vaadin.addon.charts.model.HorizontalAlign;
import com.vaadin.addon.charts.model.Labels;
import com.vaadin.addon.charts.model.ListSeries;
import com.vaadin.addon.charts.model.RangeSeries;
import com.vaadin.addon.charts.model.Series;
import com.vaadin.addon.charts.model.XAxis;
import com.vaadin.event.dd.DragAndDropEvent;
import com.vaadin.server.PaintException;
import com.vaadin.server.PaintTarget;
import com.vaadin.server.VaadinSession;
import com.vaadin.shared.ui.dd.HorizontalDropLocation;
import com.vaadin.ui.Component;

import fi.jasoft.dragdroplayouts.DDCssLayout;
import fi.jasoft.dragdroplayouts.client.ui.Constants;
import fi.jasoft.dragdroplayouts.drophandlers.DefaultCssLayoutDropHandler;
import fi.jasoft.dragdroplayouts.events.LayoutBoundTransferable;
import fi.jasoft.dragdroplayouts.interfaces.DragFilter;

/**
 * The Class ChartsLayout.
 */
public class ChartsLayout extends DDCssLayout {

    private static final long serialVersionUID = 0x4C656F6E6172646FL;

    private boolean isChartsEditing;
    private ChartProperties chartProperties;
    private String systemType;
    private String time, interval;

    /**
     * Instantiates a new charts layout.
     *
     * @param previewMode the preview mode
     * @param time the time
     * @param interval the interval
     */
    public ChartsLayout(boolean previewMode, String time, String interval) {
        this.time = time;
        this.interval = interval;

        //      addStyleName("chartsArray");
        //      addStyleName("no-vertical-drag-hints");
        setSizeFull();
        setHeight(null);
        setShim(false);

        if (previewMode != true) {
            setDropHandler(new CustomCssLayoutDropHandler());

            // Only allow dragging Charts
            setDragFilter(new DragFilter() {
                private static final long serialVersionUID = 0x4C656F6E6172646FL;

                public boolean isDraggable(Component component) {
                    return component instanceof ChartButton;
                }
            });

        }

    }

    /**
     * Gets the time.
     *
     * @return the time
     */
    public String getTime() {
        return time;
    }

    /**
     * Gets the interval.
     *
     * @return the interval
     */
    public String getInterval() {
        return interval;
    }

    /**
     * Initialize charts.
     *
     * @param chartProperties the chart properties
     * @param systemType the system type
     * @return true, if successful
     */
    public boolean initializeCharts(ChartProperties chartProperties, String systemType) {
        this.chartProperties = chartProperties;
        this.systemType = systemType;

        ArrayList<ChartMappings> chartMappings = chartProperties.getChartMappings(systemType);
        if (chartMappings != null) {
            boolean isDirty = false;
            for (ChartMappings chartMapping : chartMappings.toArray(new ChartMappings[chartMappings.size()])) {
                isDirty |= stripMissingMonitors(chartMapping);
                if (!chartMapping.getMonitorIDs().isEmpty()) {
                    UserChart userChart = new UserChart(chartMapping);
                    ChartButton chartButton = new ChartButton(userChart);
                    chartButton.setChartsLayout(this);
                    addComponent(chartButton);
                } else {
                    chartMappings.remove(chartMapping);
                }
            }
            if (isDirty) {
                chartProperties.setChartMappings(systemType, chartMappings);
            }
            return isDirty;
        }

        return false;

    }

    /**
     * Strip missing monitors.
     *
     * @param chartMapping the chart mapping
     * @return true, if successful
     */
    private boolean stripMissingMonitors(ChartMappings chartMapping) {
        boolean isDirty = false;
        ArrayList<String> monitorIDs = chartMapping.getMonitorIDs();
        for (String monitorID : monitorIDs.toArray(new String[monitorIDs.size()])) {
            if (!Monitors.getMonitorsList().containsKey(monitorID)) {
                monitorIDs.remove(monitorID);
                isDirty |= true;
            }
        }

        return isDirty;
    }

    /**
     * Save charts to properties.
     */
    private void saveChartsToProperties() {
        ArrayList<ChartMappings> chartMappings = new ArrayList<ChartMappings>();
        Iterator<Component> iter = iterator();
        while (iter.hasNext()) {
            ChartButton chartButton = (ChartButton) iter.next();
            UserChart userChart = (UserChart) chartButton.getData();
            ChartMappings chartMapping = new ChartMappings(userChart);
            chartMappings.add(chartMapping);
        }
        chartProperties.setChartMappings(systemType, chartMappings);
    }

    /**
     * Delete chart.
     *
     * @param chartButton the chart button
     */
    public void deleteChart(Component chartButton) {
        removeComponent(chartButton);
    }

    /**
     * Replace chart.
     *
     * @param oldChartButton the old chart button
     * @param userChart the user chart
     */
    public void replaceChart(ChartButton oldChartButton, UserChart userChart) {

        userChart.clearMonitorData();
        ChartButton newChart = new ChartButton(userChart);
        newChart.setEditable(isChartsEditing);
        replaceComponent(oldChartButton, newChart);

    }

    /**
     * Sets the editable.
     *
     * @param editable the new editable
     */
    public void setEditable(boolean editable) {
        isChartsEditing = editable;
        VaadinSession.getCurrent().setAttribute("isChartsEditing", isChartsEditing);

        Iterator<Component> iter = iterator();
        while (iter.hasNext()) {
            ChartButton chartButton = (ChartButton) iter.next();
            chartButton.setEditable(editable);
        }

        // when getting out of editable mode, save mappings
        if (editable == false) {
            saveChartsToProperties();
        }
    }

    /**
     * Hide charts.
     */
    public void hideCharts() {
        Iterator<Component> iter = iterator();
        while (iter.hasNext()) {

            Component component = iter.next();
            if (component instanceof ChartButton) {
                ChartButton chartButton = (ChartButton) component;
                chartButton.setVisible(false);
            }
        }
    }

    /**
     * Stop refresh.
     */
    public void stopRefresh() {
        //      if (updaterThread != null && updaterThread.isAlive()) {
        //         ManagerUI.log(this.getClass().getName() + "Stopping thread: " + updaterThread);
        //         updaterThread.flagged = true;
        //         updaterThread.interrupt();
        //      }
    }

    /**
     * Refresh.
     *
     * @param time the time
     * @param interval the interval
     */
    public void refresh(String time, String interval) {
        this.time = time;
        this.interval = interval;

        //      if (isChartsEditing) {
        //         return;
        //      }
        VaadinSession session = getSession();
        if (session == null) {
            session = VaadinSession.getCurrent();
        }
        boolean isChartsEditing2 = (Boolean) session.getAttribute("isChartsEditing");
        if (isChartsEditing2) {
            return;
        }

        ManagerUI.log("ChartsLayout refresh()");

        Iterator<Component> iter = iterator();
        while (iter.hasNext()) {

            Component component = iter.next();
            if (component instanceof ChartButton) {
                ChartButton chartButton = (ChartButton) component;

                UpdaterThread updaterThread = new UpdaterThread(chartButton);
                updaterThread.start();
            }
        }

    }

    /**
     * The Class UpdaterThread.
     */
    class UpdaterThread extends Thread {

        ChartButton chartButton;
        volatile boolean flagged = false;

        /**
         * Instantiates a new updater thread.
         *
         * @param chartButton the chart button
         */
        UpdaterThread(ChartButton chartButton) {
            this.chartButton = chartButton;
        }

        /* (non-Javadoc)
         * @see java.lang.Thread#run()
         */
        @Override
        public void run() {
            asynchRefresh(this);
        }
    }

    /**
     * Asynch refresh.
     *
     * @param updaterThread the updater thread
     */
    private void asynchRefresh(UpdaterThread updaterThread) {

        VaadinSession.getCurrent().setAttribute("ChartsRefresh", true);
        refreshCode(updaterThread.chartButton, updaterThread);
        VaadinSession.getCurrent().setAttribute("ChartsRefresh", false);

    }

    /**
     * Refresh code.
     *
     * @param chartButton the chart button
     * @param updaterThread the updater thread
     */
    public void refreshCode(ChartButton chartButton, UpdaterThread updaterThread) {
        String systemID, nodeID;

        VaadinSession session = getSession();
        if (session == null) {
            session = VaadinSession.getCurrent();
        }
        ManagerUI managerUI = session.getAttribute(ManagerUI.class);
        ClusterComponent componentInfo = session.getAttribute(ClusterComponent.class);

        switch (componentInfo.getType()) {
        case system:
            systemID = componentInfo.getID();
            nodeID = SystemInfo.SYSTEM_NODEID;
            break;

        case node:
            systemID = componentInfo.getParentID();
            nodeID = componentInfo.getID();
            break;

        default:
            return;
        }

        final UserChart userChart = (UserChart) chartButton.getData();
        final Chart chart = chartButton.getChart();
        boolean needsRedraw = false;
        String[] timeStamps = null;
        final Configuration configuration = chart.getConfiguration();

        for (String monitorID : userChart.getMonitorIDs()) {

            if (updaterThread != null && updaterThread.flagged) {
                ManagerUI.log(this.getClass().getName() + " - flagged is set before API call");
                return;
            }

            ManagerUI.log("ChartsLayout - redraw loop MonitorID: " + monitorID);
            final MonitorRecord monitor = Monitors.getMonitor(monitorID);
            if (monitor == null) {
                // monitor was removed from the system: skip
                ManagerUI.log("monitor was removed from the system");
                continue;
            }

            MonitorData monitorData = (MonitorData) userChart.getMonitorData(monitor.getID());
            if (monitorData == null) {
                String method;
                if (UserChart.ChartType.LineChart.name().equals(userChart.getType())) {
                    method = MonitorData.METHOD_AVG;
                } else if (UserChart.ChartType.AreaChart.name().equals(userChart.getType())) {
                    method = MonitorData.METHOD_MINMAX;
                } else {
                    continue; // unknown chart type, skip
                }
                monitorData = new MonitorData(monitor, systemID, nodeID, time, interval, userChart.getPoints(),
                        method);
                needsRedraw = true;
            } else if (monitorData.update(systemID, nodeID, time, interval, userChart.getPoints()) == true) {
                // data in chart needs to be updated
                needsRedraw = true;
            } else {
                continue; // no update needed
            }

            if (timeStamps == null) {
                DateConversion dateConversion = session.getAttribute(DateConversion.class);

                ArrayList<Long> unixTimes = monitorData.getTimeStamps();
                if (unixTimes != null) {
                    timeStamps = new String[unixTimes.size()];
                    int timeSpacer = unixTimes.size() / 15;
                    for (int x = 0; x < unixTimes.size(); x++) {
                        timeStamps[x] = (x % timeSpacer != 0) ? "\u00A0"
                                : dateConversion.stampToString(unixTimes.get(x));
                    }
                }
            }

            if (updaterThread != null && updaterThread.flagged) {
                ManagerUI.log("ChartsLayout - flagged is set before UI redraw");
                return;
            }

            final MonitorData finalMonitorData = monitorData;
            final String finalMonitorID = monitorID;

            managerUI.access(new Runnable() {
                @Override
                public void run() {
                    // Here the UI is locked and can be updated

                    ManagerUI.log("ChartsLayout access run() monitorID: " + finalMonitorID);

                    if (UserChart.ChartType.LineChart.name().equals(userChart.getType())) {

                        ListSeries ls = null, testLS;
                        List<Series> lsList = configuration.getSeries();
                        Iterator seriesIter = lsList.iterator();
                        while (seriesIter.hasNext()) {
                            testLS = (ListSeries) seriesIter.next();
                            if (testLS.getName().equals(monitor.getName())) {
                                ls = testLS;
                                break;
                            }
                        }
                        if (ls == null) {
                            ls = new ListSeries(monitor.getName());
                            configuration.addSeries(ls);
                        }

                        userChart.setMonitorData(monitor.getID(), finalMonitorData);

                        ArrayList<Number> avgList = finalMonitorData.getAvgPoints();
                        ls.setData(avgList);

                    } else if (UserChart.ChartType.AreaChart.name().equals(userChart.getType())) {

                        RangeSeries rs = null, testRS;
                        List<Series> lsList = configuration.getSeries();
                        Iterator seriesIter = lsList.iterator();
                        while (seriesIter.hasNext()) {
                            testRS = (RangeSeries) seriesIter.next();
                            if (testRS.getName().equals(monitor.getName())) {
                                rs = testRS;
                                break;
                            }
                        }
                        if (rs == null) {
                            rs = new RangeSeries(monitor.getName());
                            configuration.addSeries(rs);
                        }

                        userChart.setMonitorData(monitor.getID(), finalMonitorData);

                        ArrayList<Number> minList = finalMonitorData.getMinPoints();
                        ArrayList<Number> maxList = finalMonitorData.getMaxPoints();

                        if (minList != null && maxList != null && minList.size() > 0 && maxList.size() > 0
                                && minList.size() == maxList.size()) {
                            Object[] minArray = finalMonitorData.getMinPoints().toArray();
                            Object[] maxArray = finalMonitorData.getMaxPoints().toArray();

                            Number[][] dataList = new Number[minList.size()][2];
                            for (int x = 0; x < minList.size(); x++) {
                                dataList[x][0] = (Number) minArray[x];
                                dataList[x][1] = (Number) maxArray[x];
                            }

                            rs.setRangeData(dataList);
                        } else {
                            rs.setRangeData(new Number[0][0]);
                        }

                    }

                }
            });

        } // for

        final boolean finalNeedsRedraw = needsRedraw;
        final String[] finalTimeStamps = timeStamps;
        final ChartButton finalChartButton = chartButton;

        managerUI.access(new Runnable() {
            @Override
            public void run() {
                // Here the UI is locked and can be updated

                if (finalNeedsRedraw) {
                    ManagerUI.log("ChartsLayout needsRedraw");

                    if (finalTimeStamps != null) {
                        XAxis xAxis = configuration.getxAxis();
                        Labels labels = new Labels();
                        labels.setRotation(-45);
                        labels.setAlign(HorizontalAlign.RIGHT);
                        xAxis.setLabels(labels);
                        xAxis.setCategories(finalTimeStamps);
                    }

                    chart.drawChart(configuration);
                    finalChartButton.setVisible(true);
                }

            }
        });

    }

    /* (non-Javadoc)
     * @see fi.jasoft.dragdroplayouts.DDCssLayout#paintContent(com.vaadin.server.PaintTarget)
     */
    @Override
    public void paintContent(PaintTarget target) throws PaintException {
        super.paintContent(target);

        // Override paintContent (vaadin serialization api) to set the
        // horizontal drop ratio to 50% so that we don't have a "CENTER"
        // position to drop things. See
        // VDDCssLayout#getHorizontalDropLocation() and
        // VDDCssLayout#handleCellDropRatioUpdate() for details
        target.addAttribute(Constants.ATTRIBUTE_HORIZONTAL_DROP_RATIO, 0.5f);
    }

    /**
     * The Class CustomCssLayoutDropHandler.
     */
    public static class CustomCssLayoutDropHandler extends DefaultCssLayoutDropHandler {

        /* (non-Javadoc)
         * @see fi.jasoft.dragdroplayouts.drophandlers.DefaultCssLayoutDropHandler#handleComponentReordering(com.vaadin.event.dd.DragAndDropEvent)
         */
        @Override
        protected void handleComponentReordering(DragAndDropEvent event) {
            LayoutBoundTransferable transferable = (LayoutBoundTransferable) event.getTransferable();
            CssLayoutTargetDetails details = (CssLayoutTargetDetails) event.getTargetDetails();

            // Get the components
            DDCssLayout layout = (DDCssLayout) details.getTarget();
            Component comp = transferable.getComponent();
            Component over = details.getOverComponent();

            if (over == comp) {
                // If the component and the target are the same, ignore the
                // drag, the component was released "on itself" so no
                // reordering is required.
                return;
            }

            // We are using a CSS layout with float:left; we only care about
            // horizontal positioning
            HorizontalDropLocation horizontalDropLocation = details.getHorizontalDropLocation();

            // Detach - remove current component first, then calculate index.
            layout.removeComponent(comp);
            int indexOfDropTarget = layout.getComponentIndex(over);

            // The layout has the component on top of which the drop occurred
            if (indexOfDropTarget > -1) {

                // If drop location is to the LEFT, add component before
                if (HorizontalDropLocation.LEFT.equals(horizontalDropLocation)
                        || HorizontalDropLocation.CENTER.equals(horizontalDropLocation)) {
                    layout.addComponent(comp, indexOfDropTarget);
                } else {

                    // If drop target is RIGHT, add after
                    indexOfDropTarget++;

                    if (indexOfDropTarget < layout.getComponentCount()) {
                        layout.addComponent(comp, indexOfDropTarget);
                    } else {
                        layout.addComponent(comp);
                    }
                }

            } else {
                // The current layout doesn't have the component on top of which
                // it was dropped, most likely the drop was on the underlying
                // layout itself. In this case we could look at the vertical
                // drop position to determine if we should add the component at
                // the top or the bottom in the layout.
                layout.addComponent(comp);

                // The else could be left out if we want to force the user to
                // drop the component on another component, i.e. dropping on
                // layout is not supported.
            }
        }
    }

}