changeset 743:19cb0438ff2e

Eclipse VM CPU chart This commit adds a new view in Eclipse for monitoring a VM's CPU, similar to the VM's CPU tab in the Swing GUI. Reviewed-by: jerboaa Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-September/003351.html
author Elliott Baron <ebaron@redhat.com>
date Thu, 25 Oct 2012 13:36:43 -0400
parents 061618d8bcba
children af6705a84860
files client/core/src/main/java/com/redhat/thermostat/client/ui/VmCpuController.java eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/SWTVmCpuView.java eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/SWTVmCpuViewProvider.java eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/VmCpuViewPart.java eclipse/com.redhat.thermostat.eclipse.test.ui/src/com/redhat/thermostat/eclipse/test/ui/SWTVmCpuViewTest.java eclipse/com.redhat.thermostat.eclipse.test/src/com/redhat/thermostat/eclipse/test/views/VmCpuViewPartTest.java
diffstat 6 files changed, 520 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/VmCpuController.java	Thu Oct 25 13:35:41 2012 -0400
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/VmCpuController.java	Thu Oct 25 13:36:43 2012 -0400
@@ -55,7 +55,7 @@
 import com.redhat.thermostat.common.model.DiscreteTimeData;
 import com.redhat.thermostat.common.model.VmCpuStat;
 
