Mercurial > hg > release > thermostat-0.5
changeset 627:7252a5f21644
Timeline view (part I)
review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-September/003272.html
reviewed-by: rkennke
line wrap: on
line diff
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/ChartPanel.java Tue Sep 18 17:38:29 2012 -0400 +++ b/client/swing-components/src/main/java/com/redhat/thermostat/swing/ChartPanel.java Wed Sep 19 10:08:17 2012 +0200 @@ -51,7 +51,7 @@ private ChartRenderingInfo info; public ChartPanel(JFreeChart chart) { - this.chart = chart; + this(chart, new ChartRenderingInfo()); } public ChartPanel(JFreeChart chart, ChartRenderingInfo info) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/swing-components/src/main/java/com/redhat/thermostat/swing/GradientRoundBorder.java Wed Sep 19 10:08:17 2012 +0200 @@ -0,0 +1,74 @@ +/* + * 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.swing; + +import java.awt.Color; +import java.awt.Component; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.Shape; +import java.io.Serializable; + +import javax.swing.UIManager; +import javax.swing.border.AbstractBorder; +import javax.swing.plaf.UIResource; + +@SuppressWarnings("serial") +public class GradientRoundBorder extends AbstractBorder implements UIResource, Serializable { + + @Override + public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { + GraphicsUtils utils = GraphicsUtils.getInstance(); + Graphics2D graphics = utils.createAAGraphics(g); + + Color highlight = UIManager.getColor("textHighlight"); + if (highlight == null) { + highlight = Palette.EGYPTIAN_BLUE.getColor(); + } + Paint paint = new GradientPaint(x, y, highlight, 0, height, c.getBackground()); + graphics.setPaint(paint); + + graphics.translate(x, y); + + Shape shape = utils.getRoundShape(width, height); + graphics.draw(shape); + + graphics.dispose(); + } +}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/GraphicsUtils.java Tue Sep 18 17:38:29 2012 -0400 +++ b/client/swing-components/src/main/java/com/redhat/thermostat/swing/GraphicsUtils.java Wed Sep 19 10:08:17 2012 +0200 @@ -85,7 +85,7 @@ } public Shape getRoundShape(int width, int height) { - return new RoundRectangle2D.Double(0, 0, width - 2, height - 1, 4, 4); + return new RoundRectangle2D.Double(0, 0, width, height, 4, 4); } public void setGradientPaint(Graphics2D g, int x, int height, Color start, Color stop) {
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/HeaderPanel.java Tue Sep 18 17:38:29 2012 -0400 +++ b/client/swing-components/src/main/java/com/redhat/thermostat/swing/HeaderPanel.java Wed Sep 19 10:08:17 2012 +0200 @@ -43,8 +43,6 @@ import java.lang.reflect.InvocationTargetException; import javax.swing.BoxLayout; -import javax.swing.ImageIcon; -import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/swing-components/src/main/java/com/redhat/thermostat/swing/models/LongRange.java Wed Sep 19 10:08:17 2012 +0200 @@ -0,0 +1,60 @@ +/* + * 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.swing.models; + +public class LongRange { + + long min; + long max; + + public void setMax(long max) { + this.max = max; + } + + public long getMax() { + return max; + } + + public void setMin(long min) { + this.min = min; + } + + + public long getMin() { + return min; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/swing-components/src/main/java/com/redhat/thermostat/swing/models/LongRangeNormalizer.java Wed Sep 19 10:08:17 2012 +0200 @@ -0,0 +1,81 @@ +/* + * 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.swing.models; + +public class LongRangeNormalizer { + + private long minNormalized; + + private long maxNormalized; + + private long value; + + private LongRange range; + + public LongRangeNormalizer(LongRange range) { + this.range = range; + } + + public void setMaxNormalized(long maxNormalized) { + this.maxNormalized = maxNormalized; + } + + public void setMinNormalized(long minNormalized) { + this.minNormalized = minNormalized; + } + + public long getValue() { + return value; + } + + public void setValue(long newValue) { + this.value = newValue; + } + + public long getMaxNormalized() { + return maxNormalized; + } + + public long getMinNormalized() { + return minNormalized; + } + + public long getValueNormalized() { + double normalized = ((value - range.min) * (double)(maxNormalized - minNormalized)/(range.max - range.min)) + minNormalized; + return Math.round(normalized); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/swing-components/src/test/java/com/redhat/thermostat/swing/models/LongRangeNormalizerTest.java Wed Sep 19 10:08:17 2012 +0200 @@ -0,0 +1,120 @@ +/* + * 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.swing.models; + +import static org.junit.Assert.*; +import junit.framework.Assert; + +import org.junit.Test; + +public class LongRangeNormalizerTest { + + @Test + public void testSameRange() { + + LongRange range = new LongRange(); + range.setMax(10); + range.setMin(0); + + LongRangeNormalizer model = new LongRangeNormalizer(range); + + model.setValue(5); + + model.setMaxNormalized(10); + model.setMinNormalized(0); + + + Assert.assertEquals((int) model.getValue(), model.getValueNormalized()); + } + + @Test + public void testDoubleRange() { + + LongRange range = new LongRange(); + range.setMax(10); + range.setMin(0); + + LongRangeNormalizer model = new LongRangeNormalizer(range); + + model.setValue(5); + + model.setMaxNormalized(20); + model.setMinNormalized(0); + + + Assert.assertEquals(10, model.getValueNormalized()); + } + + @Test + public void testRanges() { + + LongRange range = new LongRange(); + range.setMax(10); + range.setMin(0); + + LongRangeNormalizer model = new LongRangeNormalizer(range); + + model.setValue(5); + + model.setMaxNormalized(40); + model.setMinNormalized(0); + + Assert.assertEquals(20, model.getValueNormalized()); + + model.setMaxNormalized(60); + model.setMinNormalized(0); + + Assert.assertEquals(30, model.getValueNormalized()); + + model.setMaxNormalized(200); + model.setMinNormalized(100); + + Assert.assertEquals(150, model.getValueNormalized()); + + range.setMax(100); + range.setMin(0); + model.setValue(50); + + model.setMaxNormalized(1); + model.setMinNormalized(0); + + Assert.assertEquals(1, model.getValueNormalized()); + + model.setValue(49); + Assert.assertEquals(0, model.getValueNormalized()); + } +}
--- a/distribution/config/osgi-export.properties Tue Sep 18 17:38:29 2012 -0400 +++ b/distribution/config/osgi-export.properties Wed Sep 19 10:08:17 2012 +0200 @@ -50,6 +50,7 @@ org.jfree.data.time org.jfree.data.xy org.jfree.ui +org.jfree.data.gantt sun.swing sun.swing.table
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/ThreadTimelineBean.java Wed Sep 19 10:08:17 2012 +0200 @@ -0,0 +1,86 @@ +/* + * 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.thread.client.common; + +import java.util.Date; + +public class ThreadTimelineBean { + + private long startTime; + private long stopTime; + private String name; + private Thread.State state; + + public Thread.State getState() { + return state; + } + + public void setState(Thread.State state) { + this.state = state; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public long getStartTime() { + return startTime; + } + + public void setStartTime(long startTime) { + this.startTime = startTime; + } + + public long getStopTime() { + return stopTime; + } + + public void setStopTime(long stopTime) { + this.stopTime = stopTime; + } + + @Override + public String toString() { + return "ThreadTimelineBean [name=" + name + ", state=" + state + + ", startTime=" + startTime + " (" + new Date(startTime) + ")" + + ", stopTime=" + stopTime + " (" + new Date(stopTime) + ")]"; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/ThreadTimelineView.java Wed Sep 19 10:08:17 2012 +0200 @@ -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.thread.client.common; + +import java.util.List; +import java.util.Map; + +import com.redhat.thermostat.client.osgi.service.BasicView; +import com.redhat.thermostat.thread.model.ThreadInfoData; + +public abstract class ThreadTimelineView extends BasicView { + + public abstract void displayStats(Map<ThreadInfoData, List<ThreadTimelineBean>> timelines, long start, long stop); + +}
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/ThreadView.java Tue Sep 18 17:38:29 2012 -0400 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/ThreadView.java Wed Sep 19 10:08:17 2012 +0200 @@ -74,6 +74,7 @@ public abstract VMThreadCapabilitiesView createVMThreadCapabilitiesView(); public abstract ThreadTableView createThreadTableView(); + public abstract ThreadTimelineView createThreadTimelineView(); public abstract void displayWarning(String warning);
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/locale/LocaleResources.java Tue Sep 18 17:38:29 2012 -0400 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/locale/LocaleResources.java Wed Sep 19 10:08:17 2012 +0200 @@ -57,6 +57,7 @@ VM_CAPABILITIES, TABLE, DETAILS, + TIMELINE, LIVE_THREADS, DAEMON_THREADS,
--- a/thread/client-common/src/main/resources/com/redhat/thermostat/thread/client/common/locale/strings.properties Tue Sep 18 17:38:29 2012 -0400 +++ b/thread/client-common/src/main/resources/com/redhat/thermostat/thread/client/common/locale/strings.properties Wed Sep 19 10:08:17 2012 +0200 @@ -16,6 +16,7 @@ VM_CAPABILITIES = VM Capabilities TABLE = Table DETAILS = Details +TIMELINE = Timeline LIVE_THREADS = Live Threads DAEMON_THREADS = Daemon Threads
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/CommonController.java Tue Sep 18 17:38:29 2012 -0400 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/CommonController.java Wed Sep 19 10:08:17 2012 +0200 @@ -36,6 +36,47 @@ package com.redhat.thermostat.thread.client.controller.impl; -public interface CommonController { - void initialize(); +import java.util.concurrent.TimeUnit; + +import com.redhat.thermostat.client.osgi.service.BasicView; +import com.redhat.thermostat.client.osgi.service.BasicView.Action; +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.common.Timer.SchedulingType; + +public abstract class CommonController { + + protected Timer timer; + protected BasicView view; + + public CommonController(Timer timer, BasicView view) { + this.view = view; + this.timer = timer; + } + + void initialize() { + timer.setInitialDelay(0); + timer.setDelay(1000); + timer.setTimeUnit(TimeUnit.MILLISECONDS); + timer.setSchedulingType(SchedulingType.FIXED_RATE); + + view.addActionListener(new ActionListener<Action>() { + @Override + public void actionPerformed(ActionEvent<Action> actionEvent) { + switch (actionEvent.getActionId()) { + case VISIBLE: + timer.start(); + break; + + case HIDDEN: + timer.stop(); + break; + + default: + break; + } + } + }); + } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInfoHelper.java Wed Sep 19 10:08:17 2012 +0200 @@ -0,0 +1,74 @@ +/* + * 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.thread.client.controller.impl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.redhat.thermostat.thread.model.ThreadInfoData; + +public class ThreadInfoHelper { + + /** + * Creates a {@link Map} whose keys are {@link ThreadInfoData} in the input + * list and whose values are all the {@link ThreadInfoData} equals to the + * key. + * + * <br /><br /> + * + * Preserves the order of the input list. + * + * <br /><br /> + * + * <strong>NOTE</strong>: The current invariant is that + * {@link ThreadInfoData} are equals if they have same thread id and name. + */ + public static Map<ThreadInfoData, List<ThreadInfoData>> getThreadInfoDataMap(List<ThreadInfoData> infos) { + Map<ThreadInfoData, List<ThreadInfoData>> stats = new HashMap<>(); + for (ThreadInfoData info : infos) { + List<ThreadInfoData> beanList = stats.get(info); + if (beanList == null) { + beanList = new ArrayList<ThreadInfoData>(); + stats.put(info, beanList); + } + beanList.add(info); + } + return stats; + } +}
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInformationController.java Tue Sep 18 17:38:29 2012 -0400 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInformationController.java Wed Sep 19 10:08:17 2012 +0200 @@ -197,7 +197,8 @@ } private void initControllers() { - CommonController capsController = + + VMThreadCapabilitiesController capsController = new VMThreadCapabilitiesController(view.createVMThreadCapabilitiesView(), collector); capsController.initialize(); @@ -207,5 +208,10 @@ new ThreadTableController(threadTableView, collector, ApplicationContext.getInstance().getTimerFactory().createTimer()); threadTableController.initialize(); + + CommonController threadTimeline = + new ThreadTimelineController(view.createThreadTimelineView(), collector, + ApplicationContext.getInstance().getTimerFactory().createTimer()); + threadTimeline.initialize(); } }
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadTableController.java Tue Sep 18 17:38:29 2012 -0400 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadTableController.java Wed Sep 19 10:08:17 2012 +0200 @@ -41,60 +41,29 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.TimeUnit; -import com.redhat.thermostat.client.osgi.service.BasicView.Action; -import com.redhat.thermostat.common.ActionEvent; -import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.Timer; -import com.redhat.thermostat.common.Timer.SchedulingType; import com.redhat.thermostat.thread.client.common.ThreadTableBean; import com.redhat.thermostat.thread.client.common.ThreadTableView; import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; import com.redhat.thermostat.thread.model.ThreadInfoData; -public class ThreadTableController implements CommonController { +public class ThreadTableController extends CommonController { private ThreadTableView threadTableView; private ThreadCollector collector; - private Timer timer; public ThreadTableController(ThreadTableView threadTableView, ThreadCollector collector, Timer timer) { + super(timer, threadTableView); + timer.setAction(new ThreadTableControllerAction()); + this.collector = collector; this.threadTableView = threadTableView; - this.timer = timer; } - @Override - public void initialize() { - - timer.setInitialDelay(0); - timer.setDelay(1000); - timer.setTimeUnit(TimeUnit.MILLISECONDS); - timer.setSchedulingType(SchedulingType.FIXED_RATE); - timer.setAction(new ThreadTableControllerAction()); - - threadTableView.addActionListener(new ActionListener<Action>() { - @Override - public void actionPerformed(ActionEvent<Action> actionEvent) { - switch (actionEvent.getActionId()) { - case VISIBLE: - timer.start(); - break; - - case HIDDEN: - timer.stop(); - break; - - default: - break; - } - } - }); - } private class ThreadTableControllerAction implements Runnable { @Override @@ -110,15 +79,8 @@ // first, get a map of all threads with the respective info // the list will contain an ordered-by-timestamp list // with the known history for each thread - Map<ThreadInfoData, List<ThreadInfoData>> stats = new HashMap<>(); - for (ThreadInfoData info : infos) { - List<ThreadInfoData> beanList = stats.get(info); - if (beanList == null) { - beanList = new ArrayList<ThreadInfoData>(); - stats.put(info, beanList); - } - beanList.add(info); - } + Map<ThreadInfoData, List<ThreadInfoData>> stats = + ThreadInfoHelper.getThreadInfoDataMap(infos); List<ThreadTableBean> tableBeans = new ArrayList<>();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadTimelineController.java Wed Sep 19 10:08:17 2012 +0200 @@ -0,0 +1,124 @@ +/* + * 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.thread.client.controller.impl; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.thread.client.common.ThreadTimelineBean; +import com.redhat.thermostat.thread.client.common.ThreadTimelineView; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.model.ThreadInfoData; + +public class ThreadTimelineController extends CommonController { + + private ThreadTimelineView view; + private ThreadCollector collector; + + public ThreadTimelineController(ThreadTimelineView view, ThreadCollector collector, Timer timer) { + super(timer, view); + timer.setAction(new ThreadTimelineControllerAction()); + this.view = view; + this.collector = collector; + } + + private class ThreadTimelineControllerAction implements Runnable { + @Override + public void run() { + List<ThreadInfoData> infos = collector.getThreadInfo(); + if(infos.size() > 0) { + + Map<ThreadInfoData, List<ThreadTimelineBean>> timelines = new HashMap<>(); + + Map<ThreadInfoData, List<ThreadInfoData>> stats = + ThreadInfoHelper.getThreadInfoDataMap(infos); + for (List<ThreadInfoData> beanList : stats.values()) { + + // the list is ordered in most recent first + // the first element is the latest sample we have of this + // thread, so we use it as stop time. + + ThreadInfoData lastThreadInfo = beanList.get(beanList.size() - 1); + Thread.State lastState = lastThreadInfo.getState(); + + ThreadTimelineBean timeline = new ThreadTimelineBean(); + timeline.setName(lastThreadInfo.getThreadName()); + timeline.setState(lastThreadInfo.getState()); + timeline.setStartTime(lastThreadInfo.getTimeStamp()); + + long stopTime = beanList.get(0).getTimeStamp(); + timeline.setStopTime(stopTime); + + Stack<ThreadTimelineBean> threadTimelines = new Stack<ThreadTimelineBean>(); + timelines.put(lastThreadInfo, threadTimelines); + threadTimelines.push(timeline); + + for (int i = beanList.size() - 1; i >= 0; i--) { + ThreadInfoData threadInfo = beanList.get(i); + + Thread.State currentState = threadInfo.getState(); + if (currentState != lastState) { + lastState = currentState; + + timeline = threadTimelines.pop(); + timeline.setStopTime(threadInfo.getTimeStamp()); + + threadTimelines.push(timeline); + + timeline = new ThreadTimelineBean(); + timeline.setName(threadInfo.getThreadName()); + timeline.setState(threadInfo.getState()); + timeline.setStartTime(threadInfo.getTimeStamp()); + timeline.setStopTime(stopTime); + + lastThreadInfo = threadInfo; + lastState = currentState; + + // add the new thread stat + threadTimelines.push(timeline); + } + } + } + + view.displayStats(timelines, infos.get(infos.size() - 1).getTimeStamp(), infos.get(0).getTimeStamp()); + } + } + } +}
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/VMThreadCapabilitiesController.java Tue Sep 18 17:38:29 2012 -0400 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/VMThreadCapabilitiesController.java Wed Sep 19 10:08:17 2012 +0200 @@ -43,7 +43,7 @@ import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; import com.redhat.thermostat.thread.model.VMThreadCapabilities; -public class VMThreadCapabilitiesController implements CommonController { +public class VMThreadCapabilitiesController { private ThreadCollector collector; private VMThreadCapabilitiesView view; @@ -53,7 +53,6 @@ this.collector = collector; } - @Override public void initialize() { view.addActionListener(new ActionListener<Action>() { @Override
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInfoHelperTest.java Wed Sep 19 10:08:17 2012 +0200 @@ -0,0 +1,94 @@ +/* + * 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.thread.client.controller.impl; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.junit.Test; + +import com.redhat.thermostat.thread.model.ThreadInfoData; + +public class ThreadInfoHelperTest { + + @Test + public void verifyMap() { + ThreadInfoData data1 = new ThreadInfoData(); + data1.setThreadName("test1"); + data1.setThreadId(1); + data1.setState(Thread.State.RUNNABLE); + + ThreadInfoData data2 = new ThreadInfoData(); + data2.setThreadName("test2"); + data2.setThreadId(2); + data2.setState(Thread.State.BLOCKED); + + ThreadInfoData data3 = new ThreadInfoData(); + data3.setThreadName("test1"); + data3.setThreadId(1); + data3.setState(Thread.State.TIMED_WAITING); + + ThreadInfoData data4 = new ThreadInfoData(); + data4.setThreadName("test2"); + data4.setThreadId(2); + data4.setState(Thread.State.RUNNABLE); + + List<ThreadInfoData> infos = new ArrayList<>(); + infos.add(data1); + infos.add(data2); + infos.add(data3); + infos.add(data4); + + Map<ThreadInfoData, List<ThreadInfoData>> result = ThreadInfoHelper.getThreadInfoDataMap(infos); + assertEquals(2, result.size()); + + assertTrue(result.containsKey(data1)); + assertTrue(result.containsKey(data2)); + + assertEquals(2, result.get(data1).size()); + assertEquals(2, result.get(data2).size()); + + assertEquals(Thread.State.RUNNABLE, result.get(data1).get(0).getState()); + assertEquals(Thread.State.TIMED_WAITING, result.get(data1).get(1).getState()); + + assertEquals(Thread.State.BLOCKED, result.get(data2).get(0).getState()); + assertEquals(Thread.State.RUNNABLE, result.get(data2).get(1).getState()); + } +}
--- a/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInformationControllerTest.java Tue Sep 18 17:38:29 2012 -0400 +++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInformationControllerTest.java Wed Sep 19 10:08:17 2012 +0200 @@ -60,6 +60,7 @@ import com.redhat.thermostat.thread.client.common.ThreadTableBean; import com.redhat.thermostat.thread.client.common.ThreadTableView; import com.redhat.thermostat.thread.client.common.ThreadTableView.ThreadSelectionAction; +import com.redhat.thermostat.thread.client.common.ThreadTimelineView; import com.redhat.thermostat.thread.client.common.ThreadView; import com.redhat.thermostat.thread.client.common.ThreadViewProvider; import com.redhat.thermostat.thread.client.common.VMThreadCapabilitiesView; @@ -80,6 +81,7 @@ private ThreadTableView threadTableView; private VMThreadCapabilitiesView threadCapsView; + private ThreadTimelineView threadTimelineView; @Before public void setUp() { @@ -96,13 +98,15 @@ private void setUpView() { threadCapsView = mock(VMThreadCapabilitiesView.class); threadTableView = mock(ThreadTableView.class); - + threadTimelineView = mock(ThreadTimelineView.class); + view = mock(ThreadView.class); viewFactory = mock(ThreadViewProvider.class); when(viewFactory.createView()).thenReturn(view); when(view.createVMThreadCapabilitiesView()).thenReturn(threadCapsView); when(view.createThreadTableView()).thenReturn(threadTableView); + when(view.createThreadTimelineView()).thenReturn(threadTimelineView); } private void setUpTimers() { @@ -152,6 +156,7 @@ verify(view).createThreadTableView(); verify(view).createVMThreadCapabilitiesView(); + verify(view).createThreadTimelineView(); } @Test
--- a/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadTableControllerTest.java Tue Sep 18 17:38:29 2012 -0400 +++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadTableControllerTest.java Wed Sep 19 10:08:17 2012 +0200 @@ -68,7 +68,7 @@ collector = mock(ThreadCollector.class); timer = mock(Timer.class); - + view = mock(ThreadTableView.class); setUpTimers();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadTimelineControllerTest.java Wed Sep 19 10:08:17 2012 +0200 @@ -0,0 +1,192 @@ +/* + * 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.thread.client.controller.impl; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyLong; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import com.redhat.thermostat.client.osgi.service.BasicView; +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.common.appctx.ApplicationContextUtil; +import com.redhat.thermostat.thread.client.common.ThreadTableView; +import com.redhat.thermostat.thread.client.common.ThreadTimelineBean; +import com.redhat.thermostat.thread.client.common.ThreadTimelineView; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.model.ThreadInfoData; + +public class ThreadTimelineControllerTest { + + private ThreadTimelineView view; + private ThreadCollector collector; + + private Timer timer; + + private ActionListener<ThreadTableView.Action> actionListener; + ArgumentCaptor<Runnable> timerActionCaptor; + + @Before + public void setUp() { + ApplicationContextUtil.resetApplicationContext(); + collector = mock(ThreadCollector.class); + + timer = mock(Timer.class); + + view = mock(ThreadTimelineView.class); + + setUpTimers(); + } + + private void setUpTimers() { + timer = mock(Timer.class); + timerActionCaptor = ArgumentCaptor.forClass(Runnable.class); + doNothing().when(timer).setAction(timerActionCaptor.capture()); + } + + @Test + public void testDisplayStats() { + + ThreadInfoData data1 = new ThreadInfoData(); + data1.setThreadName("test1"); + data1.setThreadId(1); + data1.setState(Thread.State.RUNNABLE); + data1.setTimeStamp(100); + + ThreadInfoData data2 = new ThreadInfoData(); + data2.setThreadName("test2"); + data2.setThreadId(2); + data2.setTimeStamp(1000); + data2.setState(Thread.State.BLOCKED); + + ThreadInfoData data3 = new ThreadInfoData(); + data3.setThreadName("test1"); + data3.setThreadId(1); + data3.setState(Thread.State.TIMED_WAITING); + data3.setTimeStamp(200); + + ThreadInfoData data4 = new ThreadInfoData(); + data4.setThreadName("test2"); + data4.setThreadId(2); + data4.setState(Thread.State.BLOCKED); + data4.setTimeStamp(2000); + + ThreadInfoData data5 = new ThreadInfoData(); + data5.setThreadName("test2"); + data5.setThreadId(2); + data5.setState(Thread.State.RUNNABLE); + data5.setTimeStamp(3000); + + List<ThreadInfoData> infos = new ArrayList<>(); + // descending order + infos.add(data5); + infos.add(data4); + infos.add(data2); + infos.add(data3); + infos.add(data1); + + when(collector.getThreadInfo()).thenReturn(infos); + + ArgumentCaptor<Runnable> timerCaptor = ArgumentCaptor.forClass(Runnable.class); + doNothing().when(timer).setAction(timerCaptor.capture()); + + ThreadTimelineController controller = new ThreadTimelineController(view, collector, timer); + controller.initialize(); + + Runnable action = timerCaptor.getValue(); + action.run(); + + ArgumentCaptor<Map> mapCaptor = ArgumentCaptor.forClass(Map.class); + + verify(view).displayStats(mapCaptor.capture(), anyLong(), anyLong()); + + Map viewResult = mapCaptor.getValue(); + assertEquals(2, viewResult.size()); + + List<ThreadTimelineBean> beanList = (List<ThreadTimelineBean>) viewResult.get(data1); + + assertEquals(2, beanList.size()); + + assertEquals("test1", beanList.get(0).getName()); + assertEquals("test1", beanList.get(1).getName()); + + beanList = (List<ThreadTimelineBean>) viewResult.get(data2); + assertEquals(2, beanList.size()); + + assertEquals("test2", beanList.get(0).getName()); + assertEquals("test2", beanList.get(1).getName()); + + assertEquals(1000, beanList.get(0).getStartTime()); + assertEquals(3000, beanList.get(0).getStopTime()); + assertEquals(Thread.State.BLOCKED, beanList.get(0).getState()); + + assertEquals(3000, beanList.get(1).getStartTime()); + assertEquals(Thread.State.BLOCKED, beanList.get(0).getState()); + } + + @Test + public void testStartThreadTimelineController() { + + ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class); + doNothing().when(view).addActionListener(viewArgumentCaptor.capture()); + + ThreadTimelineController controller = new ThreadTimelineController(view, collector, timer); + controller.initialize(); + + actionListener = viewArgumentCaptor.getValue(); + actionListener.actionPerformed(new ActionEvent<>(view, BasicView.Action.VISIBLE)); + + verify(timer).start(); + + actionListener.actionPerformed(new ActionEvent<>(view, BasicView.Action.HIDDEN)); + + verify(timer).stop(); + } +}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadDetailsView.java Tue Sep 18 17:38:29 2012 -0400 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadDetailsView.java Wed Sep 19 10:08:17 2012 +0200 @@ -36,8 +36,11 @@ package com.redhat.thermostat.thread.client.swing.impl; +import java.awt.BorderLayout; import java.awt.Component; +import javax.swing.ImageIcon; +import javax.swing.JLabel; import javax.swing.JPanel; import com.redhat.thermostat.client.ui.SwingComponent; @@ -48,15 +51,6 @@ import com.redhat.thermostat.thread.client.common.chart.ThreadDeatailsPieChart; import com.redhat.thermostat.thread.client.common.locale.LocaleResources; -import javax.swing.GroupLayout; -import javax.swing.GroupLayout.Alignment; -import javax.swing.ImageIcon; -import javax.swing.JLabel; -import java.awt.GridBagLayout; -import java.awt.GridBagConstraints; -import java.awt.BorderLayout; -import java.awt.GridLayout; - public class SwingThreadDetailsView extends ThreadDetailsView implements SwingComponent { private JPanel details;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadTimelineChart.java Wed Sep 19 10:08:17 2012 +0200 @@ -0,0 +1,197 @@ +/* + * 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.thread.client.swing.impl; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.Shape; +import java.awt.geom.Area; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +import com.redhat.thermostat.swing.GradientRoundBorder; +import com.redhat.thermostat.swing.GraphicsUtils; +import com.redhat.thermostat.swing.Palette; +import com.redhat.thermostat.swing.models.LongRange; +import com.redhat.thermostat.swing.models.LongRangeNormalizer; +import com.redhat.thermostat.thread.client.common.ThreadTimelineBean; + +@SuppressWarnings("serial") +public class SwingThreadTimelineChart extends JPanel { + + private List<ThreadTimelineBean> timeline; + + private LongRangeNormalizer normalizer; + + public SwingThreadTimelineChart(List<ThreadTimelineBean> timeline, long rangeStart, long rangeStop) { + this.timeline = timeline; + + LongRange range = new LongRange(); + range.setMin(rangeStart); + range.setMax(rangeStop); + + setBorder(new GradientRoundBorder()); + normalizer = new LongRangeNormalizer(range); + } + + @Override + protected void paintComponent(Graphics g) { + + normalizer.setMinNormalized(0); + normalizer.setMaxNormalized(getWidth() - 3); + + GraphicsUtils utils = GraphicsUtils.getInstance(); + + Graphics2D graphics = utils.createAAGraphics(g); + + int y = getHeight()/3; + graphics.clearRect(0, 0, getWidth(), getHeight()); + graphics.drawString(timeline.get(0).getName(), 2, y); + + y = getHeight()/2; + + int w = getWidth() - 4; + int h = 10; + + Shape shape = utils.getRoundShape(w, h); + + graphics.translate(2, y); + + Paint paint = new GradientPaint(0, 0, Palette.DARK_GRAY.getColor(), 0, h, Palette.WHITE.getColor()); + graphics.setPaint(paint); + graphics.fill(shape); + + for (ThreadTimelineBean thread : timeline) { + normalizer.setValue(thread.getStartTime()); + int x0 = (int) normalizer.getValueNormalized(); + + normalizer.setValue(thread.getStopTime()); + int x1 = (int) normalizer.getValueNormalized(); + + graphics.setColor(getColor(thread)); + graphics.fillRect(x0, 1, x1 - x0, h - 1); + } + + graphics.setColor(getColor(timeline.get(timeline.size() - 1))); + graphics.draw(shape); + graphics.dispose(); + } + + private Color getColor(ThreadTimelineBean thread) { + Color result = null; + + switch (thread.getState()) { + case TIMED_WAITING: + result = Palette.PALE_RED.getColor(); + break; + + case NEW: + result = Palette.POMP_AND_POWER_VIOLET.getColor(); + break; + + case RUNNABLE: + result = Palette.PRUSSIAN_BLUE.getColor(); + break; + + case TERMINATED: + result = Palette.GRAY.getColor(); + break; + + case BLOCKED: + result = Palette.RED.getColor(); + break; + + case WAITING: + result = Palette.GRANITA_ORANGE.getColor(); + break; + + default: + result = Color.BLACK; + break; + } + return result; + } + + public static void main(String[] args) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + JFrame frame = new JFrame(); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + ThreadTimelineBean bean1 = new ThreadTimelineBean(); + bean1.setName("test"); + bean1.setStartTime(0); + bean1.setStopTime(1000); + bean1.setState(Thread.State.BLOCKED); + + ThreadTimelineBean bean2 = new ThreadTimelineBean(); + bean2.setName("test"); + bean2.setStartTime(1000); + bean2.setStopTime(2000); + bean2.setState(Thread.State.RUNNABLE); + + ThreadTimelineBean bean3 = new ThreadTimelineBean(); + bean3.setName("test"); + bean3.setStartTime(2000); + bean3.setStopTime(2100); + bean3.setState(Thread.State.TIMED_WAITING); + + List<ThreadTimelineBean> timeline = new ArrayList<>(); + timeline.add(bean1); + timeline.add(bean2); + timeline.add(bean3); + + SwingThreadTimelineChart chart = new SwingThreadTimelineChart(timeline, 0, 2500); + + frame.add(chart); + frame.setSize(800, 150); + + frame.setVisible(true); + } + }); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadTimelineView.java Wed Sep 19 10:08:17 2012 +0200 @@ -0,0 +1,118 @@ +/* + * 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.thread.client.swing.impl; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.util.List; +import java.util.Map; + +import javax.swing.DefaultListModel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.ListCellRenderer; +import javax.swing.ListSelectionModel; +import javax.swing.SwingUtilities; + +import com.redhat.thermostat.client.ui.ComponentVisibleListener; +import com.redhat.thermostat.client.ui.SwingComponent; +import com.redhat.thermostat.thread.client.common.ThreadTimelineBean; +import com.redhat.thermostat.thread.client.common.ThreadTimelineView; +import com.redhat.thermostat.thread.model.ThreadInfoData; + +public class SwingThreadTimelineView extends ThreadTimelineView implements SwingComponent { + + private JPanel timeLinePanel; + private DefaultListModel<SwingThreadTimelineChart> model; + + public SwingThreadTimelineView() { + timeLinePanel = new JPanel(); + timeLinePanel.addHierarchyListener(new ComponentVisibleListener() { + @Override + public void componentShown(Component component) { + SwingThreadTimelineView.this.notify(Action.VISIBLE); + } + + @Override + public void componentHidden(Component component) { + SwingThreadTimelineView.this.notify(Action.HIDDEN); + } + }); + + timeLinePanel.setLayout(new BorderLayout(0, 0)); + model = new DefaultListModel<>(); + JList<SwingThreadTimelineChart> chartList = new JList<>(model); + + chartList.setLayoutOrientation(JList.VERTICAL); + chartList.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); + JScrollPane scrollPane = new JScrollPane(chartList); + scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + timeLinePanel.add(scrollPane); + chartList.setCellRenderer(new ListCellRenderer<SwingThreadTimelineChart>() { + @Override + public Component getListCellRendererComponent( + JList<? extends SwingThreadTimelineChart> list, SwingThreadTimelineChart value, + int index, boolean isSelected, boolean cellHasFocus) { + return value; + } + }); + } + + @Override + public void displayStats(final Map<ThreadInfoData, List<ThreadTimelineBean>> timelines, final long start, final long stop) { + + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + model.clear(); + for (List<ThreadTimelineBean> timeline : timelines.values()) { + SwingThreadTimelineChart panel = new SwingThreadTimelineChart(timeline, start, stop); + panel.setPreferredSize(new Dimension(timeLinePanel.getWidth(), 50)); + model.addElement(panel); + } + } + }); + } + + @Override + public Component getUiComponent() { + return timeLinePanel; + } +}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadView.java Tue Sep 18 17:38:29 2012 -0400 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadView.java Wed Sep 19 10:08:17 2012 +0200 @@ -56,6 +56,7 @@ import com.redhat.thermostat.swing.ChartPanel; import com.redhat.thermostat.thread.client.common.ThreadTableBean; import com.redhat.thermostat.thread.client.common.ThreadTableView; +import com.redhat.thermostat.thread.client.common.ThreadTimelineView; import com.redhat.thermostat.thread.client.common.ThreadView; import com.redhat.thermostat.thread.client.common.VMThreadCapabilitiesView; import com.redhat.thermostat.thread.client.common.chart.LivingDaemonThreadDifferenceChart; @@ -70,8 +71,9 @@ private SwingThreadTableView threadTableView; private SwingVMThreadCapabilitiesView vmCapsView; + private SwingThreadTimelineView threadTimelineView; private SwingThreadDetailsView threadDetailsView; - + private JTabbedPane pane; private static final Translate t = LocaleResources.createLocalizer(); @@ -152,6 +154,9 @@ pane.addTab(t.localize(LocaleResources.DETAILS), threadDetailsView.getUiComponent()); threadDetailsPaneID = 2; + threadTimelineView = new SwingThreadTimelineView(); + pane.addTab(t.localize(LocaleResources.TIMELINE), threadTimelineView.getUiComponent()); + panel.getSplitPane().setBottomComponent(pane); } @@ -261,4 +266,9 @@ } }); } + + @Override + public ThreadTimelineView createThreadTimelineView() { + return threadTimelineView; + } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/ThreadTimelineChart.java Wed Sep 19 10:08:17 2012 +0200 @@ -0,0 +1,89 @@ +/* + * 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.thread.client.swing.impl; + +import java.awt.Graphics; +import java.awt.Graphics2D; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import javax.swing.plaf.ColorUIResource; + +import com.redhat.thermostat.swing.GraphicsUtils; + +@SuppressWarnings("serial") +public class ThreadTimelineChart extends JPanel { + + private static final ColorUIResource TICK_COLOR = new ColorUIResource(0xa8aca8); + + public ThreadTimelineChart() { + } + + @Override + protected void paintComponent(Graphics g) { + Graphics2D graphics = GraphicsUtils.getInstance().createAAGraphics(g); + + graphics.setColor(TICK_COLOR); + + int x = 1; + int y = 2; + int w = getWidth() - 2; + int h = getHeight(); + + graphics.drawLine(x, y, w, y); + + graphics.dispose(); + } + + public static void main(String[] args) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + JFrame frame = new JFrame(); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + ThreadTimelineChart chart = new ThreadTimelineChart(); + + frame.add(chart); + frame.setSize(500, 500); + frame.setVisible(true); + } + }); + } +}