Mercurial > hg > release > thermostat-1.2
changeset 1576:a614e6dec69a
The vm-class-stats tab should fetch less data
Reviewed-by: omajid
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2014-November/011470.html
PR2020
line wrap: on
line diff
--- a/client/core/pom.xml Fri Nov 28 13:48:29 2014 -0500 +++ b/client/core/pom.xml Fri Nov 28 15:47:39 2014 -0500 @@ -121,6 +121,7 @@ <Export-Package> com.redhat.thermostat.client.ui, com.redhat.thermostat.client.locale, + com.redhat.thermostat.client.core.experimental, <!-- Interfaces for views, controllers, etc. --> com.redhat.thermostat.client.core, com.redhat.thermostat.client.core.progress,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/core/src/main/java/com/redhat/thermostat/client/core/experimental/Duration.java Fri Nov 28 15:47:39 2014 -0500 @@ -0,0 +1,54 @@ +/* + * Copyright 2012-2014 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.client.core.experimental; + +import java.util.concurrent.TimeUnit; + +public class Duration { + public final int value; + public final TimeUnit unit; + + public Duration(int value, TimeUnit unit) { + this.value = value; + this.unit = unit; + } + + @Override + public String toString() { + return value + " " + unit; + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/core/src/main/java/com/redhat/thermostat/client/core/experimental/SingleValueStat.java Fri Nov 28 15:47:39 2014 -0500 @@ -0,0 +1,45 @@ +/* + * Copyright 2012-2014 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.client.core.experimental; + +import com.redhat.thermostat.storage.model.TimeStampedPojo; + +public interface SingleValueStat<T> extends TimeStampedPojo { + + public T getValue(); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/core/src/main/java/com/redhat/thermostat/client/core/experimental/SingleValueSupplier.java Fri Nov 28 15:47:39 2014 -0500 @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2014 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.client.core.experimental; + +import com.redhat.thermostat.storage.core.VmRef; + +import java.util.List; + +public interface SingleValueSupplier<T> { + + public abstract List<T> getStats(VmRef ref, long since, long to); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/core/src/main/java/com/redhat/thermostat/client/core/experimental/TimeRangeComputer.java Fri Nov 28 15:47:39 2014 -0500 @@ -0,0 +1,102 @@ +/* + * Copyright 2012-2014 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.client.core.experimental; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.redhat.thermostat.common.model.Range; + +/** + * Compute additional data ranges to fetch when trying to update a currently + * displayed time-data with additional time-data. + */ +public class TimeRangeComputer { + + public static List<Range<Long>> computeAdditionalRangesToFetch(Range<Long> availableRange, Range<Long> desiredRange, Range<Long> displayedRange) { + + // TODO find out how to show 'sampled' values across a + // very, very large desiredRange + + // Do we need to show additional data? + if (displayedRange.equals(desiredRange)) { + return Collections.emptyList(); + } + + // Do we already have all the data? + if (contains(displayedRange, desiredRange)) { + // TODO 'narrow' view to the desired range + return Collections.emptyList(); + } + + // What's the best that we can do with the desired range? + Range<Long> closestInterval = closestInterval(availableRange, desiredRange); + + List<Range<Long>> results = new ArrayList<>(); + if (closestInterval.getMin() < displayedRange.getMin()) { + if (closestInterval.getMax() < displayedRange.getMin()) { + results.add(closestInterval); + } else if (closestInterval.getMax() < displayedRange.getMax()) { + results.add(new Range<>(closestInterval.getMin(), displayedRange.getMin())); + } else { + results.add(new Range<>(closestInterval.getMin(), displayedRange.getMin())); + results.add(new Range<>(displayedRange.getMax(), closestInterval.getMax())); + } + } else if (closestInterval.getMin() < displayedRange.getMax()) { + if (closestInterval.getMax() < displayedRange.getMax()) { + // nothing to do here + } else if (closestInterval.getMax() > displayedRange.getMax()) { + results.add(new Range<>(displayedRange.getMax(), closestInterval.getMax())); + } + } else { + results.add(closestInterval); + } + return results; + } + + private static boolean contains(Range<Long> larger, Range<Long> smaller) { + return (larger.getMin() <= smaller.getMin()) && (larger.getMax() >= smaller.getMax()); + } + + private static Range<Long> closestInterval(Range<Long> avilable, Range<Long> desired) { + long min = Math.max(avilable.getMin(), desired.getMin()); + long max = Math.min(avilable.getMax(), desired.getMax()); + return new Range<>(min, max); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/core/src/main/java/com/redhat/thermostat/client/core/experimental/TimeRangeController.java Fri Nov 28 15:47:39 2014 -0500 @@ -0,0 +1,101 @@ +/* + * Copyright 2012-2014 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.client.core.experimental; + +import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.storage.model.DiscreteTimeData; + +import java.util.ArrayList; +import java.util.List; + +public class TimeRangeController { + + private Range<Long> availableRange = new Range<>(Long.MAX_VALUE, Long.MIN_VALUE); + private Range<Long> displayedRange = new Range<>(Long.MAX_VALUE, Long.MIN_VALUE); + private List<DiscreteTimeData<Number>> allToDisplay; + + public void update(Duration userDesiredDuration,Range<Long> newAvailableRange, SingleValueSupplier dao, VmRef ref) { + long now = System.currentTimeMillis(); + long userVisibleTimeDelta = (userDesiredDuration.unit.toMillis(userDesiredDuration.value)); + Range<Long> desiredRange = new Range<>(now - userVisibleTimeDelta, now); + + if (availableRange.equals(newAvailableRange)) { + return; + } + + availableRange = newAvailableRange; + + List<Range<Long>> additionalIntervals = TimeRangeComputer.computeAdditionalRangesToFetch(availableRange, desiredRange, displayedRange); + + long displayedMin = Math.min(displayedRange.getMin(), Long.MAX_VALUE); + long displayedMax = Math.max(displayedRange.getMax(), Long.MIN_VALUE); + + allToDisplay = new ArrayList<>(); + for (Range<Long> interval : additionalIntervals) { + List<SingleValueStat> stats = dao.getStats(ref, interval.getMin(), interval.getMax()); + allToDisplay.addAll(getDiscreteTimeData(stats)); + + displayedMin = Math.min(displayedMin, interval.getMin()); + displayedMax = Math.max(displayedMax, interval.getMax()); + } + + // the view does not show data older than the delta + displayedMin = Math.max(displayedMin, displayedMax - userVisibleTimeDelta); + + displayedRange = new Range<>(displayedMin, displayedMax); + } + + public List<DiscreteTimeData<Number>> getDataToDisplay() { + return new ArrayList<>(allToDisplay); + } + + private List<DiscreteTimeData<Number>> getDiscreteTimeData(List<SingleValueStat> stats) { + List<DiscreteTimeData<Number>> toDisplay = new ArrayList<>(stats.size()); + + for (SingleValueStat stat : stats) { + DiscreteTimeData<Number> data = + new DiscreteTimeData<>(stat.getTimeStamp(),(Number) stat.getValue()); + toDisplay.add(data); + } + return toDisplay; + } + + public Range<Long> getAvailableRange() { + return availableRange; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/core/src/test/java/com/redhat/thermostat/client/core/experimental/TimeRangeComputerTest.java Fri Nov 28 15:47:39 2014 -0500 @@ -0,0 +1,98 @@ +/* + * Copyright 2012-2014 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.client.core.experimental; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.junit.Test; + +import com.redhat.thermostat.common.model.Range; + +public class TimeRangeComputerTest { + + @Test + public void verifyComputesEmptyResultIfAllDataIsAvaialable() { + Range<Long> available = new Range<>(1l, 10l); + Range<Long> desired = new Range<>(2l, 3l); + Range<Long> displayed = new Range<>(1l, 10l); + + List<Range<Long>> result = TimeRangeComputer.computeAdditionalRangesToFetch(available, desired, displayed); + + assertTrue(result.isEmpty()); + } + + @Test + public void verifyComputesRangeBeforeCorrectly() { + Range<Long> available = new Range<>(1l, 10l); + Range<Long> desired = new Range<>(1l, 7l); + Range<Long> displayed = new Range<>(5l, 10l); + + List<Range<Long>> result = TimeRangeComputer.computeAdditionalRangesToFetch(available, desired, displayed); + + assertEquals(1, result.size()); + assertEquals(new Range<>(1l,5l), result.get(0)); + } + + @Test + public void verifyComputesRangeAfterCorrectly() { + Range<Long> available = new Range<>(1l, 10l); + Range<Long> desired = new Range<>(2l, 6l); + Range<Long> displayed = new Range<>(1l, 5l); + + List<Range<Long>> result = TimeRangeComputer.computeAdditionalRangesToFetch(available, desired, displayed); + + assertEquals(1, result.size()); + assertEquals(new Range<>(5l,6l), result.get(0)); + } + + @Test + public void verifyComputesOverlappingRangeCorrectly() { + Range<Long> available = new Range<>(1l, 10l); + Range<Long> desired = new Range<>(2l, 8l); + Range<Long> displayed = new Range<>(4l, 6l); + + List<Range<Long>> result = TimeRangeComputer.computeAdditionalRangesToFetch(available, desired, displayed); + + assertEquals(2, result.size()); + assertEquals(new Range<>(2l,4l), result.get(0)); + assertEquals(new Range<>(6l, 8l), result.get(1)); + } + +}
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/RecentTimeSeriesChartPanel.java Fri Nov 28 13:48:29 2014 -0500 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/RecentTimeSeriesChartPanel.java Fri Nov 28 15:47:39 2014 -0500 @@ -40,8 +40,6 @@ import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.util.concurrent.TimeUnit; import javax.swing.DefaultComboBoxModel; @@ -50,12 +48,10 @@ import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.SwingUtilities; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; -import javax.swing.text.BadLocationException; -import javax.swing.text.Document; import javax.swing.text.JTextComponent; +import com.redhat.thermostat.client.core.experimental.Duration; +import com.redhat.thermostat.client.swing.components.experimental.TimeUnitChangeListener; import org.jfree.chart.ChartPanel; import com.redhat.thermostat.client.locale.LocaleResources; @@ -125,7 +121,13 @@ int defaultValue = controller.getTimeValue(); TimeUnit defaultUnit = controller.getTimeUnit(); - TimeUnitChangeListener timeUnitChangeListener = new TimeUnitChangeListener(controller, defaultValue, defaultUnit); + TimeUnitChangeListener timeUnitChangeListener = new TimeUnitChangeListener(new com.redhat.thermostat.common.ActionListener() { + @Override + public void actionPerformed(final com.redhat.thermostat.common.ActionEvent actionEvent) { + Duration d = (Duration) actionEvent.getPayload(); + controller.setTime(d.value, d.unit); + } + }, defaultValue, defaultUnit); durationSelector.getDocument().addDocumentListener(timeUnitChangeListener); unitSelector.addActionListener(timeUnitChangeListener); @@ -166,56 +168,5 @@ }); } - private static class TimeUnitChangeListener implements DocumentListener, ActionListener { - - private final RecentTimeSeriesChartController controller; - private int value; - private TimeUnit unit; - - public TimeUnitChangeListener(RecentTimeSeriesChartController controller, int defaultValue, TimeUnit defaultUnit) { - this.controller = controller; - this.value = defaultValue; - this.unit = defaultUnit; - } - - @Override - public void removeUpdate(DocumentEvent event) { - changed(event.getDocument()); - } - - @Override - public void insertUpdate(DocumentEvent event) { - changed(event.getDocument()); - } - - @Override - public void changedUpdate(DocumentEvent event) { - changed(event.getDocument()); - } - - private void changed(Document doc) { - try { - this.value = Integer.valueOf(doc.getText(0, doc.getLength())); - } catch (NumberFormatException nfe) { - // ignore - } catch (BadLocationException ble) { - // ignore - } - updateChartParameters(); - } - - private void updateChartParameters() { - controller.setTime(value, unit); - } - - @Override - public void actionPerformed(ActionEvent e) { - @SuppressWarnings("unchecked") // We are a TimeUnitChangeListener, specifically. - JComboBox<TimeUnit> comboBox = (JComboBox<TimeUnit>) e.getSource(); - TimeUnit time = (TimeUnit) comboBox.getSelectedItem(); - this.unit = time; - updateChartParameters(); - } - } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/experimental/SingleValueChartPanel.java Fri Nov 28 15:47:39 2014 -0500 @@ -0,0 +1,192 @@ +/* + * Copyright 2012-2014 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.client.swing.components.experimental; + +import com.redhat.thermostat.client.core.experimental.Duration; +import com.redhat.thermostat.client.locale.LocaleResources; +import com.redhat.thermostat.client.swing.components.ValueField; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.shared.locale.Translate; +import org.jfree.chart.ChartPanel; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.plot.XYPlot; + +import javax.swing.text.JTextComponent; +import java.util.concurrent.TimeUnit; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; + +import javax.swing.DefaultComboBoxModel; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; + + +public class SingleValueChartPanel extends JPanel { + + static final TimeUnit[] DEFAULT_TIMEUNITS = new TimeUnit[] { TimeUnit.DAYS, TimeUnit.HOURS, TimeUnit.MINUTES }; + + public static final String PROPERTY_VISIBLE_TIME_RANGE = "visibleTimeRange"; + + private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); + + private static final int MINIMUM_DRAW_SIZE = 100; + + private ChartPanel chartPanel; + + private JPanel labelContainer; + private JTextComponent label; + + public SingleValueChartPanel(JFreeChart chart, Duration duration) { + + this.setLayout(new BorderLayout()); + + // instead of just disabling display of tooltips, disable their generation too + if (chart.getPlot() instanceof XYPlot) { + chart.getXYPlot().getRenderer().setBaseToolTipGenerator(null); + } + + chart.getXYPlot().getRangeAxis().setAutoRange(true); + + chart.getXYPlot().getDomainAxis().setAutoRange(true); + chart.getXYPlot().getDomainAxis().setFixedAutoRange(duration.unit.toMillis(duration.value)); + + chartPanel = new ChartPanel(chart); + + chartPanel.setDisplayToolTips(false); + chartPanel.setDoubleBuffered(true); + chartPanel.setMouseZoomable(false); + chartPanel.setPopupMenu(null); + + /* + * By default, ChartPanel scales itself instead of redrawing things when + * it's resized. To have it resize automatically, we need to set minimum + * and maximum sizes. Lets constrain the minimum, but not the maximum + * size. + */ + chartPanel.setMinimumDrawHeight(MINIMUM_DRAW_SIZE); + chartPanel.setMaximumDrawHeight(Integer.MAX_VALUE); + chartPanel.setMinimumDrawWidth(MINIMUM_DRAW_SIZE); + chartPanel.setMaximumDrawWidth(Integer.MAX_VALUE); + + add(chartPanel, BorderLayout.CENTER); + add(getControlsAndAdditionalDisplay(duration), BorderLayout.SOUTH); + + } + + private Component getControlsAndAdditionalDisplay(Duration duration) { + JPanel container = new JPanel(); + container.setOpaque(false); + + container.setLayout(new BorderLayout()); + + container.add(getChartControls(duration), BorderLayout.LINE_START); + container.add(getAdditionalDataDisplay(), BorderLayout.LINE_END); + + return container; + } + + private Component getChartControls(Duration duration) { + JPanel container = new JPanel(); + container.setOpaque(false); + + final JTextField durationSelector = new JTextField(5); + final JComboBox<TimeUnit> unitSelector = new JComboBox<>(); + unitSelector.setModel(new DefaultComboBoxModel<>(DEFAULT_TIMEUNITS)); + + TimeUnitChangeListener timeUnitChangeListener = new TimeUnitChangeListener(new ActionListener() { + @Override + public void actionPerformed(final com.redhat.thermostat.common.ActionEvent actionEvent) { + Duration d = (Duration) actionEvent.getPayload(); + SingleValueChartPanel.this.firePropertyChange(PROPERTY_VISIBLE_TIME_RANGE, null, d); + } + }, duration.value, duration.unit); + + durationSelector.getDocument().addDocumentListener(timeUnitChangeListener); + unitSelector.addActionListener(timeUnitChangeListener); + + durationSelector.setText(String.valueOf(duration.value)); + unitSelector.setSelectedItem(duration.unit); + + container.add(new JLabel(translator.localize(LocaleResources.CHART_DURATION_SELECTOR_LABEL).getContents())); + container.add(durationSelector); + container.add(unitSelector); + + return container; + } + + private Component getAdditionalDataDisplay() { + JPanel panel = new JPanel(new GridBagLayout()); + panel.setOpaque(false); + labelContainer = new JPanel(); + labelContainer.setOpaque(false); + GridBagConstraints constraints = new GridBagConstraints(); + constraints.fill = GridBagConstraints.BOTH; + constraints.anchor = GridBagConstraints.CENTER; + panel.add(labelContainer, constraints); + return panel; + } + + public void setTimeRangeToShow(int timeValue, TimeUnit timeUnit) { + XYPlot plot = chartPanel.getChart().getXYPlot(); + + // Don't drop old data; just dont' show it. + plot.getDomainAxis().setAutoRange(true); + plot.getDomainAxis().setFixedAutoRange(timeUnit.toMillis(timeValue)); + } + + public void setDataInformationLabel(final String text) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (label == null) { + label = new ValueField(text); + labelContainer.add(label); + } + + label.setText(text); + } + }); + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/experimental/TimeUnitChangeListener.java Fri Nov 28 15:47:39 2014 -0500 @@ -0,0 +1,108 @@ +/* + * Copyright 2012-2014 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.client.swing.components.experimental; + +import javax.swing.JComboBox; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import java.util.concurrent.TimeUnit; + +import com.redhat.thermostat.client.core.experimental.Duration; +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; + +public class TimeUnitChangeListener implements DocumentListener, java.awt.event.ActionListener { + + public enum TimeChangeEvent { + TIME_CHANGE_EVENT; + } + + + private final ActionListener listener; + private int value; + private TimeUnit unit; + + public TimeUnitChangeListener(ActionListener listener, int defaultValue, TimeUnit defaultUnit) { + this.listener = listener; + this.value = defaultValue; + this.unit = defaultUnit; + } + + @Override + public void removeUpdate(DocumentEvent event) { + changed(event.getDocument()); + } + + @Override + public void insertUpdate(DocumentEvent event) { + changed(event.getDocument()); + } + + @Override + public void changedUpdate(DocumentEvent event) { + changed(event.getDocument()); + } + + private void changed(Document doc) { + try { + this.value = Integer.valueOf(doc.getText(0, doc.getLength())); + } catch (NumberFormatException nfe) { + // ignore + } catch (BadLocationException ble) { + // ignore + } + fireTimeChanged(); + } + + private void fireTimeChanged() { + ActionEvent e = new ActionEvent(this, TimeChangeEvent.TIME_CHANGE_EVENT); + e.setPayload(new Duration(this.value, this.unit)); + listener.actionPerformed(e); + } + + @Override + public void actionPerformed(final java.awt.event.ActionEvent e) { + @SuppressWarnings("unchecked") // We are a TimeUnitChangeListener, specifically. + JComboBox<TimeUnit> comboBox = (JComboBox<TimeUnit>) e.getSource(); + TimeUnit time = (TimeUnit) comboBox.getSelectedItem(); + this.unit = time; + fireTimeChanged(); + } + +} \ No newline at end of file
--- a/distribution/config/commands/vm-stat.properties Fri Nov 28 13:48:29 2014 -0500 +++ b/distribution/config/commands/vm-stat.properties Fri Nov 28 15:47:39 2014 -0500 @@ -2,6 +2,7 @@ com.redhat.thermostat.storage.mongodb=${project.version}, \ com.redhat.thermostat.web.common=${project.version}, \ com.redhat.thermostat.web.client=${project.version}, \ + com.redhat.thermostat.client.core=${project.version}, \ org.apache.httpcomponents.httpcore=${httpcomponents.core.version}, \ org.apache.httpcomponents.httpclient=${httpcomponents.client.version}, \ ${osgi.compendium.bundle.symbolic-name}=${osgi.compendium.osgi-version}, \
--- a/vm-classstat/client-core/src/main/java/com/redhat/thermostat/vm/classstat/client/core/VmClassStatView.java Fri Nov 28 13:48:29 2014 -0500 +++ b/vm-classstat/client-core/src/main/java/com/redhat/thermostat/vm/classstat/client/core/VmClassStatView.java Fri Nov 28 15:47:39 2014 -0500 @@ -37,13 +37,31 @@ package com.redhat.thermostat.vm.classstat.client.core; import java.util.List; +import java.util.concurrent.TimeUnit; import com.redhat.thermostat.client.core.views.BasicView; import com.redhat.thermostat.client.core.views.UIComponent; +import com.redhat.thermostat.client.core.experimental.Duration; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.model.Range; import com.redhat.thermostat.storage.model.DiscreteTimeData; public abstract class VmClassStatView extends BasicView implements UIComponent { + public enum UserAction { + USER_CHANGED_TIME_RANGE, + } + + public abstract void addUserActionListener(ActionListener<UserAction> listener); + + public abstract void removeUserActionListener(ActionListener<UserAction> listener); + + public abstract Duration getUserDesiredDuration(); + + public abstract void setVisibleDataRange(int time, TimeUnit unit); + + public abstract void setAvailableDataRange(Range<Long> availableDataRange); + public abstract void clearClassCount(); public abstract void addClassCount(List<DiscreteTimeData<Long>> data);
--- a/vm-classstat/client-core/src/main/java/com/redhat/thermostat/vm/classstat/client/core/internal/VmClassStatController.java Fri Nov 28 13:48:29 2014 -0500 +++ b/vm-classstat/client-core/src/main/java/com/redhat/thermostat/vm/classstat/client/core/internal/VmClassStatController.java Fri Nov 28 15:47:39 2014 -0500 @@ -43,16 +43,20 @@ import com.redhat.thermostat.client.core.controllers.InformationServiceController; import com.redhat.thermostat.client.core.views.UIComponent; import com.redhat.thermostat.client.core.views.BasicView.Action; +import com.redhat.thermostat.client.core.experimental.Duration; +import com.redhat.thermostat.client.core.experimental.TimeRangeController; import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.ApplicationService; import com.redhat.thermostat.common.NotImplementedException; import com.redhat.thermostat.common.Timer; import com.redhat.thermostat.common.Timer.SchedulingType; +import com.redhat.thermostat.common.model.Range; import com.redhat.thermostat.shared.locale.LocalizedString; import com.redhat.thermostat.shared.locale.Translate; import com.redhat.thermostat.storage.core.VmRef; -import com.redhat.thermostat.storage.model.DiscreteTimeData; +import com.redhat.thermostat.client.core.experimental.SingleValueSupplier; +import com.redhat.thermostat.client.core.experimental.SingleValueStat; import com.redhat.thermostat.vm.classstat.client.core.VmClassStatView; import com.redhat.thermostat.vm.classstat.client.core.VmClassStatViewProvider; import com.redhat.thermostat.vm.classstat.client.locale.LocaleResources; @@ -63,19 +67,46 @@ private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); + private TimeRangeController timeRangeController; + private class UpdateChartData implements Runnable { @Override public void run() { - long timeStamp = lastSeenTimeStamp; - List<VmClassStat> latestClassStats = dao.getLatestClassStats(ref, timeStamp); - List<DiscreteTimeData<Long>> timeData = new ArrayList<>(); - for (VmClassStat stat : latestClassStats) { - timeData.add(new DiscreteTimeData<Long>(stat.getTimeStamp(), stat.getLoadedClasses())); - timeStamp = Math.max(timeStamp, stat.getTimeStamp()); - } - classesView.addClassCount(timeData); - lastSeenTimeStamp = timeStamp; + + VmClassStat oldest = dao.getOldest(ref); + VmClassStat latest = dao.getLatest(ref); + + Range<Long> newAvailableRange = new Range<>(oldest.getTimeStamp(), latest.getTimeStamp()); + + SingleValueSupplier singleValueSupplier = new SingleValueSupplier() { + @Override + public List getStats(final VmRef ref, final long since, final long to) { + List<VmClassStat> stats = dao.getClassStats(ref, since, to); + List<SingleValueStat<Long>> singleValueStats = new ArrayList<>(); + for (final VmClassStat stat : stats ) { + singleValueStats.add(new SingleValueStat<Long>() { + @Override + public Long getValue() { + return stat.getLoadedClasses(); + } + + @Override + public long getTimeStamp() { + return stat.getTimeStamp(); + } + }); + } + return singleValueStats; + } + }; + + timeRangeController.update(userDesiredDuration, newAvailableRange, singleValueSupplier, ref); + classesView.setAvailableDataRange(timeRangeController.getAvailableRange()); + + List classCount = timeRangeController.getDataToDisplay(); + classesView.addClassCount(classCount); } + } private final VmClassStatView classesView; @@ -83,7 +114,7 @@ private final VmClassStatDAO dao; private final Timer timer; - private volatile long lastSeenTimeStamp = Long.MIN_VALUE; + private Duration userDesiredDuration; public VmClassStatController(ApplicationService appSvc, VmClassStatDAO vmClassStatDao, VmRef ref, VmClassStatViewProvider viewProvider) { this.ref = ref; @@ -113,6 +144,27 @@ } } }); + + classesView.addUserActionListener(new ActionListener<VmClassStatView.UserAction>() { + + @Override + public void actionPerformed(final ActionEvent<VmClassStatView.UserAction> actionEvent) { + switch (actionEvent.getActionId()) { + case USER_CHANGED_TIME_RANGE: + Duration duration = classesView.getUserDesiredDuration(); + userDesiredDuration = duration; + classesView.setVisibleDataRange(duration.value, duration.unit); + break; + default: + throw new AssertionError("Unhandled action type"); + } + } + }); + + userDesiredDuration = classesView.getUserDesiredDuration(); + + timeRangeController = new TimeRangeController(); + } private void start() {
--- a/vm-classstat/client-core/src/test/java/com/redhat/thermostat/vm/classstat/client/core/internal/VmClassStatControllerTest.java Fri Nov 28 13:48:29 2014 -0500 +++ b/vm-classstat/client-core/src/test/java/com/redhat/thermostat/vm/classstat/client/core/internal/VmClassStatControllerTest.java Fri Nov 28 15:47:39 2014 -0500 @@ -37,7 +37,6 @@ package com.redhat.thermostat.vm.classstat.client.core.internal; import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -45,7 +44,9 @@ import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeUnit; +import com.redhat.thermostat.client.core.experimental.Duration; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -71,10 +72,13 @@ stats.add(stat1); VmClassStatDAO vmClassStatDAO = mock(VmClassStatDAO.class); - when(vmClassStatDAO.getLatestClassStats(any(VmRef.class), anyInt())).thenReturn(stats).thenReturn(new ArrayList<VmClassStat>()); VmRef ref = mock(VmRef.class); + when(vmClassStatDAO.getLatestClassStats(any(VmRef.class), any(Long.class))).thenThrow(new AssertionError("Unbounded queries are bad!")); + when(vmClassStatDAO.getOldest(ref)).thenReturn(stat1); + when(vmClassStatDAO.getLatest(ref)).thenReturn(stat1); + Timer timer = mock(Timer.class); ArgumentCaptor<Runnable> timerActionCaptor = ArgumentCaptor.forClass(Runnable.class); doNothing().when(timer).setAction(timerActionCaptor.capture()); @@ -87,7 +91,9 @@ VmClassStatView view = mock(VmClassStatView.class); ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class); doNothing().when(view).addActionListener(viewArgumentCaptor.capture()); - + + when(view.getUserDesiredDuration()).thenReturn(new Duration(1, TimeUnit.MINUTES)); + VmClassStatViewProvider viewProvider = mock(VmClassStatViewProvider.class); when(viewProvider.createView()).thenReturn(view);
--- a/vm-classstat/client-swing/src/main/java/com/redhat/thermostat/vm/classstat/client/swing/VmClassStatPanel.java Fri Nov 28 13:48:29 2014 -0500 +++ b/vm-classstat/client-swing/src/main/java/com/redhat/thermostat/vm/classstat/client/swing/VmClassStatPanel.java Fri Nov 28 15:47:39 2014 -0500 @@ -37,12 +37,17 @@ package com.redhat.thermostat.vm.classstat.client.swing; import java.awt.Component; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeUnit; -import javax.swing.JComponent; import javax.swing.SwingUtilities; +import com.redhat.thermostat.client.core.experimental.Duration; +import com.redhat.thermostat.client.swing.components.experimental.SingleValueChartPanel; +import com.redhat.thermostat.common.model.Range; import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.NumberAxis; @@ -56,9 +61,7 @@ import com.redhat.thermostat.client.swing.SwingComponent; import com.redhat.thermostat.client.swing.components.HeaderPanel; -import com.redhat.thermostat.client.swing.components.RecentTimeSeriesChartPanel; import com.redhat.thermostat.client.swing.experimental.ComponentVisibilityNotifier; -import com.redhat.thermostat.client.ui.RecentTimeSeriesChartController; import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.ActionNotifier; import com.redhat.thermostat.shared.locale.Translate; @@ -70,10 +73,19 @@ private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); + private static final int DEFAULT_VALUE = 10; + private static final TimeUnit DEFAULT_UNIT = TimeUnit.MINUTES; + + private Duration duration; + private HeaderPanel visiblePanel; private final TimeSeriesCollection dataset = new TimeSeriesCollection(); + private SingleValueChartPanel chartPanel; + + private ActionNotifier<UserAction> userActionActionNotifier = new ActionNotifier<VmClassStatView.UserAction>(this); + private final ActionNotifier<Action> notifier = new ActionNotifier<Action>(this); public VmClassStatPanel() { @@ -81,6 +93,8 @@ // any name works dataset.addSeries(new TimeSeries("class-stat")); + duration = new Duration(DEFAULT_VALUE, DEFAULT_UNIT); + visiblePanel.setHeader(t.localize(LocaleResources.VM_LOADED_CLASSES)); JFreeChart chart = ChartFactory.createTimeSeriesChart( @@ -104,10 +118,18 @@ axis.setRangeType(RangeType.POSITIVE); axis.setAutoRangeMinimumSize(10); - JComponent chartPanel = new RecentTimeSeriesChartPanel(new RecentTimeSeriesChartController(chart)); + chartPanel = new SingleValueChartPanel(chart, duration); visiblePanel.setContent(chartPanel); + chartPanel.addPropertyChangeListener(SingleValueChartPanel.PROPERTY_VISIBLE_TIME_RANGE, new PropertyChangeListener() { + @Override + public void propertyChange(final PropertyChangeEvent evt) { + duration = (Duration) evt.getNewValue(); + userActionActionNotifier.fireAction(UserAction.USER_CHANGED_TIME_RANGE); + } + }); + new ComponentVisibilityNotifier().initialize(visiblePanel, notifier); } @@ -141,6 +163,31 @@ } @Override + public void addUserActionListener(final ActionListener<UserAction> listener) { + userActionActionNotifier.addActionListener(listener); + } + + @Override + public void removeUserActionListener(final ActionListener<UserAction> listener) { + userActionActionNotifier.removeActionListener(listener); + } + + @Override + public Duration getUserDesiredDuration() { + return duration; + } + + @Override + public void setVisibleDataRange(final int time, final TimeUnit unit) { + chartPanel.setTimeRangeToShow(time, unit); + } + + @Override + public void setAvailableDataRange(final Range<Long> availableDataRange) { + // FIXME indicate the total data range to the user somehow + } + + @Override public void clearClassCount() { SwingUtilities.invokeLater(new Runnable() { @Override
--- a/vm-classstat/common/pom.xml Fri Nov 28 13:48:29 2014 -0500 +++ b/vm-classstat/common/pom.xml Fri Nov 28 15:47:39 2014 -0500 @@ -124,5 +124,10 @@ <version>${project.version}</version> <scope>test</scope> </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-client-core</artifactId> + <version>${project.version}</version> + </dependency> </dependencies> </project>
--- a/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/VmClassStatDAO.java Fri Nov 28 13:48:29 2014 -0500 +++ b/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/VmClassStatDAO.java Fri Nov 28 15:47:39 2014 -0500 @@ -56,7 +56,13 @@ public List<VmClassStat> getLatestClassStats(VmRef ref, long since); + public List<VmClassStat> getClassStats(VmRef ref, long since, long to); + public void putVmClassStat(VmClassStat stat); + public abstract VmClassStat getOldest(VmRef ref); + + public abstract VmClassStat getLatest(VmRef ref); + }
--- a/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImpl.java Fri Nov 28 13:48:29 2014 -0500 +++ b/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImpl.java Fri Nov 28 15:47:39 2014 -0500 @@ -41,6 +41,7 @@ import java.util.logging.Logger; import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.DescriptorParsingException; import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.PreparedStatement; @@ -49,6 +50,7 @@ import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.core.VmLatestPojoListGetter; import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.storage.core.VmTimeIntervalPojoListGetter; import com.redhat.thermostat.vm.classstat.common.VmClassStatDAO; import com.redhat.thermostat.vm.classstat.common.model.VmClassStat; @@ -65,13 +67,35 @@ "'" + Key.TIMESTAMP.getName() + "' = ?l , " + "'" + loadedClassesKey.getName() + "' = ?l"; + // LATEST vm-cpu-stats WHERE 'agentId' = ?s AND \ + // 'vmId' = ?s \ + // SORT 'timeStamp' ASC \ + // LIMIT 1 + static final String DESC_OLDEST_VM_CLASS_STAT = "QUERY " + vmClassStatsCategory.getName() + + " WHERE '" + Key.AGENT_ID.getName() + "' = ?s " + + " AND '" + Key.VM_ID.getName() + "' = ?s " + + " SORT '" + Key.TIMESTAMP.getName() + "' ASC " + + " LIMIT 1"; + + // LATEST vm-cpu-stats WHERE 'agentId' = ?s AND \ + // 'vmId' = ?s \ + // SORT 'timeStamp' DSC \ + // LIMIT 1 + static final String DESC_LATEST_VM_CLASS_STAT = "QUERY " + vmClassStatsCategory.getName() + + " WHERE '" + Key.AGENT_ID.getName() + "' = ?s " + + " AND '" + Key.VM_ID.getName() + "' = ?s " + + " SORT '" + Key.TIMESTAMP.getName() + "' DSC " + + " LIMIT 1"; + private final Storage storage; private final VmLatestPojoListGetter<VmClassStat> getter; + private final VmTimeIntervalPojoListGetter<VmClassStat> otherGetter; VmClassStatDAOImpl(Storage storage) { this.storage = storage; storage.registerCategory(vmClassStatsCategory); this.getter = new VmLatestPojoListGetter<>(storage, vmClassStatsCategory); + this.otherGetter = new VmTimeIntervalPojoListGetter<>(storage, vmClassStatsCategory); } @Override @@ -80,6 +104,11 @@ } @Override + public List<VmClassStat> getClassStats(VmRef ref, long since, long to) { + return otherGetter.getLatest(ref, since, to); + } + + @Override public void putVmClassStat(VmClassStat stat) { StatementDescriptor<VmClassStat> desc = new StatementDescriptor<>(vmClassStatsCategory, DESC_ADD_VM_CLASS_STAT); PreparedStatement<VmClassStat> prepared; @@ -96,5 +125,34 @@ logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e); } } + + @Override + public VmClassStat getOldest(final VmRef ref) { + return runAgentAndVmIdQuery(ref, DESC_OLDEST_VM_CLASS_STAT); + } + + @Override + public VmClassStat getLatest(final VmRef ref) { + return runAgentAndVmIdQuery(ref, DESC_LATEST_VM_CLASS_STAT); + } + + private VmClassStat runAgentAndVmIdQuery(final VmRef ref, final String descriptor) { + StatementDescriptor<VmClassStat> desc = new StatementDescriptor<>(vmClassStatsCategory, descriptor); + PreparedStatement<VmClassStat> prepared; + try { + prepared = storage.prepareStatement(desc); + prepared.setString(0, ref.getHostRef().getAgentId()); + prepared.setString(1, ref.getVmId()); + Cursor<VmClassStat> cursor = prepared.executeQuery(); + if (cursor.hasNext()) { + return cursor.next(); + } + } catch (DescriptorParsingException e) { + logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e); + } catch (StatementExecutionException e) { + logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e); + } + return null; + } }
--- a/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImplStatementDescriptorRegistration.java Fri Nov 28 13:48:29 2014 -0500 +++ b/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImplStatementDescriptorRegistration.java Fri Nov 28 15:47:39 2014 -0500 @@ -41,6 +41,7 @@ import com.redhat.thermostat.storage.core.PreparedParameter; import com.redhat.thermostat.storage.core.VmLatestPojoListGetter; +import com.redhat.thermostat.storage.core.VmTimeIntervalPojoListGetter; import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; import com.redhat.thermostat.vm.classstat.common.VmClassStatDAO; @@ -53,13 +54,18 @@ public class VmClassStatDAOImplStatementDescriptorRegistration implements StatementDescriptorRegistration { - static final String QUERY = String.format(VmLatestPojoListGetter.VM_LATEST_QUERY_FORMAT, + static final String LATEST = String.format(VmLatestPojoListGetter.VM_LATEST_QUERY_FORMAT, + VmClassStatDAO.vmClassStatsCategory.getName()); + static final String RANGE = String.format(VmTimeIntervalPojoListGetter.VM_INTERVAL_QUERY_FORMAT, VmClassStatDAO.vmClassStatsCategory.getName()); @Override public Set<String> getStatementDescriptors() { Set<String> descs = new HashSet<>(1); - descs.add(QUERY); + descs.add(LATEST); + descs.add(RANGE); + descs.add(VmClassStatDAOImpl.DESC_LATEST_VM_CLASS_STAT); + descs.add(VmClassStatDAOImpl.DESC_OLDEST_VM_CLASS_STAT); descs.add(VmClassStatDAOImpl.DESC_ADD_VM_CLASS_STAT); return descs; }
--- a/vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImplStatementDescriptorRegistrationTest.java Fri Nov 28 13:48:29 2014 -0500 +++ b/vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImplStatementDescriptorRegistrationTest.java Fri Nov 28 15:47:39 2014 -0500 @@ -58,10 +58,10 @@ public void registersAllDescriptors() { VmClassStatDAOImplStatementDescriptorRegistration reg = new VmClassStatDAOImplStatementDescriptorRegistration(); Set<String> descriptors = reg.getStatementDescriptors(); - assertEquals(2, descriptors.size()); + assertEquals(5, descriptors.size()); assertFalse("null descriptor not allowed", descriptors.contains(null)); } - + /* * The web storage end-point uses service loader in order to determine the * list of trusted/known registrations. This test is to ensure service loading @@ -86,8 +86,8 @@ // storage-core + this module assertEquals(2, registrations.size()); assertNotNull(vmClassStatReg); - assertEquals(2, vmClassStatReg.getStatementDescriptors().size()); + assertEquals(5, vmClassStatReg.getStatementDescriptors().size()); } - + }
--- a/vm-cpu/client-core/src/main/java/com/redhat/thermostat/vm/cpu/client/core/VmCpuView.java Fri Nov 28 13:48:29 2014 -0500 +++ b/vm-cpu/client-core/src/main/java/com/redhat/thermostat/vm/cpu/client/core/VmCpuView.java Fri Nov 28 15:47:39 2014 -0500 @@ -41,27 +41,13 @@ import com.redhat.thermostat.client.core.views.BasicView; import com.redhat.thermostat.client.core.views.UIComponent; +import com.redhat.thermostat.client.core.experimental.Duration; import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.model.Range; import com.redhat.thermostat.storage.model.DiscreteTimeData; public abstract class VmCpuView extends BasicView implements UIComponent { - public static class Duration { - public final int value; - public final TimeUnit unit; - - public Duration(int value, TimeUnit unit) { - this.value = value; - this.unit = unit; - } - - @Override - public String toString() { - return value + " " + unit; - } - } - public enum UserAction { USER_CHANGED_TIME_RANGE, }
--- a/vm-cpu/client-core/src/main/java/com/redhat/thermostat/vm/cpu/client/core/internal/TimeRangeComputer.java Fri Nov 28 13:48:29 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -/* - * Copyright 2012-2014 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.vm.cpu.client.core.internal; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import com.redhat.thermostat.common.model.Range; - -/** - * Compute additional data ranges to fetch when trying to update a currently - * displayed time-data with additional time-data. - */ -public class TimeRangeComputer { - - public static List<Range<Long>> computeAdditionalRangesToFetch(Range<Long> availableRange, Range<Long> desiredRange, Range<Long> displayedRange) { - - // TODO find out how to show 'sampled' values across a - // very, very large desiredRange - - // Do we need to show additional data? - if (displayedRange.equals(desiredRange)) { - return Collections.emptyList(); - } - - // Do we already have all the data? - if (contains(displayedRange, desiredRange)) { - // TODO 'narrow' view to the desired range - return Collections.emptyList(); - } - - // What's the best that we can do with the desired range? - Range<Long> closestInterval = closestInterval(availableRange, desiredRange); - - List<Range<Long>> results = new ArrayList<>(); - if (closestInterval.getMin() < displayedRange.getMin()) { - if (closestInterval.getMax() < displayedRange.getMin()) { - results.add(closestInterval); - } else if (closestInterval.getMax() < displayedRange.getMax()) { - results.add(new Range<>(closestInterval.getMin(), displayedRange.getMin())); - } else { - results.add(new Range<>(closestInterval.getMin(), displayedRange.getMin())); - results.add(new Range<>(displayedRange.getMax(), closestInterval.getMax())); - } - } else if (closestInterval.getMin() < displayedRange.getMax()) { - if (closestInterval.getMax() < displayedRange.getMax()) { - // nothing to do here - } else if (closestInterval.getMax() > displayedRange.getMax()) { - results.add(new Range<>(displayedRange.getMax(), closestInterval.getMax())); - } - } else { - results.add(closestInterval); - } - return results; - } - - private static boolean contains(Range<Long> larger, Range<Long> smaller) { - return (larger.getMin() <= smaller.getMin()) && (larger.getMax() >= smaller.getMax()); - } - - private static Range<Long> closestInterval(Range<Long> avilable, Range<Long> desired) { - long min = Math.max(avilable.getMin(), desired.getMin()); - long max = Math.min(avilable.getMax(), desired.getMax()); - return new Range<>(min, max); - } - -}
--- a/vm-cpu/client-core/src/main/java/com/redhat/thermostat/vm/cpu/client/core/internal/VmCpuController.java Fri Nov 28 13:48:29 2014 -0500 +++ b/vm-cpu/client-core/src/main/java/com/redhat/thermostat/vm/cpu/client/core/internal/VmCpuController.java Fri Nov 28 15:47:39 2014 -0500 @@ -37,13 +37,14 @@ package com.redhat.thermostat.vm.cpu.client.core.internal; import java.util.ArrayList; -import java.util.Date; import java.util.List; import java.util.concurrent.TimeUnit; import com.redhat.thermostat.client.core.controllers.InformationServiceController; import com.redhat.thermostat.client.core.views.BasicView.Action; import com.redhat.thermostat.client.core.views.UIComponent; +import com.redhat.thermostat.client.core.experimental.Duration; +import com.redhat.thermostat.client.core.experimental.TimeRangeController; import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.ApplicationService; @@ -54,9 +55,9 @@ import com.redhat.thermostat.shared.locale.LocalizedString; import com.redhat.thermostat.shared.locale.Translate; import com.redhat.thermostat.storage.core.VmRef; -import com.redhat.thermostat.storage.model.DiscreteTimeData; +import com.redhat.thermostat.client.core.experimental.SingleValueSupplier; +import com.redhat.thermostat.client.core.experimental.SingleValueStat; import com.redhat.thermostat.vm.cpu.client.core.VmCpuView; -import com.redhat.thermostat.vm.cpu.client.core.VmCpuView.Duration; import com.redhat.thermostat.vm.cpu.client.core.VmCpuViewProvider; import com.redhat.thermostat.vm.cpu.client.core.VmCpuView.UserAction; import com.redhat.thermostat.vm.cpu.client.locale.LocaleResources; @@ -73,10 +74,9 @@ private final Timer timer; - private Range<Long> availableRange = new Range<Long>(Long.MAX_VALUE, Long.MIN_VALUE); - private Range<Long> displayedRange = new Range<Long>(Long.MAX_VALUE, Long.MIN_VALUE); + private Duration userDesiredDuration; - private Duration userDesiredDuration; + private TimeRangeController timeRangeController; public VmCpuController(ApplicationService appSvc, VmCpuStatDAO vmCpuStatDao, VmRef ref, VmCpuViewProvider provider) { this.ref = ref; @@ -118,7 +118,7 @@ public void actionPerformed(ActionEvent<UserAction> actionEvent) { switch (actionEvent.getActionId()) { case USER_CHANGED_TIME_RANGE: - Duration duration = (Duration) view.getUserDesiredDuration(); + Duration duration = view.getUserDesiredDuration(); userDesiredDuration = duration; view.setVisibleDataRange(duration.value, duration.unit); break; @@ -129,6 +129,8 @@ }); userDesiredDuration = view.getUserDesiredDuration(); + + timeRangeController = new TimeRangeController(); } private void start() { @@ -136,54 +138,38 @@ } private void updateData() { - long now = System.currentTimeMillis(); - long userVisibleTimeDelta = (userDesiredDuration.unit.toMillis(userDesiredDuration.value)); - Range<Long> desiredRange = new Range<Long>(now - userVisibleTimeDelta, now); - VmCpuStat oldest = dao.getOldest(ref); VmCpuStat latest = dao.getLatest(ref); Range<Long> newAvailableRange = new Range<>(oldest.getTimeStamp(), latest.getTimeStamp()); - if (availableRange.equals(newAvailableRange)) { - return; - } - - availableRange = newAvailableRange; - - view.setAvailableDataRange(availableRange); - - List<Range<Long>> additionalIntervals = TimeRangeComputer.computeAdditionalRangesToFetch(availableRange, desiredRange, displayedRange); - - long displayedMin = Math.min(displayedRange.getMin(), Long.MAX_VALUE); - long displayedMax = Math.max(displayedRange.getMax(), Long.MIN_VALUE); - - for (Range<Long> interval : additionalIntervals) { - List<VmCpuStat> stats = dao.getVmCpuStats(ref, interval.getMin(), interval.getMax()); - appendToVmCpuCharts(stats); + SingleValueSupplier singleValueSupplier = new SingleValueSupplier() { + @Override + public List getStats(final VmRef ref, final long since, final long to) { + List<VmCpuStat> stats = dao.getVmCpuStats(ref, since, to); + List<SingleValueStat<Double>> singleValueStats = new ArrayList<>(); + for (final VmCpuStat stat : stats ) { + singleValueStats.add(new SingleValueStat<Double>() { + @Override + public Double getValue() { + return stat.getCpuLoad(); + } - displayedMin = Math.min(displayedMin, interval.getMin()); - displayedMax = Math.max(displayedMax, interval.getMax()); - } - - // the view does not show data older than the delta - displayedMin = Math.max(displayedMin, displayedMax - userVisibleTimeDelta); - - // System.out.println("Wanted to display " + new Date(desiredRange.getMin()) + " to " + new Date(desiredRange.getMax())); - displayedRange = new Range<>(displayedMin, displayedMax); - // System.out.println("Displayed from " + new Date(displayedRange.getMin()) + " to " + new Date(displayedRange.getMax())); + @Override + public long getTimeStamp() { + return stat.getTimeStamp(); + } + }); + } + return singleValueStats; + } + }; - } + timeRangeController.update(userDesiredDuration, newAvailableRange, singleValueSupplier, ref); + view.setAvailableDataRange(timeRangeController.getAvailableRange()); - private void appendToVmCpuCharts(List<VmCpuStat> stats) { - List<DiscreteTimeData<? extends Number>> toDisplay = new ArrayList<>(stats.size()); - for (VmCpuStat stat: stats) { - DiscreteTimeData<? extends Number> data = - new DiscreteTimeData<Number>(stat.getTimeStamp(), stat.getCpuLoad()); - toDisplay.add(data); - } - - view.addData(toDisplay); + List data = timeRangeController.getDataToDisplay(); + view.addData(data); } private void stop() {
--- a/vm-cpu/client-core/src/test/java/com/redhat/thermostat/vm/cpu/client/core/internal/TimeRangeComputerTest.java Fri Nov 28 13:48:29 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -/* - * Copyright 2012-2014 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.vm.cpu.client.core.internal; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.List; - -import org.junit.Test; - -import com.redhat.thermostat.common.model.Range; - -public class TimeRangeComputerTest { - - @Test - public void verifyComputesEmptyResultIfAllDataIsAvaialable() { - Range<Long> available = new Range<>(1l, 10l); - Range<Long> desired = new Range<>(2l, 3l); - Range<Long> displayed = new Range<>(1l, 10l); - - List<Range<Long>> result = TimeRangeComputer.computeAdditionalRangesToFetch(available, desired, displayed); - - assertTrue(result.isEmpty()); - } - - @Test - public void verifyComputesRangeBeforeCorrectly() { - Range<Long> available = new Range<>(1l, 10l); - Range<Long> desired = new Range<>(1l, 7l); - Range<Long> displayed = new Range<>(5l, 10l); - - List<Range<Long>> result = TimeRangeComputer.computeAdditionalRangesToFetch(available, desired, displayed); - - assertEquals(1, result.size()); - assertEquals(new Range<>(1l,5l), result.get(0)); - } - - @Test - public void verifyComputesRangeAfterCorrectly() { - Range<Long> available = new Range<>(1l, 10l); - Range<Long> desired = new Range<>(2l, 6l); - Range<Long> displayed = new Range<>(1l, 5l); - - List<Range<Long>> result = TimeRangeComputer.computeAdditionalRangesToFetch(available, desired, displayed); - - assertEquals(1, result.size()); - assertEquals(new Range<>(5l,6l), result.get(0)); - } - - @Test - public void verifyComputesOverlappingRangeCorrectly() { - Range<Long> available = new Range<>(1l, 10l); - Range<Long> desired = new Range<>(2l, 8l); - Range<Long> displayed = new Range<>(4l, 6l); - - List<Range<Long>> result = TimeRangeComputer.computeAdditionalRangesToFetch(available, desired, displayed); - - assertEquals(2, result.size()); - assertEquals(new Range<>(2l,4l), result.get(0)); - assertEquals(new Range<>(6l, 8l), result.get(1)); - } - -}
--- a/vm-cpu/client-core/src/test/java/com/redhat/thermostat/vm/cpu/client/core/internal/VmCpuControllerTest.java Fri Nov 28 13:48:29 2014 -0500 +++ b/vm-cpu/client-core/src/test/java/com/redhat/thermostat/vm/cpu/client/core/internal/VmCpuControllerTest.java Fri Nov 28 15:47:39 2014 -0500 @@ -49,6 +49,7 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; +import com.redhat.thermostat.client.core.experimental.Duration; import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.ApplicationService; @@ -56,7 +57,6 @@ import com.redhat.thermostat.common.TimerFactory; import com.redhat.thermostat.storage.core.VmRef; import com.redhat.thermostat.vm.cpu.client.core.VmCpuView; -import com.redhat.thermostat.vm.cpu.client.core.VmCpuView.Duration; import com.redhat.thermostat.vm.cpu.client.core.VmCpuViewProvider; import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; import com.redhat.thermostat.vm.cpu.common.model.VmCpuStat;
--- a/vm-cpu/client-swing/src/main/java/com/redhat/thermostat/vm/cpu/client/swing/internal/VmCpuChartPanel.java Fri Nov 28 13:48:29 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,243 +0,0 @@ -/* - * Copyright 2012-2014 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.vm.cpu.client.swing.internal; - -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.concurrent.TimeUnit; - -import javax.swing.DefaultComboBoxModel; -import javax.swing.JComboBox; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JTextField; -import javax.swing.SwingUtilities; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; -import javax.swing.text.BadLocationException; -import javax.swing.text.Document; -import javax.swing.text.JTextComponent; - -import org.jfree.chart.ChartPanel; -import org.jfree.chart.JFreeChart; -import org.jfree.chart.plot.XYPlot; - -import com.redhat.thermostat.client.locale.LocaleResources; -import com.redhat.thermostat.client.swing.components.ValueField; -import com.redhat.thermostat.shared.locale.Translate; -import com.redhat.thermostat.vm.cpu.client.core.VmCpuView; -import com.redhat.thermostat.vm.cpu.client.core.VmCpuView.Duration; - -public class VmCpuChartPanel extends JPanel { - - static final TimeUnit[] DEFAULT_TIMEUNITS = new TimeUnit[] { TimeUnit.DAYS, TimeUnit.HOURS, TimeUnit.MINUTES }; - - public static final String PROPERTY_VISIBLE_TIME_RANGE = "visibleTimeRange"; - - private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); - - private static final long serialVersionUID = -1733906800911900456L; - private static final int MINIMUM_DRAW_SIZE = 100; - - private ChartPanel chartPanel; - - private JPanel labelContainer; - private JTextComponent label; - - public VmCpuChartPanel(JFreeChart chart, Duration duration) { - - this.setLayout(new BorderLayout()); - - // instead of just disabling display of tooltips, disable their generation too - if (chart.getPlot() instanceof XYPlot) { - chart.getXYPlot().getRenderer().setBaseToolTipGenerator(null); - } - - chart.getXYPlot().getRangeAxis().setAutoRange(true); - - chart.getXYPlot().getDomainAxis().setAutoRange(true); - chart.getXYPlot().getDomainAxis().setFixedAutoRange(duration.unit.toMillis(duration.value)); - - chartPanel = new ChartPanel(chart); - - chartPanel.setDisplayToolTips(false); - chartPanel.setDoubleBuffered(true); - chartPanel.setMouseZoomable(false); - chartPanel.setPopupMenu(null); - - /* - * By default, ChartPanel scales itself instead of redrawing things when - * it's resized. To have it resize automatically, we need to set minimum - * and maximum sizes. Lets constrain the minimum, but not the maximum - * size. - */ - chartPanel.setMinimumDrawHeight(MINIMUM_DRAW_SIZE); - chartPanel.setMaximumDrawHeight(Integer.MAX_VALUE); - chartPanel.setMinimumDrawWidth(MINIMUM_DRAW_SIZE); - chartPanel.setMaximumDrawWidth(Integer.MAX_VALUE); - - add(chartPanel, BorderLayout.CENTER); - add(getControlsAndAdditionalDisplay(duration), BorderLayout.SOUTH); - - } - - private Component getControlsAndAdditionalDisplay(Duration duration) { - JPanel container = new JPanel(); - container.setOpaque(false); - - container.setLayout(new BorderLayout()); - - container.add(getChartControls(duration), BorderLayout.LINE_START); - container.add(getAdditionalDataDisplay(), BorderLayout.LINE_END); - - return container; - } - - private Component getChartControls(Duration duration) { - JPanel container = new JPanel(); - container.setOpaque(false); - - final JTextField durationSelector = new JTextField(5); - final JComboBox<TimeUnit> unitSelector = new JComboBox<>(); - unitSelector.setModel(new DefaultComboBoxModel<>(DEFAULT_TIMEUNITS)); - - TimeUnitChangeListener timeUnitChangeListener = new TimeUnitChangeListener(duration.value, duration.unit); - - durationSelector.getDocument().addDocumentListener(timeUnitChangeListener); - unitSelector.addActionListener(timeUnitChangeListener); - - durationSelector.setText(String.valueOf(duration.value)); - unitSelector.setSelectedItem(duration.unit); - - container.add(new JLabel(translator.localize(LocaleResources.CHART_DURATION_SELECTOR_LABEL).getContents())); - container.add(durationSelector); - container.add(unitSelector); - - return container; - } - - private Component getAdditionalDataDisplay() { - JPanel panel = new JPanel(new GridBagLayout()); - panel.setOpaque(false); - labelContainer = new JPanel(); - labelContainer.setOpaque(false); - GridBagConstraints constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.BOTH; - constraints.anchor = GridBagConstraints.CENTER; - panel.add(labelContainer, constraints); - return panel; - } - - public void setTimeRangeToShow(int timeValue, TimeUnit timeUnit) { - XYPlot plot = chartPanel.getChart().getXYPlot(); - - // Don't drop old data; just dont' show it. - plot.getDomainAxis().setAutoRange(true); - plot.getDomainAxis().setFixedAutoRange(timeUnit.toMillis(timeValue)); - } - - public void setDataInformationLabel(final String text) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - if (label == null) { - label = new ValueField(text); - labelContainer.add(label); - } - - label.setText(text); - } - }); - } - - private class TimeUnitChangeListener implements DocumentListener, ActionListener { - - private int value; - private TimeUnit unit; - - public TimeUnitChangeListener(int defaultValue, TimeUnit defaultUnit) { - this.value = defaultValue; - this.unit = defaultUnit; - } - - @Override - public void removeUpdate(DocumentEvent event) { - changed(event.getDocument()); - } - - @Override - public void insertUpdate(DocumentEvent event) { - changed(event.getDocument()); - } - - @Override - public void changedUpdate(DocumentEvent event) { - changed(event.getDocument()); - } - - private void changed(Document doc) { - try { - this.value = Integer.valueOf(doc.getText(0, doc.getLength())); - } catch (NumberFormatException nfe) { - // ignore - } catch (BadLocationException ble) { - // ignore - } - chartChanged(); - } - - private void chartChanged() { - VmCpuChartPanel.this.firePropertyChange(PROPERTY_VISIBLE_TIME_RANGE, null, new VmCpuView.Duration(value, unit)); - } - - @Override - public void actionPerformed(ActionEvent e) { - @SuppressWarnings("unchecked") // We are a TimeUnitChangeListener, specifically. - JComboBox<TimeUnit> comboBox = (JComboBox<TimeUnit>) e.getSource(); - TimeUnit time = (TimeUnit) comboBox.getSelectedItem(); - this.unit = time; - chartChanged(); - } - } - - -} -
--- a/vm-cpu/client-swing/src/main/java/com/redhat/thermostat/vm/cpu/client/swing/internal/VmCpuPanel.java Fri Nov 28 13:48:29 2014 -0500 +++ b/vm-cpu/client-swing/src/main/java/com/redhat/thermostat/vm/cpu/client/swing/internal/VmCpuPanel.java Fri Nov 28 15:47:39 2014 -0500 @@ -45,6 +45,8 @@ import javax.swing.SwingUtilities; +import com.redhat.thermostat.client.core.experimental.Duration; +import com.redhat.thermostat.client.swing.components.experimental.SingleValueChartPanel; import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; import org.jfree.data.time.FixedMillisecond; @@ -77,7 +79,7 @@ private final TimeSeriesCollection data = new TimeSeriesCollection(); private final TimeSeries cpuTimeSeries = new TimeSeries("cpu-stats"); - private VmCpuChartPanel chartPanel; + private SingleValueChartPanel chartPanel; private ActionNotifier<UserAction> userActionNotifier = new ActionNotifier<VmCpuView.UserAction>(this); @@ -110,11 +112,11 @@ chart.getXYPlot().getRangeAxis().setLowerBound(0.0); - chartPanel = new VmCpuChartPanel(chart, duration); + chartPanel = new SingleValueChartPanel(chart, duration); visiblePanel.setContent(chartPanel); - chartPanel.addPropertyChangeListener(VmCpuChartPanel.PROPERTY_VISIBLE_TIME_RANGE, new PropertyChangeListener() { + chartPanel.addPropertyChangeListener(SingleValueChartPanel.PROPERTY_VISIBLE_TIME_RANGE, new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { duration = (Duration) evt.getNewValue();
--- a/vm-cpu/common/pom.xml Fri Nov 28 13:48:29 2014 -0500 +++ b/vm-cpu/common/pom.xml Fri Nov 28 15:47:39 2014 -0500 @@ -130,5 +130,10 @@ <version>${project.version}</version> <scope>test</scope> </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-client-core</artifactId> + <version>${project.version}</version> + </dependency> </dependencies> </project>
--- a/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImpl.java Fri Nov 28 13:48:29 2014 -0500 +++ b/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImpl.java Fri Nov 28 15:47:39 2014 -0500 @@ -36,7 +36,6 @@ package com.redhat.thermostat.vm.cpu.common.internal; -import java.util.Date; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger;
--- a/vm-cpu/distribution/thermostat-plugin.xml Fri Nov 28 13:48:29 2014 -0500 +++ b/vm-cpu/distribution/thermostat-plugin.xml Fri Nov 28 15:47:39 2014 -0500 @@ -53,6 +53,7 @@ <bundles> <bundle><symbolic-name>com.redhat.thermostat.vm.cpu.common</symbolic-name><version>${project.version}</version></bundle> <bundle><symbolic-name>com.redhat.thermostat.vm.cpu.agent</symbolic-name><version>${project.version}</version></bundle> + <bundle><symbolic-name>com.redhat.thermostat.client.core</symbolic-name><version>${project.version}</version></bundle> </bundles> </extension> <extension>