Mercurial > hg > release > thermostat-0.4
changeset 588:591c74ae68d5
Add initial Thread Monitor Pie Chart
reviewed-by: rkennke
review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-September/003079.html
line wrap: on
line diff
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/ChartPanel.java Wed Sep 05 11:30:48 2012 +0200 +++ b/client/swing-components/src/main/java/com/redhat/thermostat/swing/ChartPanel.java Fri Sep 07 17:22:36 2012 +0200 @@ -43,6 +43,7 @@ import com.redhat.thermostat.charts.Chart; +@SuppressWarnings("serial") public class ChartPanel extends JPanel { private Chart chart;
--- a/distribution/config/osgi-export.properties Wed Sep 05 11:30:48 2012 +0200 +++ b/distribution/config/osgi-export.properties Fri Sep 07 17:22:36 2012 +0200 @@ -46,6 +46,7 @@ org.jfree.chart.plot org.jfree.chart.renderer.xy org.jfree.data +org.jfree.data.general org.jfree.data.time org.jfree.data.xy org.jfree.ui
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/ThreadDetailsView.java Fri Sep 07 17:22:36 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.thread.client.common; + +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.redhat.thermostat.client.osgi.service.BasicView; +import com.redhat.thermostat.client.ui.IconDescriptor; + +public abstract class ThreadDetailsView extends BasicView { + + private static final Logger logger = Logger.getLogger(ThreadDetailsView.class.getSimpleName()); + + public IconDescriptor getEmptyDetailsIcon() { + try { + return IconDescriptor.createFromClassloader(ClassLoader.getSystemClassLoader(), "com/redhat/thermostat/thread/client/common/monitor.png"); + } catch (IOException e) { + logger.log(Level.WARNING, "Can't load emptyDetailsIcon", e); + } + return null; + } + + public abstract void setDetails(ThreadTableBean thread); +}
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/ThreadTableBean.java Wed Sep 05 11:30:48 2012 +0200 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/ThreadTableBean.java Fri Sep 07 17:22:36 2012 +0200 @@ -47,9 +47,11 @@ private long start; private long waitedCount; private long blockedCount; - + private double runningPercent; private double waitingPercent; + private double monitorPercent; + private double sleepingPercent; public long getId() { return id; @@ -145,4 +147,20 @@ public void setRunningPercent(double runningPercent) { this.runningPercent = runningPercent; } + + public void setMonitorPercent(double monitorPercent) { + this.monitorPercent = monitorPercent; + } + + public double getMonitorPercent() { + return monitorPercent; + } + + public void setSleepingPercent(double sleepingPercent) { + this.sleepingPercent = sleepingPercent; + } + + public double getSleepingPercent() { + return sleepingPercent; + } }
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/ThreadTableView.java Wed Sep 05 11:30:48 2012 +0200 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/ThreadTableView.java Fri Sep 07 17:22:36 2012 +0200 @@ -39,8 +39,27 @@ import java.util.List; import com.redhat.thermostat.client.osgi.service.BasicView; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.ActionNotifier; public abstract class ThreadTableView extends BasicView { + public static enum ThreadSelectionAction { + SHOW_THREAD_DETAILS + } + + protected final ActionNotifier<ThreadSelectionAction> threadTableNotifier; + public ThreadTableView() { + threadTableNotifier = new ActionNotifier<>(this); + } + + public void addThreadSelectionActionListener(ActionListener<ThreadSelectionAction> listener) { + threadTableNotifier.addActionListener(listener); + } + + public void removeThreadSelectionActionListener(ActionListener<ThreadSelectionAction> listener) { + threadTableNotifier.removeActionListener(listener); + } + public abstract void display(List<ThreadTableBean> arrayList); }
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/ThreadView.java Wed Sep 05 11:30:48 2012 +0200 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/ThreadView.java Fri Sep 07 17:22:36 2012 +0200 @@ -81,4 +81,6 @@ this.appService = appService; this.uniqueId = uniqueId; } + + public abstract void displayThreadDetails(ThreadTableBean thread); }
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/ThreadViewProvider.java Wed Sep 05 11:30:48 2012 +0200 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/ThreadViewProvider.java Fri Sep 07 17:22:36 2012 +0200 @@ -37,7 +37,6 @@ package com.redhat.thermostat.thread.client.common; import com.redhat.thermostat.client.osgi.service.ViewProvider; -import com.redhat.thermostat.client.ui.UIComponent; public interface ThreadViewProvider extends ViewProvider {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/chart/ThreadDeatailsPieChart.java Fri Sep 07 17:22:36 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.chart; + +import java.awt.Color; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.plot.PiePlot3D; +import org.jfree.data.general.DefaultPieDataset; + +import com.redhat.thermostat.charts.Chart; +import com.redhat.thermostat.thread.client.common.ThreadTableBean; + +public class ThreadDeatailsPieChart extends Chart { + + private ThreadTableBean thread; + + public ThreadDeatailsPieChart(ThreadTableBean thread) { + this.thread = thread; + } + + @Override + protected JFreeChart createChart(int width, int height, Color bgColor) { + + DefaultPieDataset dataset = new DefaultPieDataset(); + + dataset.setValue("Running", thread.getRunningPercent()); + dataset.setValue("Waiting", thread.getWaitingPercent()); + dataset.setValue("Monitor", thread.getMonitorPercent()); + dataset.setValue("Sleeping", thread.getSleepingPercent()); + + JFreeChart chart = ChartFactory.createPieChart3D( + thread.getName(), // chart title + dataset, // data + true, // include legend + true, + false + ); + + chart.setAntiAlias(true); + + PiePlot3D plot = (PiePlot3D) chart.getPlot(); + plot.setBackgroundPaint(bgColor); + + plot.setStartAngle(290); + plot.setForegroundAlpha(0.5f); + + + return chart; + } +}
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/locale/LocaleResources.java Wed Sep 05 11:30:48 2012 +0200 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/locale/LocaleResources.java Fri Sep 07 17:22:36 2012 +0200 @@ -48,12 +48,15 @@ BLOCK_COUNT, RUNNING, WAITING, + SLEEPING, + MONITOR, START_RECORDING, STOP_RECORDING, VM_CAPABILITIES, TABLE, + DETAILS, LIVE_THREADS, DAEMON_THREADS, @@ -61,7 +64,8 @@ THREAD_CONTROL_PANEL, THREAD_DUMP, - MISSING_INFO; + MISSING_INFO, + THREAD_DETAILS_EMTPY; public static final String RESOURCE_BUNDLE = "com.redhat.thermostat.thread.client.common.locale.strings";
--- a/thread/client-common/src/main/resources/com/redhat/thermostat/thread/client/common/locale/strings.properties Wed Sep 05 11:30:48 2012 +0200 +++ b/thread/client-common/src/main/resources/com/redhat/thermostat/thread/client/common/locale/strings.properties Fri Sep 07 17:22:36 2012 +0200 @@ -8,14 +8,19 @@ BLOCK_COUNT = Blocked Count RUNNING = Running % WAITING = Waiting % - +SLEEPING = Sleeping % +MONITOR = Monitor % + START_RECORDING = Start Recording STOP_RECORDING = Stop Recording VM_CAPABILITIES = VM Capabilities TABLE = Table +DETAILS = Details LIVE_THREADS = Live Threads DAEMON_THREADS = Daemon Threads THREAD_CONTROL_PANEL = Thread Control Panel THREAD_DUMP = Thread Dump + +THREAD_DETAILS_EMTPY = Please, select a Thread from the Thread Table \ No newline at end of file
Binary file thread/client-common/src/main/resources/com/redhat/thermostat/thread/client/common/monitor.png has changed
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInformationController.java Wed Sep 05 11:30:48 2012 +0200 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInformationController.java Fri Sep 07 17:22:36 2012 +0200 @@ -41,10 +41,9 @@ import java.util.logging.Level; import java.util.logging.Logger; -import com.redhat.thermostat.client.osgi.service.ApplicationCache; import com.redhat.thermostat.client.osgi.service.ApplicationService; +import com.redhat.thermostat.client.osgi.service.BasicView.Action; import com.redhat.thermostat.client.osgi.service.VmInformationServiceController; -import com.redhat.thermostat.client.osgi.service.BasicView.Action; import com.redhat.thermostat.client.ui.UIComponent; import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener; @@ -53,16 +52,16 @@ import com.redhat.thermostat.common.Timer.SchedulingType; import com.redhat.thermostat.common.appctx.ApplicationContext; import com.redhat.thermostat.common.dao.VmRef; +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.ThreadView; +import com.redhat.thermostat.thread.client.common.ThreadView.ThreadAction; import com.redhat.thermostat.thread.client.common.ThreadViewProvider; -import com.redhat.thermostat.thread.client.common.VMThreadCapabilitiesView; -import com.redhat.thermostat.thread.client.common.ThreadView.ThreadAction; import com.redhat.thermostat.thread.client.common.chart.LivingDaemonThreadDifferenceChart; import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; import com.redhat.thermostat.thread.client.common.collector.ThreadCollectorFactory; - import com.redhat.thermostat.thread.model.ThreadSummary; -import com.redhat.thermostat.thread.model.VMThreadCapabilities; public class ThreadInformationController implements VmInformationServiceController { @@ -190,13 +189,22 @@ } } + private class ThreadSelectionActionListener implements ActionListener<ThreadSelectionAction> { + @Override + public void actionPerformed(ActionEvent<ThreadSelectionAction> actionEvent) { + view.displayThreadDetails((ThreadTableBean) actionEvent.getPayload()); + } + } + private void initControllers() { CommonController capsController = new VMThreadCapabilitiesController(view.createVMThreadCapabilitiesView(), collector); capsController.initialize(); + ThreadTableView threadTableView = view.createThreadTableView(); + threadTableView.addThreadSelectionActionListener(new ThreadSelectionActionListener()); CommonController threadTableController = - new ThreadTableController(view.createThreadTableView(), collector, + new ThreadTableController(threadTableView, collector, ApplicationContext.getInstance().getTimerFactory().createTimer()); threadTableController.initialize(); }
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadTableController.java Wed Sep 05 11:30:48 2012 +0200 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadTableController.java Fri Sep 07 17:22:36 2012 +0200 @@ -146,6 +146,8 @@ // time for some stats double running = 0; double waiting = 0; + double monitor = 0; + double sleeping = 0; for (ThreadInfoData info : beanList) { State state = info.getState(); switch (state) { @@ -154,10 +156,13 @@ break; case NEW: case TERMINATED: - System.err.println("yeah!"); break; case BLOCKED: + monitor++; + break; case TIMED_WAITING: + sleeping++; + break; case WAITING: waiting++; default: @@ -165,12 +170,18 @@ } } int polls = beanList.size(); - double runningPercent = (running/polls) * 100; - double waitingPercent = (waiting/polls) * 100; + double percent = (running/polls) * 100; + bean.setRunningPercent(percent); + + percent = (waiting/polls) * 100; + bean.setWaitingPercent(percent); - bean.setRunningPercent(runningPercent); - bean.setWaitingPercent(waitingPercent); - + percent = (monitor/polls) * 100; + bean.setMonitorPercent(percent); + + percent = (sleeping/polls) * 100; + bean.setSleepingPercent(percent); + tableBeans.add(bean); }
--- a/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInformationControllerTest.java Wed Sep 05 11:30:48 2012 +0200 +++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInformationControllerTest.java Fri Sep 07 17:22:36 2012 +0200 @@ -36,13 +36,11 @@ 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.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.mockito.Mockito.anyString; -import static org.mockito.Mockito.times; import org.junit.After; import org.junit.Before; @@ -59,7 +57,9 @@ import com.redhat.thermostat.common.appctx.ApplicationContextUtil; import com.redhat.thermostat.common.dao.HostRef; import com.redhat.thermostat.common.dao.VmRef; +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.ThreadView; import com.redhat.thermostat.thread.client.common.ThreadViewProvider; import com.redhat.thermostat.thread.client.common.VMThreadCapabilitiesView; @@ -71,12 +71,16 @@ private Timer timer; private ThreadView view; private ActionListener<ThreadView.Action> actionListener; - + private ActionListener<ThreadTableView.ThreadSelectionAction> threadTableActionListener; + private ThreadViewProvider viewFactory; private ThreadInformationController controller; private ApplicationService appService; - + + private ThreadTableView threadTableView; + private VMThreadCapabilitiesView threadCapsView; + @Before public void setUp() { ApplicationContextUtil.resetApplicationContext(); @@ -90,15 +94,15 @@ } private void setUpView() { - VMThreadCapabilitiesView commonController1 = mock(VMThreadCapabilitiesView.class); - ThreadTableView commonController2 = mock(ThreadTableView.class); + threadCapsView = mock(VMThreadCapabilitiesView.class); + threadTableView = mock(ThreadTableView.class); view = mock(ThreadView.class); viewFactory = mock(ThreadViewProvider.class); when(viewFactory.createView()).thenReturn(view); - when(view.createVMThreadCapabilitiesView()).thenReturn(commonController1); - when(view.createThreadTableView()).thenReturn(commonController2); + when(view.createVMThreadCapabilitiesView()).thenReturn(threadCapsView); + when(view.createThreadTableView()).thenReturn(threadTableView); } private void setUpTimers() { @@ -112,12 +116,16 @@ } private void setUpListeners() { - ArgumentCaptor<ActionListener> viewArgumentCaptor1 = ArgumentCaptor.forClass(ActionListener.class); - doNothing().when(view).addActionListener(viewArgumentCaptor1.capture()); + ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class); + doNothing().when(view).addActionListener(viewArgumentCaptor.capture()); + + ArgumentCaptor<ActionListener> threadTableViewCaptor = ArgumentCaptor.forClass(ActionListener.class); + doNothing().when(threadTableView).addThreadSelectionActionListener(threadTableViewCaptor.capture()); createController(); - actionListener = viewArgumentCaptor1.getValue(); + actionListener = viewArgumentCaptor.getValue(); + threadTableActionListener = threadTableViewCaptor.getValue(); } private void createController() { @@ -138,6 +146,15 @@ } @Test + public void verifyViewCreateSubViewCalled() { + + createController(); + + verify(view).createThreadTableView(); + verify(view).createVMThreadCapabilitiesView(); + } + + @Test public void verifyLiveRecording() { ActionListener<ThreadView.ThreadAction> threadActionListener; @@ -199,4 +216,18 @@ actionListener.actionPerformed(new ActionEvent<>(view, ThreadView.Action.HIDDEN)); verify(timer).stop(); } + + @Test + public void verifyTableViewLinksToDetailsView() { + setUpListeners(); + + ThreadTableBean bean = mock(ThreadTableBean.class); + + ActionEvent<ThreadSelectionAction> event = + new ActionEvent<>(threadTableView, ThreadSelectionAction.SHOW_THREAD_DETAILS); + event.setPayload(bean); + + threadTableActionListener.actionPerformed(event); + verify(view).displayThreadDetails(bean); + } }
--- a/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadTableControllerTest.java Wed Sep 05 11:30:48 2012 +0200 +++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadTableControllerTest.java Fri Sep 07 17:22:36 2012 +0200 @@ -38,12 +38,8 @@ import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; -import java.util.ArrayList; -import java.util.List; - import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -55,7 +51,6 @@ import com.redhat.thermostat.common.appctx.ApplicationContextUtil; 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 ThreadTableControllerTest {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadDetailsView.java Fri Sep 07 17:22:36 2012 +0200 @@ -0,0 +1,91 @@ +/* + * 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.Component; + +import javax.swing.JPanel; + +import com.redhat.thermostat.client.ui.SwingComponent; +import com.redhat.thermostat.common.locale.Translate; +import com.redhat.thermostat.swing.ChartPanel; +import com.redhat.thermostat.thread.client.common.ThreadDetailsView; +import com.redhat.thermostat.thread.client.common.ThreadTableBean; +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; + private static final Translate t = LocaleResources.createLocalizer(); + + SwingThreadDetailsView() { + details = new JPanel(); + details.setLayout(new BorderLayout(0, 0)); + + JLabel lblNewLabel = new JLabel(t.localize(LocaleResources.THREAD_DETAILS_EMTPY)); + lblNewLabel.setIcon(new ImageIcon(getEmptyDetailsIcon().getData().array())); + details.add(lblNewLabel); + } + + @Override + public Component getUiComponent() { + return details; + } + + @Override + public void setDetails(ThreadTableBean thread) { + details.removeAll(); + + ThreadDetailsChart threadChart = new ThreadDetailsChart(); + + ChartPanel threadSummary = new ChartPanel(new ThreadDeatailsPieChart(thread)); + threadChart.add(threadSummary); + + details.add(threadChart); + details.repaint(); + } +}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadTableView.java Wed Sep 05 11:30:48 2012 +0200 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadTableView.java Fri Sep 07 17:22:36 2012 +0200 @@ -37,12 +37,15 @@ package com.redhat.thermostat.thread.client.swing.impl; import java.awt.Component; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.swing.JTable; import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.DefaultTableModel; @@ -78,6 +81,7 @@ }); table = new JTable(new ThreadViewTableModel(new ArrayList<ThreadTableBean>())); + table.setName("threadBeansTable"); table.getModel().addTableModelListener(new TableModelListener() { @Override public void tableChanged(TableModelEvent e) { @@ -100,6 +104,27 @@ table.setFillsViewportHeight(true); table.setAutoCreateRowSorter(true); tablePanel.setTable(table); + + table.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { + ThreadViewTableModel model = (ThreadViewTableModel) table.getModel(); + int selectedRow = table.getSelectedRow(); + if (selectedRow != -1) { + selectedRow = table.convertRowIndexToModel(selectedRow); + final ThreadTableBean bean = model.infos.get(selectedRow); + SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { + protected Void doInBackground() throws Exception { + threadTableNotifier.fireAction(ThreadSelectionAction.SHOW_THREAD_DETAILS, bean); + return null; + } + }; + worker.execute(); + } + } + } + }); } @Override @@ -153,7 +178,9 @@ t.localize(LocaleResources.WAIT_COUNT), t.localize(LocaleResources.BLOCK_COUNT), t.localize(LocaleResources.RUNNING), - t.localize(LocaleResources.WAITING), //, "Heap", "CPU Time", "User CPU Time" + t.localize(LocaleResources.WAITING), + t.localize(LocaleResources.SLEEPING), + t.localize(LocaleResources.MONITOR), //, "Heap", "CPU Time", "User CPU Time" }; private List<ThreadTableBean> infos; @@ -233,7 +260,13 @@ break; case 7: result = info.getWaitingPercent(); - break; + break; + case 8: + result = info.getSleepingPercent(); + break; + case 9: + result = info.getMonitorPercent(); + break; default: result = "n/a"; break;
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadView.java Wed Sep 05 11:30:48 2012 +0200 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadView.java Fri Sep 07 17:22:36 2012 +0200 @@ -54,6 +54,8 @@ import com.redhat.thermostat.client.ui.SwingComponent; import com.redhat.thermostat.common.locale.Translate; import com.redhat.thermostat.swing.ChartPanel; +import com.redhat.thermostat.thread.client.common.ThreadDetailsView; +import com.redhat.thermostat.thread.client.common.ThreadTableBean; import com.redhat.thermostat.thread.client.common.ThreadTableView; import com.redhat.thermostat.thread.client.common.ThreadView; import com.redhat.thermostat.thread.client.common.VMThreadCapabilitiesView; @@ -67,13 +69,18 @@ private ThreadMainPanel panel; private ThreadAliveDaemonTimelinePanel timelinePanel; - private SwingThreadTableView threadTable; + private SwingThreadTableView threadTableView; private SwingVMThreadCapabilitiesView vmCapsView; + private SwingThreadDetailsView threadDetailsView; + + private JTabbedPane pane; private static final Translate t = LocaleResources.createLocalizer(); private boolean skipNotification = false; + private int threadDetailsPaneID = 0; + public SwingThreadView() { panel = new ThreadMainPanel(); @@ -135,11 +142,17 @@ panel.getSplitPane().setTopComponent(timelinePanel); vmCapsView = new SwingVMThreadCapabilitiesView(); - JTabbedPane pane = new JTabbedPane(); + pane = new JTabbedPane(); + pane.setName("tabbedPane"); + pane.addTab(t.localize(LocaleResources.VM_CAPABILITIES), vmCapsView.getUiComponent()); - threadTable = new SwingThreadTableView(); - pane.addTab(t.localize(LocaleResources.TABLE), threadTable.getUiComponent()); + threadTableView = new SwingThreadTableView(); + pane.addTab(t.localize(LocaleResources.TABLE), threadTableView.getUiComponent()); + + threadDetailsView = new SwingThreadDetailsView(); + pane.addTab(t.localize(LocaleResources.DETAILS), threadDetailsView.getUiComponent()); + threadDetailsPaneID = 2; panel.getSplitPane().setBottomComponent(pane); } @@ -210,7 +223,7 @@ @Override public ThreadTableView createThreadTableView() { - return threadTable; + return threadTableView; } @Override @@ -239,4 +252,15 @@ appService.getApplicationCache().addAttribute(DIVIDER_LOCATION_KEY, location); } } + + @Override + public void displayThreadDetails(final ThreadTableBean thread) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + pane.setSelectedIndex(threadDetailsPaneID); + threadDetailsView.setDetails(thread); + } + }); + } }
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/ThreadAliveDaemonTimelinePanel.java Wed Sep 05 11:30:48 2012 +0200 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/ThreadAliveDaemonTimelinePanel.java Fri Sep 07 17:22:36 2012 +0200 @@ -41,7 +41,6 @@ import javax.swing.GroupLayout.Alignment; import javax.swing.JLabel; import javax.swing.JPanel; -import javax.swing.JToggleButton; import javax.swing.LayoutStyle.ComponentPlacement; import javax.swing.SwingConstants;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/ThreadDetailsChart.java Fri Sep 07 17:22:36 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.swing.impl; + +import javax.swing.BoxLayout; +import javax.swing.JPanel; + +@SuppressWarnings("serial") +public class ThreadDetailsChart extends JPanel { + + public ThreadDetailsChart() { + setOpaque(false); + setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); + } +}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/ThreadMainPanel.java Wed Sep 05 11:30:48 2012 +0200 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/ThreadMainPanel.java Fri Sep 07 17:22:36 2012 +0200 @@ -62,6 +62,7 @@ headerPanel.setContent(content); splitPane = new JSplitPane(); + splitPane.setName("threadMainPanelSplitPane"); splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT); splitPane.setOneTouchExpandable(true);
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/ThreadTable.java Wed Sep 05 11:30:48 2012 +0200 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/ThreadTable.java Fri Sep 07 17:22:36 2012 +0200 @@ -41,6 +41,7 @@ import javax.swing.JScrollPane; import javax.swing.JTable; +@SuppressWarnings("serial") public class ThreadTable extends JPanel { private JScrollPane scrollPane;
--- a/thread/client-swing/src/test/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadViewTest.java Wed Sep 05 11:30:48 2012 +0200 +++ b/thread/client-swing/src/test/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadViewTest.java Fri Sep 07 17:22:36 2012 +0200 @@ -36,22 +36,27 @@ package com.redhat.thermostat.thread.client.swing.impl; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; +import java.util.concurrent.Semaphore; -import javax.swing.JButton; import javax.swing.JFrame; import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner; import org.fest.swing.annotation.GUITest; +import org.fest.swing.data.TableCell; import org.fest.swing.edt.FailOnThreadViolationRepaintManager; import org.fest.swing.edt.GuiActionRunner; import org.fest.swing.edt.GuiTask; import org.fest.swing.fixture.FrameFixture; -import org.fest.swing.fixture.JButtonFixture; import org.fest.swing.fixture.JLabelFixture; import org.fest.swing.fixture.JToggleButtonFixture; import org.junit.After; @@ -61,7 +66,12 @@ import org.junit.Test; import org.junit.runner.RunWith; +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.locale.Translate; +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.locale.LocaleResources; @RunWith(CacioFESTRunner.class) @@ -132,4 +142,44 @@ toggleTest.requireText(t.localize(LocaleResources.START_RECORDING) + ":"); } + @GUITest + @Test + public void verifTableViewLinksToDetailsView() throws InvocationTargetException, InterruptedException { + + final boolean listenerCalled[] = new boolean[1]; + + ThreadTableBean bean1 = mock(ThreadTableBean.class); + when(bean1.getName()).thenReturn("mocked bean 1"); + + ThreadTableBean bean2 = mock(ThreadTableBean.class); + when(bean2.getName()).thenReturn("mocked bean 2"); + + List<ThreadTableBean> threadList = new ArrayList<>(); + threadList.add(bean1); + threadList.add(bean2); + + frameFixture.show(); + + frameFixture.splitPane("threadMainPanelSplitPane").moveDividerTo(0); + frameFixture.tabbedPane("tabbedPane").selectTab(1); + + final Semaphore sem = new Semaphore(1); + ThreadTableView tableView = view.createThreadTableView(); + tableView.addThreadSelectionActionListener(new ActionListener<ThreadTableView.ThreadSelectionAction>() { + @Override + public void actionPerformed(ActionEvent<ThreadSelectionAction> actionEvent) { + listenerCalled[0] = true; + view.displayThreadDetails((ThreadTableBean) actionEvent.getPayload()); + sem.release(); + } + }); + + tableView.display(threadList); + + frameFixture.table("threadBeansTable").cell(TableCell.row(1).column(0)).doubleClick(); + sem.acquire(); + + assertTrue(listenerCalled[0]); + assertEquals(2, frameFixture.tabbedPane("tabbedPane").target.getSelectedIndex()); + } }