-class VmCpuController {
+public class VmCpuController {
 
     private final VmRef ref;
     private final VmCpuStatDAO dao;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/SWTVmCpuView.java	Thu Oct 25 13:36:43 2012 -0400
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat 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 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat 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 Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.eclipse.chart.common;
+
+import java.awt.EventQueue;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.JFreeChart;
+import org.jfree.data.time.FixedMillisecond;
+import org.jfree.data.time.RegularTimePeriod;
+import org.jfree.data.time.TimeSeries;
+import org.jfree.data.time.TimeSeriesCollection;
+
+import com.redhat.thermostat.client.core.views.VmCpuView;
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
+import com.redhat.thermostat.eclipse.ThermostatConstants;
+import com.redhat.thermostat.eclipse.views.SWTComponent;
+
+public class SWTVmCpuView extends VmCpuView implements SWTComponent {
+    
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+    
+    private final TimeSeriesCollection data;
+    private final TimeSeries cpuTimeSeries;
+    
+    private JFreeChart chart;
+    private ViewVisibilityWatcher watcher;
+    
+    public SWTVmCpuView() {
+        data = new TimeSeriesCollection();
+        cpuTimeSeries = new TimeSeries("cpu-stats");
+        watcher = new ViewVisibilityWatcher(notifier);
+        chart = createCpuChart();
+        
+        data.addSeries(cpuTimeSeries);
+    }
+    
+    public void createControl(Composite parent) {
+        Composite chartTop = new RecentTimeSeriesChartComposite(parent, SWT.NONE, chart);
+        chartTop.setLayout(new GridLayout());
+        chartTop.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+        
+        watcher.watch(parent, ThermostatConstants.VIEW_ID_VM_CPU);
+    }
+
+    private JFreeChart createCpuChart() {
+        JFreeChart chart = ChartFactory.createTimeSeriesChart(
+                null,
+                translator.localize(LocaleResources.VM_CPU_CHART_TIME_LABEL),
+                translator.localize(LocaleResources.VM_CPU_CHART_LOAD_LABEL),
+                data,
+                false, false, false);
+
+        chart.getXYPlot().getRangeAxis().setLowerBound(0.0);
+
+        return chart;
+    }
+    
+    @Override
+    public void addData(List<DiscreteTimeData<? extends Number>> data) {
+        final List<DiscreteTimeData<? extends Number>> copy = new ArrayList<>(data);
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                for (DiscreteTimeData<? extends Number> data: copy) {
+                    RegularTimePeriod period = new FixedMillisecond(data.getTimeInMillis());
+                    if (cpuTimeSeries.getDataItem(period) == null) {
+                        cpuTimeSeries.add(period, data.getData(), false);
+                    }
+                }
+                cpuTimeSeries.fireSeriesChanged();
+            }
+        });
+    }
+
+    @Override
+    public void clearData() {
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                cpuTimeSeries.clear();
+            }
+        });
+    }
+    
+    public JFreeChart getChart() {
+        return chart;
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/SWTVmCpuViewProvider.java	Thu Oct 25 13:36:43 2012 -0400
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat 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 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat 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 Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.eclipse.chart.common;
+
+import com.redhat.thermostat.client.core.views.VmCpuView;
+import com.redhat.thermostat.client.core.views.VmCpuViewProvider;
+
+public class SWTVmCpuViewProvider implements VmCpuViewProvider {
+
+    @Override
+    public VmCpuView createView() {
+        return new SWTVmCpuView();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/VmCpuViewPart.java	Thu Oct 25 13:36:43 2012 -0400
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat 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 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat 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 Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.eclipse.chart.common;
+
+import com.redhat.thermostat.client.core.views.VmCpuViewProvider;
+import com.redhat.thermostat.client.ui.VmCpuController;
+import com.redhat.thermostat.common.dao.VmCpuStatDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.eclipse.views.SWTComponent;
+
+public class VmCpuViewPart extends VmRefViewPart {
+
+    private VmCpuController controller;
+
+    @Override
+    protected void createControllerView(VmRef ref) {
+        VmCpuStatDAO vmCpuStatDao = OSGIUtils.getInstance().getService(
+                VmCpuStatDAO.class);
+        VmCpuViewProvider viewProvider = OSGIUtils.getInstance().getService(
+                VmCpuViewProvider.class);
+        controller = createController(vmCpuStatDao, ref, viewProvider);
+        SWTComponent view = (SWTComponent) controller.getView();
+        view.createControl(top);
+    }
+
+    public VmCpuController createController(VmCpuStatDAO vmCpuStatDao,
+            VmRef ref, VmCpuViewProvider viewProvider) {
+        return new VmCpuController(vmCpuStatDao, ref, viewProvider);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.test.ui/src/com/redhat/thermostat/eclipse/test/ui/SWTVmCpuViewTest.java	Thu Oct 25 13:36:43 2012 -0400
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat 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 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat 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 Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.eclipse.test.ui;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot;
+import org.eclipse.swtbot.swt.finder.waits.DefaultCondition;
+import org.jfree.chart.JFreeChart;
+import org.jfree.data.xy.XYDataset;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.model.DiscreteTimeData;
+import com.redhat.thermostat.eclipse.chart.common.SWTVmCpuView;
+
+public class SWTVmCpuViewTest {
+    private SWTWorkbenchBot bot;
+    private SWTVmCpuView view;
+    private Shell shell;
+
+    @Before
+    public void beforeTest() throws Exception {
+        bot = new SWTWorkbenchBot();
+        
+        Display.getDefault().syncExec(new Runnable() {
+
+            @Override
+            public void run() {
+                shell = new Shell(Display.getCurrent());
+                Composite parent = new Composite(shell, SWT.NONE);
+                parent.setLayout(new GridLayout());
+                parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
+                        true));
+                view = new SWTVmCpuView();
+                view.createControl(parent);
+                shell.open();
+            }
+        });
+    }
+
+    @After
+    public void afterTest() throws Exception {
+        Display.getDefault().syncExec(new Runnable() {
+
+            @Override
+            public void run() {
+                if (shell != null) {
+                    shell.close();
+                    view = null;
+                }
+            }
+        });
+    }
+    
+    @Test
+    public void testAddData() {
+        List<DiscreteTimeData<? extends Number>> data = new ArrayList<DiscreteTimeData<? extends Number>>();
+        
+        data.add(new DiscreteTimeData<Number>(1000L, 20));
+        data.add(new DiscreteTimeData<Number>(2000L, 80));
+        data.add(new DiscreteTimeData<Number>(3000L, 50));
+        
+        addSeries(data);
+        
+        JFreeChart chart = view.getChart();
+        XYDataset dataset = chart.getXYPlot().getDataset();
+        assertEquals(1000L, dataset.getX(0, 0));
+        assertEquals(2000L, dataset.getX(0, 1));
+        assertEquals(3000L, dataset.getX(0, 2));
+        
+        assertEquals(20, dataset.getY(0, 0));
+        assertEquals(80, dataset.getY(0, 1));
+        assertEquals(50, dataset.getY(0, 2));
+    }
+
+    private void addSeries(List<DiscreteTimeData<? extends Number>> data) {
+        view.addData(data);
+        
+        bot.waitUntil(new DefaultCondition() {
+            
+            @Override
+            public boolean test() throws Exception {
+                JFreeChart chart = view.getChart();
+                return chart.getXYPlot().getDataset().getItemCount(0) == 3;
+            }
+            
+            @Override
+            public String getFailureMessage() {
+                return "Data never added";
+            }
+        });
+    }
+
+    @Test
+    public void testClearData() {
+        List<DiscreteTimeData<? extends Number>> data = new ArrayList<DiscreteTimeData<? extends Number>>();
+        
+        data.add(new DiscreteTimeData<Number>(1000L, 20));
+        data.add(new DiscreteTimeData<Number>(2000L, 80));
+        data.add(new DiscreteTimeData<Number>(3000L, 50));
+        
+        addSeries(data);
+        
+        view.clearData();
+        
+        bot.waitUntil(new DefaultCondition() {
+            
+            @Override
+            public boolean test() throws Exception {
+                JFreeChart chart = view.getChart();
+                return chart.getXYPlot().getDataset().getItemCount(0) == 0;
+            }
+            
+            @Override
+            public String getFailureMessage() {
+                return "Data never cleared";
+            }
+        });
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.test/src/com/redhat/thermostat/eclipse/test/views/VmCpuViewPartTest.java	Thu Oct 25 13:36:43 2012 -0400
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat 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 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat 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 Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.eclipse.test.views;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.widgets.Composite;
+import org.junit.Test;
+
+import com.redhat.thermostat.client.core.views.VmCpuViewProvider;
+import com.redhat.thermostat.client.ui.VmCpuController;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.VmCpuStatDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.eclipse.chart.common.RefViewPart;
+import com.redhat.thermostat.eclipse.chart.common.SWTVmCpuView;
+import com.redhat.thermostat.eclipse.chart.common.VmCpuViewPart;
+
+public class VmCpuViewPartTest extends AbstractRefViewPartTest<VmRef> {
+
+    @Test
+    public void testSelectionHostRef() throws Exception {
+        view.createPartControl(parent);
+
+        HostRef hostRef = new HostRef("TEST", "Test");
+        IStructuredSelection selection = mockSelection(hostRef);
+        view.selectionChanged(hostVMView, selection);
+
+        // Ensure not created
+        verify(thermoView, never()).createControl(any(Composite.class));
+    }
+
+    @Test
+    public void testSelectionAfter() throws Exception {
+        view.createPartControl(parent);
+
+        HostRef hostRef = new HostRef("TEST", "Test");
+        VmRef vmRef = new VmRef(hostRef, 0, "Test");
+        IStructuredSelection selection = mockSelection(vmRef);
+        view.selectionChanged(hostVMView, selection);
+
+        verify(thermoView).createControl(any(Composite.class));
+    }
+
+    @Override
+    protected void mockController() {
+        VmCpuController controller = mock(VmCpuController.class);
+        thermoView = mock(SWTVmCpuView.class);
+
+        VmCpuStatDAO cpuStatDao = mock(VmCpuStatDAO.class);
+        VmCpuViewProvider viewProvider = mock(VmCpuViewProvider.class);
+        when(osgi.getService(VmCpuStatDAO.class)).thenReturn(cpuStatDao);
+        when(osgi.getService(VmCpuViewProvider.class)).thenReturn(viewProvider);
+
+        doReturn(controller).when(((VmCpuViewPart) view)).createController(
+                same(cpuStatDao), any(VmRef.class), same(viewProvider));
+        when(controller.getView()).thenReturn(thermoView);
+    }
+
+    @Override
+    protected RefViewPart<VmRef> createViewPart() {
+        return new VmCpuViewPart();
+    }
+
+}