changeset 267:7d5c9fdb7305

Make start and stop methods of the controllers non-public Reviewed-by: rkennke Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-April/001147.html
author Omair Majid <omajid@redhat.com>
date Mon, 30 Apr 2012 11:44:05 -0400
parents aa3fb04ae01f
children 19b44914e3e1
files client/src/main/java/com/redhat/thermostat/client/AsyncUiFacade.java client/src/main/java/com/redhat/thermostat/client/HostPanelFacade.java client/src/main/java/com/redhat/thermostat/client/HostPanelFacadeImpl.java client/src/main/java/com/redhat/thermostat/client/MainView.java client/src/main/java/com/redhat/thermostat/client/MainWindowController.java client/src/main/java/com/redhat/thermostat/client/MainWindowControllerImpl.java client/src/main/java/com/redhat/thermostat/client/SummaryPanelFacade.java client/src/main/java/com/redhat/thermostat/client/ui/AsyncFacadeManager.java client/src/main/java/com/redhat/thermostat/client/ui/HostCpuController.java client/src/main/java/com/redhat/thermostat/client/ui/HostCpuPanel.java client/src/main/java/com/redhat/thermostat/client/ui/HostCpuView.java client/src/main/java/com/redhat/thermostat/client/ui/HostMemoryController.java client/src/main/java/com/redhat/thermostat/client/ui/HostMemoryPanel.java client/src/main/java/com/redhat/thermostat/client/ui/HostMemoryView.java client/src/main/java/com/redhat/thermostat/client/ui/HostOverviewController.java client/src/main/java/com/redhat/thermostat/client/ui/HostOverviewPanel.java client/src/main/java/com/redhat/thermostat/client/ui/HostOverviewView.java client/src/main/java/com/redhat/thermostat/client/ui/HostPanel.java client/src/main/java/com/redhat/thermostat/client/ui/MainWindow.java client/src/main/java/com/redhat/thermostat/client/ui/SummaryPanel.java client/src/main/java/com/redhat/thermostat/client/ui/VmClassStatController.java client/src/main/java/com/redhat/thermostat/client/ui/VmClassStatPanel.java client/src/main/java/com/redhat/thermostat/client/ui/VmClassStatView.java client/src/main/java/com/redhat/thermostat/client/ui/VmCpuController.java client/src/main/java/com/redhat/thermostat/client/ui/VmCpuPanel.java client/src/main/java/com/redhat/thermostat/client/ui/VmCpuView.java client/src/main/java/com/redhat/thermostat/client/ui/VmGcController.java client/src/main/java/com/redhat/thermostat/client/ui/VmGcPanel.java client/src/main/java/com/redhat/thermostat/client/ui/VmGcView.java client/src/main/java/com/redhat/thermostat/client/ui/VmInformationController.java client/src/main/java/com/redhat/thermostat/client/ui/VmInformationPanel.java client/src/main/java/com/redhat/thermostat/client/ui/VmMemoryController.java client/src/main/java/com/redhat/thermostat/client/ui/VmMemoryPanel.java client/src/main/java/com/redhat/thermostat/client/ui/VmMemoryView.java client/src/main/java/com/redhat/thermostat/client/ui/VmOverviewController.java client/src/main/java/com/redhat/thermostat/client/ui/VmOverviewPanel.java client/src/main/java/com/redhat/thermostat/client/ui/VmOverviewView.java client/src/test/java/com/redhat/thermostat/client/MainWindowControllerImplTest.java client/src/test/java/com/redhat/thermostat/client/ui/HostCpuControllerTest.java client/src/test/java/com/redhat/thermostat/client/ui/HostMemoryControllerTest.java client/src/test/java/com/redhat/thermostat/client/ui/VmClassStatControllerTest.java client/src/test/java/com/redhat/thermostat/client/ui/VmCpuControllerTest.java client/src/test/java/com/redhat/thermostat/client/ui/VmMemoryControllerTest.java common/src/main/java/com/redhat/thermostat/common/ActionNotifier.java
diffstat 44 files changed, 774 insertions(+), 370 deletions(-) [+]
line wrap: on
line diff
--- a/client/src/main/java/com/redhat/thermostat/client/AsyncUiFacade.java	Thu Apr 26 13:32:33 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * 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.client;
-
-public interface AsyncUiFacade {
-
-    public void start();
-
-    public void stop();
-}
--- a/client/src/main/java/com/redhat/thermostat/client/HostPanelFacade.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/HostPanelFacade.java	Mon Apr 30 11:44:05 2012 -0400
@@ -40,7 +40,7 @@
 import com.redhat.thermostat.client.ui.HostMemoryController;
 import com.redhat.thermostat.client.ui.HostOverviewController;
 
-public interface HostPanelFacade extends AsyncUiFacade {
+public interface HostPanelFacade  {
 
     public HostOverviewController getOverviewController();
 
--- a/client/src/main/java/com/redhat/thermostat/client/HostPanelFacadeImpl.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/HostPanelFacadeImpl.java	Mon Apr 30 11:44:05 2012 -0400
@@ -54,20 +54,6 @@
     }
 
     @Override
-    public void start() {
-        overviewController.start();
-        cpuController.start();
-        memoryController.start();
-    }
-
-    @Override
-    public void stop() {
-        overviewController.stop();
-        cpuController.stop();
-        memoryController.stop();
-    }
-
-    @Override
     public HostOverviewController getOverviewController() {
         return overviewController;
     }
--- a/client/src/main/java/com/redhat/thermostat/client/MainView.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/MainView.java	Mon Apr 30 11:44:05 2012 -0400
@@ -44,6 +44,8 @@
 public interface MainView {
 
     enum Action {
+        VISIBLE,
+        HIDDEN,
         HOST_VM_TREE_FILTER,
         HOST_VM_SELECTION_CHANGED,
         SHOW_AGENT_CONFIG,
--- a/client/src/main/java/com/redhat/thermostat/client/MainWindowController.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/MainWindowController.java	Mon Apr 30 11:44:05 2012 -0400
@@ -37,7 +37,7 @@
 package com.redhat.thermostat.client;
 
 
-public interface MainWindowController extends AsyncUiFacade {
+public interface MainWindowController {
 
     public void setHostVmTreeFilter(String filter);
 
--- a/client/src/main/java/com/redhat/thermostat/client/MainWindowControllerImpl.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/MainWindowControllerImpl.java	Mon Apr 30 11:44:05 2012 -0400
@@ -78,10 +78,8 @@
 
     private boolean showHistory;
 
-    private AsyncUiFacade oldController = null;
+    private VmInformationControllerProvider vmInfoControllerProvider;
 
-    private VmInformationControllerProvider vmInfoControllerProvider;
-    
     public MainWindowControllerImpl(UiFacadeFactory facadeFactory, MainView view) {
         this.facadeFactory = facadeFactory;
 
@@ -91,13 +89,12 @@
         vmsDAO = daoFactory.getVmInfoDAO();
 
         initView(view);
-        
+
         vmInfoControllerProvider = new VmInformationControllerProvider();
-        
+
         appInfo = new ApplicationInfo();
         view.setWindowTitle(appInfo.getName());
         initializeTimer();
-        start();
     }
 
     private class HostsVMsLoaderImpl implements HostsVMsLoader {
@@ -133,13 +130,11 @@
         backgroundUpdater.setSchedulingType(SchedulingType.FIXED_RATE);
     }
 
-    @Override
-    public void start() {
+    private void startBackgroundUpdates() {
         backgroundUpdater.start();
     }
 
-    @Override
-    public void stop() {
+    public void stopBackgroundUpdates() {
         backgroundUpdater.stop();
     }
 
@@ -162,6 +157,12 @@
             public void actionPerformed(ActionEvent<MainView.Action> evt) {
                 MainView.Action action = evt.getActionId();
                 switch (action) {
+                case VISIBLE:
+                    startBackgroundUpdates();
+                    break;
+                case HIDDEN:
+                    stopBackgroundUpdates();
+                    break;
                 case HOST_VM_SELECTION_CHANGED:
                     updateView();
                     break;
@@ -183,7 +184,6 @@
                     break;
                 case SHUTDOWN:
                     view.hideMainWindow();
-                    stop();
                     ApplicationContext.getInstance().getTimerFactory().shutdown();
                     break;
                 default:
@@ -229,11 +229,6 @@
         // this is quite an ugly method. there must be a cleaner way to do this
         Ref ref = view.getSelectedHostOrVm();
 
-        if (oldController != null) {
-            oldController.stop();
-            oldController = null;
-        }
-
         if (ref == null) {
             view.setSubView(new SummaryPanel(facadeFactory.getSummaryPanel()));
         } else if (ref instanceof HostRef) {
@@ -244,8 +239,6 @@
             VmInformationController vmInformation =
                     vmInfoControllerProvider.getVmInfoController(vmRef);
             view.setSubView(vmInformation.getComponent());
-            vmInformation.start();
-            oldController = vmInformation;
         } else {
             throw new IllegalArgumentException("unknown type of ref");
         }
--- a/client/src/main/java/com/redhat/thermostat/client/SummaryPanelFacade.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/SummaryPanelFacade.java	Mon Apr 30 11:44:05 2012 -0400
@@ -38,7 +38,7 @@
 
 import java.util.List;
 
-public interface SummaryPanelFacade extends AsyncUiFacade {
+public interface SummaryPanelFacade {
 
     public ChangeableText getTotalMonitoredVms();
 
@@ -46,4 +46,8 @@
 
     public List<String> getIssues();
 
+    void start();
+
+    void stop();
+
 }
--- a/client/src/main/java/com/redhat/thermostat/client/ui/AsyncFacadeManager.java	Thu Apr 26 13:32:33 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/*
- * 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.client.ui;
-
-import java.awt.Component;
-
-import com.redhat.thermostat.client.AsyncUiFacade;
-
-public class AsyncFacadeManager extends ComponentVisibleListener {
-
-    private AsyncUiFacade facade;
-
-    public AsyncFacadeManager(AsyncUiFacade facade) {
-        this.facade = facade;
-    }
-
-    @Override
-    public void componentHidden(Component component) {
-        facade.stop();
-    }
-
-    @Override
-    public void componentShown(Component component) {
-        facade.start();
-    }
-
-}
--- a/client/src/main/java/com/redhat/thermostat/client/ui/HostCpuController.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/HostCpuController.java	Mon Apr 30 11:44:05 2012 -0400
@@ -41,7 +41,10 @@
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
-import com.redhat.thermostat.client.AsyncUiFacade;
+import com.redhat.thermostat.client.ui.HostCpuView.Action;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.NotImplementedException;
 import com.redhat.thermostat.common.Timer;
 import com.redhat.thermostat.common.Timer.SchedulingType;
 import com.redhat.thermostat.common.appctx.ApplicationContext;
@@ -53,7 +56,7 @@
 import com.redhat.thermostat.common.model.DiscreteTimeData;
 import com.redhat.thermostat.common.model.HostInfo;
 
-public class HostCpuController implements AsyncUiFacade {
+public class HostCpuController {
 
     private final HostCpuView view;
     private final Timer backgroundUpdateTimer;
@@ -83,6 +86,23 @@
         backgroundUpdateTimer.setDelay(5);
         backgroundUpdateTimer.setTimeUnit(TimeUnit.SECONDS);
         backgroundUpdateTimer.setSchedulingType(SchedulingType.FIXED_RATE);
+
+        view.addActionListener(new ActionListener<HostCpuView.Action>() {
+            @Override
+            public void actionPerformed(ActionEvent<Action> actionEvent) {
+                switch (actionEvent.getActionId()) {
+                    case VISIBLE:
+                        start();
+                        break;
+                    case HIDDEN:
+                        stop();
+                        break;
+                    default:
+                        throw new NotImplementedException("unhandled action: " + actionEvent.getActionId());
+                }
+            }
+        });
+
     }
 
     // TODO: Consider doing this in a background thread (move to view and use SwingWorker or such).
@@ -95,13 +115,11 @@
         doCpuChartUpdate();
     }
 
-    @Override
-    public void start() {
+    private void start() {
         backgroundUpdateTimer.start();
     }
 
-    @Override
-    public void stop() {
+    private void stop() {
         backgroundUpdateTimer.stop();
     }
 
--- a/client/src/main/java/com/redhat/thermostat/client/ui/HostCpuPanel.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/HostCpuPanel.java	Mon Apr 30 11:44:05 2012 -0400
@@ -57,12 +57,16 @@
 import com.redhat.thermostat.client.locale.LocaleResources;
 import com.redhat.thermostat.client.ui.SimpleTable.Section;
 import com.redhat.thermostat.client.ui.SimpleTable.TableEntry;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ActionNotifier;
 import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public class HostCpuPanel extends JPanel implements HostCpuView {
 
     private static final long serialVersionUID = -1840585935194027332L;
 
+    private final ActionNotifier<Action> notifier = new ActionNotifier<>(this);
+
     private final ChangeableText cpuModel = new ChangeableText("");
     private final ChangeableText cpuCount = new ChangeableText("");
 
@@ -72,6 +76,27 @@
     public HostCpuPanel() {
         datasetCollection.addSeries(dataset);
         initializePanel();
+
+        addHierarchyListener(new ComponentVisibleListener() {
+            @Override
+            public void componentShown(Component component) {
+                notifier.fireAction(Action.VISIBLE);
+            }
+            @Override
+            public void componentHidden(Component component) {
+                notifier.fireAction(Action.HIDDEN);
+            }
+        });
+    }
+
+    @Override
+    public void addActionListener(ActionListener<Action> listener) {
+       notifier.addActionListener(listener);
+    }
+
+    @Override
+    public void removeActionListener(ActionListener<Action> listener) {
+        notifier.removeActionListener(listener);
     }
 
     @Override
--- a/client/src/main/java/com/redhat/thermostat/client/ui/HostCpuView.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/HostCpuView.java	Mon Apr 30 11:44:05 2012 -0400
@@ -39,11 +39,21 @@
 import java.awt.Component;
 import java.util.List;
 
+import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.View;
 import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public interface HostCpuView extends View {
 
+    enum Action {
+        VISIBLE,
+        HIDDEN,
+    }
+
+    void addActionListener(ActionListener<Action> listener);
+
+    void removeActionListener(ActionListener<Action> listener);
+
     void setCpuCount(String count);
 
     void setCpuModel(String model);
--- a/client/src/main/java/com/redhat/thermostat/client/ui/HostMemoryController.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/HostMemoryController.java	Mon Apr 30 11:44:05 2012 -0400
@@ -41,13 +41,16 @@
 import java.awt.Component;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Timer;
-import java.util.TimerTask;
 import java.util.concurrent.TimeUnit;
 
-import com.redhat.thermostat.client.AsyncUiFacade;
 import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.ui.HostMemoryView.Action;
 import com.redhat.thermostat.client.ui.HostMemoryView.GraphVisibilityChangeListener;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.NotImplementedException;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.Timer.SchedulingType;
 import com.redhat.thermostat.common.appctx.ApplicationContext;
 import com.redhat.thermostat.common.dao.DAOFactory;
 import com.redhat.thermostat.common.dao.HostInfoDAO;
@@ -57,7 +60,7 @@
 import com.redhat.thermostat.common.model.MemoryStat;
 import com.redhat.thermostat.common.model.MemoryType;
 
-public class HostMemoryController implements AsyncUiFacade {
+public class HostMemoryController {
 
     private final HostMemoryView view;
 
@@ -68,7 +71,7 @@
     private final Timer backgroundUpdateTimer;
     private final GraphVisibilityChangeListener listener = new ShowHideGraph();
 
-    public HostMemoryController(HostRef ref) {
+    public HostMemoryController(final HostRef ref) {
         this.ref = ref;
         DAOFactory daos = ApplicationContext.getInstance().getDAOFactory();
         hostInfoDAO = daos.getHostInfoDAO();
@@ -84,30 +87,46 @@
         view.addMemoryChart(MemoryType.BUFFERS.name(), localize(LocaleResources.HOST_BUFFERS));
 
         view.addGraphVisibilityListener(listener);
-
-        backgroundUpdateTimer = new Timer();
-    }
+        view.addActionListener(new ActionListener<HostMemoryView.Action>() {
+            @Override
+            public void actionPerformed(ActionEvent<Action> actionEvent) {
+                switch (actionEvent.getActionId()) {
+                    case HIDDEN:
+                        stopBackgroundUpdates();
+                        break;
+                    case VISIBLE:
+                        startBackgroundUpdates();
+                        break;
+                    default:
+                        throw new NotImplementedException("action event not handled: " + actionEvent.getActionId());
+                }
+            }
+        });
 
-    @Override
-    public void start() {
-        for (MemoryType type : MemoryType.values()) {
-            view.showMemoryChart(type.name());
-        }
-
-        backgroundUpdateTimer.scheduleAtFixedRate(new TimerTask() {
+        backgroundUpdateTimer = ApplicationContext.getInstance().getTimerFactory().createTimer();
+        backgroundUpdateTimer.setAction(new Runnable() {
             @Override
             public void run() {
                 view.setTotalMemory(String.valueOf(hostInfoDAO.getHostInfo(ref).getTotalMemory()));
                 doMemoryChartUpdate();
             }
-
-        }, 0, TimeUnit.SECONDS.toMillis(5));
-
+        });
+        backgroundUpdateTimer.setSchedulingType(SchedulingType.FIXED_RATE);
+        backgroundUpdateTimer.setTimeUnit(TimeUnit.SECONDS);
+        backgroundUpdateTimer.setInitialDelay(0);
+        backgroundUpdateTimer.setDelay(5);
     }
 
-    @Override
-    public void stop() {
-        backgroundUpdateTimer.cancel();
+    private void startBackgroundUpdates() {
+        for (MemoryType type : MemoryType.values()) {
+            view.showMemoryChart(type.name());
+        }
+
+        backgroundUpdateTimer.start();
+    }
+
+    private void stopBackgroundUpdates() {
+        backgroundUpdateTimer.stop();
         for (MemoryType type : MemoryType.values()) {
             view.hideMemoryChart(type.name());
         }
--- a/client/src/main/java/com/redhat/thermostat/client/ui/HostMemoryPanel.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/HostMemoryPanel.java	Mon Apr 30 11:44:05 2012 -0400
@@ -41,8 +41,6 @@
 import java.awt.BorderLayout;
 import java.awt.Component;
 import java.awt.FlowLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -63,12 +61,18 @@
 import com.redhat.thermostat.client.locale.LocaleResources;
 import com.redhat.thermostat.client.ui.SimpleTable.Section;
 import com.redhat.thermostat.client.ui.SimpleTable.TableEntry;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ActionNotifier;
 import com.redhat.thermostat.common.model.DiscreteTimeData;
 
-public class HostMemoryPanel extends JPanel implements HostMemoryView, ActionListener {
+public class HostMemoryPanel extends JPanel implements HostMemoryView {
 
     private static final long serialVersionUID = -6971357935957876582L;
 
+    private final ActionNotifier<Action> notifier = new ActionNotifier<Action>(this);
+
+    private final MemoryCheckboxListener memoryCheckboxListener = new MemoryCheckboxListener();
+
     private final ChangeableText totalMemory = new ChangeableText("");
 
     private final JPanel memoryCheckBoxPanel = new JPanel(new WrapLayout(FlowLayout.LEADING));
@@ -79,6 +83,17 @@
 
     public HostMemoryPanel() {
         initializePanel();
+
+        addHierarchyListener(new ComponentVisibleListener() {
+            @Override
+            public void componentShown(Component component) {
+                notifier.fireAction(Action.VISIBLE);
+            }
+            @Override
+            public void componentHidden(Component component) {
+                notifier.fireAction(Action.HIDDEN);
+            }
+        });
     }
 
     @Override
@@ -102,7 +117,7 @@
                 JCheckBox newCheckBox = new JCheckBox(humanReadableName);
                 newCheckBox.setActionCommand(tag);
                 newCheckBox.setSelected(true);
-                newCheckBox.addActionListener(HostMemoryPanel.this);
+                newCheckBox.addActionListener(memoryCheckboxListener);
                 checkBoxes.put(tag, newCheckBox);
                 memoryCheckBoxPanel.add(newCheckBox);
             }
@@ -181,6 +196,16 @@
         listeners.remove(listener);
     }
 
+    @Override
+    public void addActionListener(ActionListener<Action> listener) {
+        notifier.addActionListener(listener);
+    }
+
+    @Override
+    public void removeActionListener(ActionListener<Action> listener) {
+        notifier.removeActionListener(listener);
+    }
+
     private void initializePanel() {
         setLayout(new BorderLayout());
 
@@ -222,11 +247,6 @@
         return chart;
     }
 
-    @Override
-    public void actionPerformed(ActionEvent e) {
-        JCheckBox source = (JCheckBox) e.getSource();
-        fireShowHideHandlers(source.isSelected(), source.getActionCommand());
-    }
 
     private void fireShowHideHandlers(boolean show, String tag) {
         for (GraphVisibilityChangeListener listener: listeners) {
@@ -238,4 +258,12 @@
         }
     }
 
+    private class MemoryCheckboxListener implements java.awt.event.ActionListener {
+        @Override
+        public void actionPerformed(java.awt.event.ActionEvent e) {
+            JCheckBox source = (JCheckBox) e.getSource();
+            fireShowHideHandlers(source.isSelected(), source.getActionCommand());
+        }
+
+    }
 }
--- a/client/src/main/java/com/redhat/thermostat/client/ui/HostMemoryView.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/HostMemoryView.java	Mon Apr 30 11:44:05 2012 -0400
@@ -39,11 +39,17 @@
 import java.awt.Component;
 import java.util.List;
 
+import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.View;
 import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public interface HostMemoryView extends View {
 
+    enum Action {
+        VISIBLE,
+        HIDDEN,
+    }
+
     public interface GraphVisibilityChangeListener {
         public void show(String tag);
 
@@ -64,6 +70,10 @@
 
     void clearMemoryData(String tag);
 
+    void addActionListener(ActionListener<Action> listener);
+
+    void removeActionListener(ActionListener<Action> listener);
+
     void addGraphVisibilityListener(GraphVisibilityChangeListener listener);
 
     void removeGraphVisibilityListener(GraphVisibilityChangeListener listener);
--- a/client/src/main/java/com/redhat/thermostat/client/ui/HostOverviewController.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/HostOverviewController.java	Mon Apr 30 11:44:05 2012 -0400
@@ -41,8 +41,6 @@
 import java.awt.Component;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Timer;
-import java.util.TimerTask;
 import java.util.Vector;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
@@ -51,8 +49,13 @@
 
 import javax.swing.SwingWorker;
 
-import com.redhat.thermostat.client.AsyncUiFacade;
 import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.ui.HostOverviewView.Action;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.NotImplementedException;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.Timer.SchedulingType;
 import com.redhat.thermostat.common.appctx.ApplicationContext;
 import com.redhat.thermostat.common.dao.DAOFactory;
 import com.redhat.thermostat.common.dao.HostInfoDAO;
@@ -62,7 +65,7 @@
 import com.redhat.thermostat.common.model.NetworkInterfaceInfo;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 
-public class HostOverviewController implements AsyncUiFacade {
+public class HostOverviewController {
 
     private static final Logger logger = LoggingUtils.getLogger(HostOverviewController.class);
 
@@ -74,7 +77,7 @@
 
     private final HostOverviewView view;
 
-    public HostOverviewController(HostRef ref) {
+    public HostOverviewController(final HostRef ref) {
         this.ref = ref;
         DAOFactory df = ApplicationContext.getInstance().getDAOFactory();
         hostInfoDAO = df.getHostInfoDAO();
@@ -86,10 +89,45 @@
         networkTableColumnVector.add(localize(LocaleResources.NETWORK_IPV4_COLUMN));
         networkTableColumnVector.add(localize(LocaleResources.NETWORK_IPV6_COLUMN));
 
-        backgroundUpdateTimer = new Timer();
+        backgroundUpdateTimer = ApplicationContext.getInstance().getTimerFactory().createTimer();
+        backgroundUpdateTimer.setAction(new Runnable() {
+            @Override
+            public void run() {
+                HostInfo hostInfo = hostInfoDAO.getHostInfo(ref);
+                view.setHostName(hostInfo.getHostname());
+                view.setOsName(hostInfo.getOsName());
+                view.setOsKernel(hostInfo.getOsKernel());
+                view.setCpuModel(hostInfo.getCpuModel());
+                view.setCpuCount(String.valueOf(hostInfo.getCpuCount()));
+                view.setTotalMemory(String.valueOf(hostInfo.getTotalMemory()));
+
+                doNetworkTableUpdateAsync();
+            }
+        });
+        backgroundUpdateTimer.setSchedulingType(SchedulingType.FIXED_RATE);
+        backgroundUpdateTimer.setTimeUnit(TimeUnit.SECONDS);
+        backgroundUpdateTimer.setInitialDelay(0);
+        backgroundUpdateTimer.setDelay(5);
+
         view = ApplicationContext.getInstance().getViewFactory().getView(HostOverviewView.class);
 
         view.setNetworkTableColumns(networkTableColumnVector.toArray());
+
+        view.addActionListener(new ActionListener<Action>() {
+            @Override
+            public void actionPerformed(ActionEvent<Action> actionEvent) {
+                switch (actionEvent.getActionId()) {
+                    case HIDDEN:
+                        stop();
+                        break;
+                    case VISIBLE:
+                        start();
+                        break;
+                    default:
+                        throw new NotImplementedException("unhandled: " + actionEvent.getActionId());
+                }
+            }
+        });
     }
 
     private void doNetworkTableUpdateAsync() {
@@ -128,28 +166,12 @@
         }
     }
 
-    @Override
-    public void start() {
-        backgroundUpdateTimer.scheduleAtFixedRate(new TimerTask() {
-            @Override
-            public void run() {
-                HostInfo hostInfo = hostInfoDAO.getHostInfo(ref);
-                view.setHostName(hostInfo.getHostname());
-                view.setOsName(hostInfo.getOsName());
-                view.setOsKernel(hostInfo.getOsKernel());
-                view.setCpuModel(hostInfo.getCpuModel());
-                view.setCpuCount(String.valueOf(hostInfo.getCpuCount()));
-                view.setTotalMemory(String.valueOf(hostInfo.getTotalMemory()));
-
-                doNetworkTableUpdateAsync();
-            }
-        }, 0, TimeUnit.SECONDS.toMillis(5));
-
+    private void start() {
+        backgroundUpdateTimer.start();
     }
 
-    @Override
-    public void stop() {
-        backgroundUpdateTimer.cancel();
+    private void stop() {
+        backgroundUpdateTimer.stop();
     }
 
     public Component getComponent() {
--- a/client/src/main/java/com/redhat/thermostat/client/ui/HostOverviewPanel.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/HostOverviewPanel.java	Mon Apr 30 11:44:05 2012 -0400
@@ -54,11 +54,15 @@
 import com.redhat.thermostat.client.ui.SimpleTable.Section;
 import com.redhat.thermostat.client.ui.SimpleTable.TableEntry;
 import com.redhat.thermostat.client.ui.SimpleTable.Value;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ActionNotifier;
 
 public class HostOverviewPanel extends JPanel implements HostOverviewView {
 
     private static final long serialVersionUID = 1692529334143017953L;
 
+    private final ActionNotifier<Action> notifier = new ActionNotifier<>(this);
+
     private final ChangeableText hostname = new ChangeableText("");
     private final ChangeableText cpuModel = new ChangeableText("");
     private final ChangeableText cpuCount = new ChangeableText("");
@@ -66,12 +70,34 @@
     private final ChangeableText osName = new ChangeableText("");
     private final ChangeableText osKernel = new ChangeableText("");
 
-    private final DefaultTableModel networkTableModel = new DefaultTableModel();;
+    private final DefaultTableModel networkTableModel = new DefaultTableModel();
     private Object[] networkTableColumns;
     private Object[][] networkTableData;
 
     public HostOverviewPanel() {
         initializePanel();
+
+        addHierarchyListener(new ComponentVisibleListener() {
+            @Override
+            public void componentShown(Component component) {
+                notifier.fireAction(Action.VISIBLE);
+            }
+
+            @Override
+            public void componentHidden(Component component) {
+                notifier.fireAction(Action.HIDDEN);
+            }
+        });
+    }
+
+    @Override
+    public void addActionListener(ActionListener<Action> listener) {
+        notifier.addActionListener(listener);
+    }
+
+    @Override
+    public void removeActionListener(ActionListener<Action> listener) {
+        notifier.removeActionListener(listener);
     }
 
     @Override
--- a/client/src/main/java/com/redhat/thermostat/client/ui/HostOverviewView.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/HostOverviewView.java	Mon Apr 30 11:44:05 2012 -0400
@@ -38,10 +38,20 @@
 
 import java.awt.Component;
 
+import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.View;
 
 public interface HostOverviewView extends View {
 
+    enum Action {
+        VISIBLE,
+        HIDDEN,
+    }
+
+    void addActionListener(ActionListener<Action> listener);
+
+    void removeActionListener(ActionListener<Action> listener);
+
     void setHostName(String newHostName);
 
     void setCpuModel(String newCpuModel);
--- a/client/src/main/java/com/redhat/thermostat/client/ui/HostPanel.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/HostPanel.java	Mon Apr 30 11:44:05 2012 -0400
@@ -61,7 +61,6 @@
         this.facade = facade;
 
         init();
-        addHierarchyListener(new AsyncFacadeManager(facade));
     }
 
     private void init() {
--- a/client/src/main/java/com/redhat/thermostat/client/ui/MainWindow.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/MainWindow.java	Mon Apr 30 11:44:05 2012 -0400
@@ -44,6 +44,8 @@
 import java.awt.Dimension;
 import java.awt.Insets;
 import java.awt.event.ActionEvent;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
 import java.awt.event.InputEvent;
 import java.awt.event.KeyEvent;
 import java.awt.event.WindowAdapter;
@@ -252,6 +254,20 @@
 
         setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
         addWindowListener(shutdownAction);
+
+        addComponentListener(new ComponentAdapter() {
+
+            @Override
+            public void componentShown(ComponentEvent e) {
+                fireViewAction(Action.VISIBLE);
+            }
+
+            @Override
+            public void componentHidden(ComponentEvent e) {
+                fireViewAction(Action.HIDDEN);
+            }
+        });
+
     }
 
     private void setupMenus() {
@@ -307,7 +323,7 @@
             }
         });
         editMenu.add(configureClientMenuItem);
-        
+
         editMenu.addSeparator();
         JMenuItem historyModeMenuItem = new JCheckBoxMenuItem(localize(LocaleResources.MENU_EDIT_ENABLE_HISTORY_MODE));
         historyModeMenuItem.setName("historyModeSwitch");
@@ -318,7 +334,7 @@
                 fireViewAction(Action.SWITCH_HISTORY_MODE);
             }
         });
-        
+
         editMenu.add(historyModeMenuItem);
         JMenu helpMenu = new JMenu(localize(LocaleResources.MENU_HELP));
         helpMenu.getPopupMenu().setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1));
@@ -549,7 +565,7 @@
     public void showMainWindow() {
         try {
             new EdtHelper().callAndWait(new Runnable() {
-                
+
                 @Override
                 public void run() {
                     pack();
@@ -598,7 +614,7 @@
                 public String call() throws Exception {
                     return searchField.getText();
                 }
-                
+
             });
         } catch (InvocationTargetException e) {
             throw new RuntimeException(e);
--- a/client/src/main/java/com/redhat/thermostat/client/ui/SummaryPanel.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/SummaryPanel.java	Mon Apr 30 11:44:05 2012 -0400
@@ -39,6 +39,7 @@
 import static com.redhat.thermostat.client.locale.Translate.localize;
 
 import java.awt.BorderLayout;
+import java.awt.Component;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -59,7 +60,7 @@
 
     private final SummaryPanelFacade facade;
 
-    public SummaryPanel(SummaryPanelFacade facade) {
+    public SummaryPanel(final SummaryPanelFacade facade) {
         this.facade = facade;
 
         setLayout(new BorderLayout());
@@ -84,7 +85,17 @@
         issuesPanel.setBorder(Components.smallBorder());
         add(issuesPanel, BorderLayout.PAGE_END);
 
-        addHierarchyListener(new AsyncFacadeManager(facade));
+        addHierarchyListener(new ComponentVisibleListener() {
+            @Override
+            public void componentShown(Component component) {
+                facade.start();
+            }
+
+            @Override
+            public void componentHidden(Component component) {
+                facade.stop();
+            }
+        });
     }
 
     public JPanel createIssuesPanel() {
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmClassStatController.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmClassStatController.java	Mon Apr 30 11:44:05 2012 -0400
@@ -39,20 +39,23 @@
 import java.awt.Component;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Timer;
-import java.util.TimerTask;
 import java.util.concurrent.TimeUnit;
 
-import com.redhat.thermostat.client.AsyncUiFacade;
+import com.redhat.thermostat.client.ui.VmClassStatView.Action;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.NotImplementedException;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.Timer.SchedulingType;
 import com.redhat.thermostat.common.appctx.ApplicationContext;
 import com.redhat.thermostat.common.dao.VmClassStatDAO;
 import com.redhat.thermostat.common.dao.VmRef;
 import com.redhat.thermostat.common.model.DiscreteTimeData;
 import com.redhat.thermostat.common.model.VmClassStat;
 
-class VmClassStatController implements AsyncUiFacade {
+class VmClassStatController {
 
-    private class UpdateChartData extends TimerTask {
+    private class UpdateChartData implements Runnable {
         @Override
         public void run() {
             List<VmClassStat> latestClassStats = dao.getLatestClassStats(ref);
@@ -65,32 +68,47 @@
 
     }
 
-    private VmClassStatView classesView;
-    private VmRef ref;
-    private VmClassStatDAO dao;
-
-    // TODO: Use application wide ScheduledExecutorService thread pool.
-    private Timer timer;
+    private final VmClassStatView classesView;
+    private final VmRef ref;
+    private final VmClassStatDAO dao;
+    private final Timer timer;
 
     public VmClassStatController(VmRef ref) {
         this.ref = ref;
         dao = ApplicationContext.getInstance().getDAOFactory().getVmClassStatsDAO();
+        timer = ApplicationContext.getInstance().getTimerFactory().createTimer();
+
+        timer.setAction(new UpdateChartData());
+        timer.setSchedulingType(SchedulingType.FIXED_RATE);
+        timer.setTimeUnit(TimeUnit.SECONDS);
+        timer.setDelay(5);
+        timer.setInitialDelay(0);
+
         classesView = ApplicationContext.getInstance().getViewFactory().getView(VmClassStatView.class);
+
+        classesView.addActionListener(new ActionListener<VmClassStatView.Action>() {
+            @Override
+            public void actionPerformed(ActionEvent<Action> actionEvent) {
+                switch(actionEvent.getActionId()) {
+                    case HIDDEN:
+                        stop();
+                        break;
+                    case VISIBLE:
+                        start();
+                        break;
+                    default:
+                        throw new NotImplementedException("unknown action: " + actionEvent.getActionId());
+                }
+            }
+        });
     }
 
-    @Override
-    public void start() {
-        if (timer == null) {
-            timer = new Timer();
-        }
-        TimerTask updateTimerTask = new UpdateChartData();
-        timer.scheduleAtFixedRate(updateTimerTask, 0, TimeUnit.SECONDS.toMillis(5));
+    private void start() {
+        timer.start();
     }
 
-    @Override
-    public void stop() {
-        timer.cancel();
-        timer = null;
+    private void stop() {
+        timer.stop();
     }
 
     public Component getComponent() {
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmClassStatPanel.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmClassStatPanel.java	Mon Apr 30 11:44:05 2012 -0400
@@ -53,6 +53,8 @@
 import org.jfree.data.time.TimeSeriesCollection;
 
 import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ActionNotifier;
 import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public class VmClassStatPanel extends JPanel implements VmClassStatView {
@@ -61,6 +63,8 @@
 
     private final TimeSeriesCollection dataset = new TimeSeriesCollection();
 
+    private final ActionNotifier<Action> notifier = new ActionNotifier<Action>(this);
+
     public VmClassStatPanel() {
         // any name works
         dataset.addSeries(new TimeSeries("class-stat"));
@@ -80,6 +84,28 @@
         Component chartPanel = new RecentTimeSeriesChartPanel(new RecentTimeSeriesChartController(chart));
 
         add(chartPanel, BorderLayout.CENTER);
+
+        addHierarchyListener(new ComponentVisibleListener() {
+            @Override
+            public void componentShown(Component component) {
+                notifier.fireAction(Action.VISIBLE);
+            }
+
+            @Override
+            public void componentHidden(Component component) {
+                notifier.fireAction(Action.HIDDEN);
+            }
+        });
+    }
+
+    @Override
+    public void addActionListener(ActionListener<Action> listener) {
+        notifier.addActionListener(listener);
+    }
+
+    @Override
+    public void removeActionListener(ActionListener<Action> listener) {
+        notifier.addActionListener(listener);
     }
 
     @Override
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmClassStatView.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmClassStatView.java	Mon Apr 30 11:44:05 2012 -0400
@@ -39,11 +39,22 @@
 import java.awt.Component;
 import java.util.List;
 
+import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.View;
 import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public interface VmClassStatView extends View {
 
+    enum Action {
+        VISIBLE,
+        HIDDEN,
+    }
+
+    void addActionListener(ActionListener<Action> listener);
+
+    void removeActionListener(ActionListener<Action> listener);
+
+
     void clearClassCount();
 
     void addClassCount(List<DiscreteTimeData<Long>> data);
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmCpuController.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmCpuController.java	Mon Apr 30 11:44:05 2012 -0400
@@ -39,41 +39,65 @@
 import java.awt.Component;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Timer;
-import java.util.TimerTask;
 import java.util.concurrent.TimeUnit;
 
-import com.redhat.thermostat.client.AsyncUiFacade;
+import com.redhat.thermostat.client.ui.VmCpuView.Action;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.NotImplementedException;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.Timer.SchedulingType;
 import com.redhat.thermostat.common.appctx.ApplicationContext;
 import com.redhat.thermostat.common.dao.VmCpuStatDAO;
 import com.redhat.thermostat.common.dao.VmRef;
 import com.redhat.thermostat.common.model.DiscreteTimeData;
 import com.redhat.thermostat.common.model.VmCpuStat;
 
-class VmCpuController implements AsyncUiFacade {
+class VmCpuController {
 
     private final VmRef ref;
     private final VmCpuStatDAO dao;
     private final VmCpuView view;
 
-    private final Timer timer = new Timer();
+    private final Timer timer;
 
     public VmCpuController(VmRef ref) {
         this.ref = ref;
         dao = ApplicationContext.getInstance().getDAOFactory().getVmCpuStatDAO();
-        view = ApplicationContext.getInstance().getViewFactory().getView(VmCpuView.class);
-    }
+        timer = ApplicationContext.getInstance().getTimerFactory().createTimer();
 
-    @Override
-    public void start() {
-        timer.scheduleAtFixedRate(new TimerTask() {
+        timer.setAction(new Runnable() {
             @Override
             public void run() {
                 doUpdateVmCpuCharts();
             }
+        });
+        timer.setTimeUnit(TimeUnit.SECONDS);
+        timer.setDelay(5);
+        timer.setInitialDelay(0);
+        timer.setSchedulingType(SchedulingType.FIXED_RATE);
 
-        }, 0, TimeUnit.SECONDS.toMillis(5));
+        view = ApplicationContext.getInstance().getViewFactory().getView(VmCpuView.class);
 
+        view.addActionListener(new ActionListener<VmCpuView.Action>() {
+            @Override
+            public void actionPerformed(ActionEvent<Action> actionEvent) {
+                switch (actionEvent.getActionId()) {
+                    case HIDDEN:
+                        stop();
+                        break;
+                    case VISIBLE:
+                        start();
+                        break;
+                    default:
+                        throw new NotImplementedException("unknown event : " + actionEvent.getActionId());
+                }
+            }
+        });
+    }
+
+    private void start() {
+        timer.start();
     }
 
     private void doUpdateVmCpuCharts() {
@@ -88,9 +112,8 @@
         view.addData(toDisplay);
     }
 
-    @Override
-    public void stop() {
-        timer.cancel();
+    private void stop() {
+        timer.stop();
     }
 
     public Component getComponent() {
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmCpuPanel.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmCpuPanel.java	Mon Apr 30 11:44:05 2012 -0400
@@ -54,12 +54,16 @@
 import org.jfree.data.time.TimeSeriesCollection;
 
 import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ActionNotifier;
 import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public class VmCpuPanel extends JPanel implements VmCpuView {
 
     private static final long serialVersionUID = 6181274336251822530L;
 
+    private final ActionNotifier<Action> notifier = new ActionNotifier<>(this);
+
     private final TimeSeriesCollection data = new TimeSeriesCollection();
     private final TimeSeries cpuTimeSeries = new TimeSeries("cpu-stats");
 
@@ -67,6 +71,28 @@
         data.addSeries(cpuTimeSeries);
 
         initializePanel();
+
+        addHierarchyListener(new ComponentVisibleListener() {
+            @Override
+            public void componentShown(Component component) {
+                notifier.fireAction(Action.VISIBLE);
+            }
+
+            @Override
+            public void componentHidden(Component component) {
+                notifier.fireAction(Action.HIDDEN);
+            }
+        });
+    }
+
+    @Override
+    public void addActionListener(ActionListener<Action> listener) {
+        notifier.addActionListener(listener);
+    }
+
+    @Override
+    public void removeActionListener(ActionListener<Action> listener) {
+        notifier.removeActionListener(listener);
     }
 
     @Override
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmCpuView.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmCpuView.java	Mon Apr 30 11:44:05 2012 -0400
@@ -39,11 +39,21 @@
 import java.awt.Component;
 import java.util.List;
 
+import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.View;
 import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public interface VmCpuView extends View {
 
+    enum Action {
+        VISIBLE,
+        HIDDEN,
+    }
+
+    void addActionListener(ActionListener<Action> listener);
+
+    void removeActionListener(ActionListener<Action> listener);
+
     void addData(List<DiscreteTimeData<? extends Number>> data);
 
     void clearData();
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmGcController.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmGcController.java	Mon Apr 30 11:44:05 2012 -0400
@@ -44,13 +44,16 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.Timer;
-import java.util.TimerTask;
 import java.util.TreeSet;
 import java.util.concurrent.TimeUnit;
 
-import com.redhat.thermostat.client.AsyncUiFacade;
 import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.ui.VmGcView.Action;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.NotImplementedException;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.Timer.SchedulingType;
 import com.redhat.thermostat.common.appctx.ApplicationContext;
 import com.redhat.thermostat.common.dao.DAOFactory;
 import com.redhat.thermostat.common.dao.VmGcStatDAO;
@@ -61,7 +64,7 @@
 import com.redhat.thermostat.common.model.VmMemoryStat;
 import com.redhat.thermostat.common.model.VmMemoryStat.Generation;
 
-class VmGcController implements AsyncUiFacade {
+class VmGcController {
 
     private final VmRef ref;
     private final VmGcView view;
@@ -71,35 +74,51 @@
 
     private final Set<String> addedCollectors = new TreeSet<String>();
 
-    private final Timer timer = new Timer();
+    private final Timer timer;
 
     public VmGcController(VmRef ref) {
         this.ref = ref;
         this.view = ApplicationContext.getInstance().getViewFactory().getView(VmGcView.class);
+        this.timer = ApplicationContext.getInstance().getTimerFactory().createTimer();
 
         DAOFactory df = ApplicationContext.getInstance().getDAOFactory();
         gcDao = df.getVmGcStatDAO();
         memDao = df.getVmMemoryStatDAO();
-    }
 
-    @Override
-    public void start() {
-        timer.scheduleAtFixedRate(new TimerTask() {
+        view.addActionListener(new ActionListener<VmGcView.Action>() {
+            @Override
+            public void actionPerformed(ActionEvent<Action> actionEvent) {
+                switch (actionEvent.getActionId()) {
+                    case HIDDEN:
+                        stop();
+                        break;
+                    case VISIBLE:
+                        start();
+                        break;
+                    default:
+                        throw new NotImplementedException("unkonwn action: " + actionEvent.getActionId());
+                }
+            }
+        });
+
+        timer.setAction(new Runnable() {
             @Override
             public void run() {
                 doUpdateCollectorData();
             }
-
-        }, 0, TimeUnit.SECONDS.toMillis(5));
+        });
+        timer.setSchedulingType(SchedulingType.FIXED_RATE);
+        timer.setInitialDelay(0);
+        timer.setDelay(5);
+        timer.setTimeUnit(TimeUnit.SECONDS);
     }
 
-    @Override
-    public void stop() {
-        for (String name: addedCollectors) {
-            view.removeChart(name);
-        }
-        addedCollectors.clear();
-        timer.cancel();
+    private void start() {
+        timer.start();
+    }
+
+    private void stop() {
+         timer.stop();
     }
 
     // FIXME
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmGcPanel.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmGcPanel.java	Mon Apr 30 11:44:05 2012 -0400
@@ -57,12 +57,16 @@
 import org.jfree.data.time.TimeSeriesCollection;
 
 import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ActionNotifier;
 import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public class VmGcPanel extends JPanel implements VmGcView {
 
     private static final long serialVersionUID = -4924051863887499866L;
 
+    private final ActionNotifier<Action> notifier = new ActionNotifier<>(this);
+
     private final Map<String, TimeSeriesCollection> dataset = new HashMap<>();
     private final Map<String, JPanel> subPanels = new HashMap<>();
 
@@ -77,6 +81,28 @@
         gcPanelConstraints.fill = GridBagConstraints.BOTH;
         gcPanelConstraints.weightx = 1;
         gcPanelConstraints.weighty = 1;
+
+        addHierarchyListener(new ComponentVisibleListener() {
+            @Override
+            public void componentShown(Component component) {
+                notifier.fireAction(Action.VISIBLE);
+            }
+
+            @Override
+            public void componentHidden(Component component) {
+                notifier.fireAction(Action.HIDDEN);
+            }
+        });
+    }
+
+    @Override
+    public void addActionListener(ActionListener<Action> listener) {
+        notifier.addActionListener(listener);
+    }
+
+    @Override
+    public void removeActionListener(ActionListener<Action> listener) {
+        notifier.removeActionListener(listener);
     }
 
     @Override
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmGcView.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmGcView.java	Mon Apr 30 11:44:05 2012 -0400
@@ -39,11 +39,21 @@
 import java.awt.Component;
 import java.util.List;
 
+import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.View;
 import com.redhat.thermostat.common.model.DiscreteTimeData;
 
 public interface VmGcView extends View {
 
+    enum Action {
+        VISIBLE,
+        HIDDEN,
+    }
+
+    void addActionListener(ActionListener<Action> listener);
+
+    void removeActionListener(ActionListener<Action> listener);
+
     void addChart(String tag, String title);
 
     void removeChart(String tag);
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmInformationController.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmInformationController.java	Mon Apr 30 11:44:05 2012 -0400
@@ -40,12 +40,11 @@
 
 import java.awt.Component;
 
-import com.redhat.thermostat.client.AsyncUiFacade;
 import com.redhat.thermostat.client.locale.LocaleResources;
 import com.redhat.thermostat.common.appctx.ApplicationContext;
 import com.redhat.thermostat.common.dao.VmRef;
 
-public class VmInformationController implements AsyncUiFacade {
+public class VmInformationController {
 
     private final VmInformationView view;
 
@@ -69,39 +68,21 @@
         view.addChildView(localize(LocaleResources.VM_INFO_TAB_MEMORY), memoryController.getComponent());
         view.addChildView(localize(LocaleResources.VM_INFO_TAB_GC), gcController.getComponent());
         view.addChildView(localize(LocaleResources.VM_INFO_TAB_CLASSES), classesController.getComponent());
-    }
 
-    @Override
-    public void start() {
-        overviewController.start();
-        cpuController.start();
-        memoryController.start();
-        gcController.start();
-        classesController.start();
-
-    }
-
-    @Override
-    public void stop() {
-        overviewController.stop();
-        cpuController.stop();
-        memoryController.stop();
-        gcController.stop();
-        classesController.stop();
     }
 
     public Component getComponent() {
         return view.getUiComponent();
     }
-    
+
     public int getSelectedChildID() {
         return view.getSelectedChildID();
     }
-    
+
     public void selectChildID(int id) {
         view.selectChildID(id);
     }
-    
+
     public int getNumChildren() {
         return view.getNumChildren();
     }
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmInformationPanel.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmInformationPanel.java	Mon Apr 30 11:44:05 2012 -0400
@@ -70,12 +70,12 @@
     public int getSelectedChildID() {
         return tabPane.getSelectedIndex();
     }
-    
+
     @Override
     public void selectChildID(int id) {
         tabPane.setSelectedIndex(id);
     }
-    
+
     @Override
     public int getNumChildren() {
         return tabPane.getComponentCount();
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmMemoryController.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmMemoryController.java	Mon Apr 30 11:44:05 2012 -0400
@@ -43,8 +43,11 @@
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
-import com.redhat.thermostat.client.AsyncUiFacade;
 import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.ui.VmMemoryView.Action;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.NotImplementedException;
 import com.redhat.thermostat.common.Timer;
 import com.redhat.thermostat.common.Timer.SchedulingType;
 import com.redhat.thermostat.common.appctx.ApplicationContext;
@@ -54,7 +57,7 @@
 import com.redhat.thermostat.common.model.VmMemoryStat.Generation;
 import com.redhat.thermostat.common.model.VmMemoryStat.Space;
 
-class VmMemoryController implements AsyncUiFacade {
+class VmMemoryController {
 
     private final VmMemoryView view;
     private final VmMemoryStatDAO dao;
@@ -94,18 +97,34 @@
             }
         });
         timer.setInitialDelay(0);
-        timer.setDelay(10);
-        timer.setTimeUnit(TimeUnit.MILLISECONDS);
+        timer.setDelay(1);
+        timer.setTimeUnit(TimeUnit.SECONDS);
         timer.setSchedulingType(SchedulingType.FIXED_RATE);
+
+        view.addActionListener(new ActionListener<VmMemoryView.Action>() {
+
+            @Override
+            public void actionPerformed(ActionEvent<Action> actionEvent) {
+                switch(actionEvent.getActionId()) {
+                    case HIDDEN:
+                        stop();
+                        break;
+                    case VISIBLE:
+                        start();
+                        break;
+                    default:
+                        throw new NotImplementedException("unknown event: " + actionEvent.getActionId());
+                }
+            }
+        });
+
     }
 
-    @Override
-    public void start() {
+    private void start() {
         timer.start();
     }
 
-    @Override
-    public void stop() {
+    private void stop() {
         timer.stop();
     }
 
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmMemoryPanel.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmMemoryPanel.java	Mon Apr 30 11:44:05 2012 -0400
@@ -50,11 +50,15 @@
 import javax.swing.SwingUtilities;
 
 import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ActionNotifier;
 
 public class VmMemoryPanel extends JPanel implements VmMemoryView {
 
     private static final long serialVersionUID = -2882890932814218436L;
 
+    private final ActionNotifier<Action> notifier = new ActionNotifier<>(this);
+
     private final Map<String, MemorySpacePanel> regions = new HashMap<>();
 
     private final JPanel currentRegionSizePanel;
@@ -89,6 +93,28 @@
         currentRegionSizePanel.setLayout(new BoxLayout(currentRegionSizePanel, BoxLayout.PAGE_AXIS));
         setLayout(groupLayout);
 
+
+        addHierarchyListener(new ComponentVisibleListener() {
+            @Override
+            public void componentShown(Component component) {
+                notifier.fireAction(Action.VISIBLE);
+            }
+
+            @Override
+            public void componentHidden(Component component) {
+                notifier.fireAction(Action.HIDDEN);
+            }
+        });
+    }
+
+    @Override
+    public void addActionListener(ActionListener<Action> listener) {
+        notifier.addActionListener(listener);
+    }
+
+    @Override
+    public void removeActionListener(ActionListener<Action> listener) {
+        notifier.removeActionListener(listener);
     }
 
     @Override
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmMemoryView.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmMemoryView.java	Mon Apr 30 11:44:05 2012 -0400
@@ -38,10 +38,20 @@
 
 import java.awt.Component;
 
+import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.View;
 
 public interface VmMemoryView extends View {
 
+    enum Action {
+        VISIBLE,
+        HIDDEN,
+    }
+
+    void addActionListener(ActionListener<Action> listener);
+
+    void removeActionListener(ActionListener<Action> listener);
+
     void addRegion(String humanReadableName);
 
     void removeAllRegions();
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmOverviewController.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmOverviewController.java	Mon Apr 30 11:44:05 2012 -0400
@@ -41,18 +41,21 @@
 import java.awt.Component;
 import java.text.DateFormat;
 import java.util.Date;
-import java.util.Timer;
-import java.util.TimerTask;
 import java.util.concurrent.TimeUnit;
 
-import com.redhat.thermostat.client.AsyncUiFacade;
 import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.ui.VmOverviewView.Action;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.NotImplementedException;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.Timer.SchedulingType;
 import com.redhat.thermostat.common.appctx.ApplicationContext;
 import com.redhat.thermostat.common.dao.VmInfoDAO;
 import com.redhat.thermostat.common.dao.VmRef;
 import com.redhat.thermostat.common.model.VmInfo;
 
-class VmOverviewController implements AsyncUiFacade {
+class VmOverviewController {
 
     private final VmRef ref;
     private final VmInfoDAO dao;
@@ -67,14 +70,27 @@
         this.view = ApplicationContext.getInstance().getViewFactory().getView(VmOverviewView.class);
 
         dao = ApplicationContext.getInstance().getDAOFactory().getVmInfoDAO();
+        timer = ApplicationContext.getInstance().getTimerFactory().createTimer();
 
         vmRunningTimeFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.FULL);
-        timer = new Timer();
-    }
 
-    @Override
-    public void start() {
-        timer.scheduleAtFixedRate(new TimerTask() {
+        view.addActionListener(new ActionListener<VmOverviewView.Action>() {
+            @Override
+            public void actionPerformed(ActionEvent<Action> actionEvent) {
+                switch(actionEvent.getActionId()) {
+                    case HIDDEN:
+                        stop();
+                        break;
+                    case VISIBLE:
+                        start();
+                        break;
+                    default:
+                        throw new NotImplementedException("unknown event: " + actionEvent.getActionId());
+                }
+            }
+        });
+
+        timer.setAction(new Runnable() {
 
             @Override
             public void run() {
@@ -100,14 +116,19 @@
                         actualVmName, actualVmVersion));
                 view.setVmArguments(info.getVmArguments());
             }
-
-        }, 0, TimeUnit.SECONDS.toMillis(5));
-
+        });
+        timer.setInitialDelay(0);
+        timer.setDelay(5);
+        timer.setTimeUnit(TimeUnit.SECONDS);
+        timer.setSchedulingType(SchedulingType.FIXED_RATE);
     }
 
-    @Override
-    public void stop() {
-        timer.cancel();
+    private void start() {
+        timer.start();
+    }
+
+    private void stop() {
+        timer.stop();
     }
 
     public Component getComponent() {
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmOverviewPanel.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmOverviewPanel.java	Mon Apr 30 11:44:05 2012 -0400
@@ -49,11 +49,15 @@
 import com.redhat.thermostat.client.locale.LocaleResources;
 import com.redhat.thermostat.client.ui.SimpleTable.Section;
 import com.redhat.thermostat.client.ui.SimpleTable.TableEntry;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ActionNotifier;
 
 public class VmOverviewPanel extends JPanel implements VmOverviewView {
 
     private static final long serialVersionUID = 3280274963512229970L;
 
+    private final ActionNotifier<Action> notifier = new ActionNotifier<>(this);
+
     private final ChangeableText pid = new ChangeableText("");
     private final ChangeableText startTimeStamp = new ChangeableText("");
     private final ChangeableText stopTimeStamp = new ChangeableText("");
@@ -66,6 +70,27 @@
 
     public VmOverviewPanel() {
         initializePanel();
+        addHierarchyListener(new ComponentVisibleListener() {
+            @Override
+            public void componentShown(Component component) {
+                notifier.fireAction(Action.VISIBLE);
+            }
+
+            @Override
+            public void componentHidden(Component component) {
+                notifier.fireAction(Action.HIDDEN);
+            }
+        });
+    }
+
+    @Override
+    public void addActionListener(ActionListener<Action> listener) {
+        notifier.addActionListener(listener);
+    }
+
+    @Override
+    public void removeActionListener(ActionListener<Action> listener) {
+        notifier.removeActionListener(listener);
     }
 
     @Override
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmOverviewView.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmOverviewView.java	Mon Apr 30 11:44:05 2012 -0400
@@ -38,10 +38,20 @@
 
 import java.awt.Component;
 
+import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.View;
 
 public interface VmOverviewView extends View {
 
+    enum Action {
+        VISIBLE,
+        HIDDEN,
+    }
+
+    void addActionListener(ActionListener<Action> listener);
+
+    void removeActionListener(ActionListener<Action> listener);
+
     void setVmPid(String pid);
 
     void setVmStartTimeStamp(String timestamp);
--- a/client/src/test/java/com/redhat/thermostat/client/MainWindowControllerImplTest.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/test/java/com/redhat/thermostat/client/MainWindowControllerImplTest.java	Mon Apr 30 11:44:05 2012 -0400
@@ -79,7 +79,7 @@
     private MainWindowControllerImpl controller;
 
     private UiFacadeFactory uiFacadeFactory;
-    
+
     private MainView view;
 
     private Timer mainWindowTimer;
@@ -102,7 +102,7 @@
 
         uiFacadeFactory = mock(UiFacadeFactory.class);
         when(uiFacadeFactory.getSummaryPanel()).thenReturn(summaryPanelFacade);
-        
+
         setupDAOs();
 
         view = mock(MainView.class);
@@ -136,9 +136,9 @@
     }
 
     @Test
-    public void verifyThatShutdownEventStopsController() {
+    public void verifyThatHiddenEventStopsController() {
 
-        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.SHUTDOWN));
+        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HIDDEN));
 
         verify(mainWindowTimer).stop();
 
@@ -156,7 +156,9 @@
     }
 
     @Test
-    public void verifyTimerGetsStartedOnConstruction() {
+    public void verifyTimerGetsStartedOnBecomingVisible() {
+        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.VISIBLE));
+
         verify(mainWindowTimer).setDelay(3);
         verify(mainWindowTimer).setTimeUnit(TimeUnit.SECONDS);
         verify(mainWindowTimer).setSchedulingType(SchedulingType.FIXED_RATE);
@@ -168,7 +170,7 @@
         controller.showMainMainWindow();
         verify(view).showMainWindow();
     }
-    
+
     @Test
     public void verifyUpdateHostsVMsLoadsCorrectHosts() {
 
@@ -194,29 +196,29 @@
         Collection<HostRef> liveHost = new ArrayList<>();
         liveHost.add(new HostRef("123", "fluffhost1"));
         liveHost.add(new HostRef("456", "fluffhost2"));
-        
+
         Collection<HostRef> allHosts = new ArrayList<>();
         allHosts.addAll(liveHost);
         allHosts.add(new HostRef("789", "fluffhost3"));
-        
+
         when(mockHostsDAO.getAliveHosts()).thenReturn(liveHost);
         when(mockHostsDAO.getHosts()).thenReturn(allHosts);
-        
+
         controller.doUpdateTreeAsync();
-        
+
         ArgumentCaptor<HostsVMsLoader> arg = ArgumentCaptor.forClass(HostsVMsLoader.class);
         verify(view).updateTree(anyString(), arg.capture());
         HostsVMsLoader loader = arg.getValue();
 
         Collection<HostRef> actualHosts = loader.getHosts();
         assertEqualCollection(liveHost, actualHosts);
-        
+
         l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.SWITCH_HISTORY_MODE));
-        
+
         actualHosts = loader.getHosts();
         assertEqualCollection(allHosts, actualHosts);
     }
-    
+
     @Test
     public void verifyUpdateHostsVMsLoadsCorrectVMs() {
 
@@ -241,7 +243,7 @@
         assertEquals(expected.size(), actual.size());
         assertTrue(expected.containsAll(actual));
     }
-    
+
     @Test
     @Bug(id="954",
          summary="Thermostat GUI client should remember my last panel selected",
@@ -250,28 +252,28 @@
 
         VmRef vmRef = mock(VmRef.class);
         when(view.getSelectedHostOrVm()).thenReturn(vmRef);
-                
+
         VmInformationController vmInformationController = mock(VmInformationController.class);
         when(vmInformationController.getSelectedChildID()).thenReturn(3);
         when(uiFacadeFactory.getVmController(any(VmRef.class))).thenReturn(vmInformationController);
-        
+
         l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_SELECTION_CHANGED));
-        
+
         ArgumentCaptor<Integer> arg = ArgumentCaptor.forClass(Integer.class);
         verify(vmInformationController).selectChildID(arg.capture());
         verify(vmInformationController, times(0)).getSelectedChildID();
-        
+
         int id = arg.getValue();
-        
+
         assertEquals(0, id);
-        
+
         l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_SELECTION_CHANGED));
-        
+
         arg = ArgumentCaptor.forClass(Integer.class);
         verify(vmInformationController, times(1)).getSelectedChildID();
         verify(vmInformationController, times(2)).selectChildID(arg.capture());
         id = arg.getValue();
-        
+
         assertEquals(3, id);
     }
 }
--- a/client/src/test/java/com/redhat/thermostat/client/ui/HostCpuControllerTest.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/test/java/com/redhat/thermostat/client/ui/HostCpuControllerTest.java	Mon Apr 30 11:44:05 2012 -0400
@@ -56,8 +56,10 @@
 
 import com.redhat.thermostat.client.ui.HostCpuController;
 import com.redhat.thermostat.client.ui.HostCpuView;
+import com.redhat.thermostat.common.ActionEvent;
 import com.redhat.thermostat.common.Timer;
 import com.redhat.thermostat.common.Timer.SchedulingType;
+import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.TimerFactory;
 import com.redhat.thermostat.common.ViewFactory;
 import com.redhat.thermostat.common.appctx.ApplicationContext;
@@ -78,6 +80,7 @@
 
     private Timer timer;
 
+    private ActionListener<HostCpuView.Action> viewListener;
     private Runnable timerAction;
 
     @Before
@@ -108,7 +111,10 @@
 
         ApplicationContext.getInstance().setDAOFactory(daoFactory);
 
+        // Set up View
         view = mock(HostCpuView.class);
+        ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(view).addActionListener(viewArgumentCaptor.capture());
         ViewFactory viewFactory = mock(ViewFactory.class);
         when(viewFactory.getView(eq(HostCpuView.class))).thenReturn(view);
 
@@ -118,6 +124,7 @@
         controller = new HostCpuController(host);
 
         timerAction = actionCaptor.getValue();
+        viewListener = viewArgumentCaptor.getValue();
     }
 
     @After
@@ -131,7 +138,7 @@
 
     @Test
     public void testTimer() {
-        controller.start();
+        viewListener.actionPerformed(new ActionEvent<>(view, HostCpuView.Action.VISIBLE));
 
         verify(timer).setAction(isNotNull(Runnable.class));
         verify(timer).setDelay(5);
@@ -140,7 +147,7 @@
         verify(timer).setSchedulingType(SchedulingType.FIXED_RATE);
         verify(timer).start();
 
-        controller.stop();
+        viewListener.actionPerformed(new ActionEvent<>(view, HostCpuView.Action.HIDDEN));
 
         verify(timer).stop();
     }
--- a/client/src/test/java/com/redhat/thermostat/client/ui/HostMemoryControllerTest.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/test/java/com/redhat/thermostat/client/ui/HostMemoryControllerTest.java	Mon Apr 30 11:44:05 2012 -0400
@@ -38,8 +38,9 @@
 
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.atLeast;
+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;
 
@@ -48,7 +49,12 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
 
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.TimerFactory;
 import com.redhat.thermostat.common.ViewFactory;
 import com.redhat.thermostat.common.appctx.ApplicationContext;
 import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
@@ -85,24 +91,39 @@
         when(daoFactory.getMemoryStatDAO()).thenReturn(memoryStatDAO);
         ApplicationContext.getInstance().setDAOFactory(daoFactory);
 
+        Timer timer = mock(Timer.class);
+        ArgumentCaptor<Runnable> timerActionCaptor = ArgumentCaptor.forClass(Runnable.class);
+        doNothing().when(timer).setAction(timerActionCaptor.capture());
+
+        TimerFactory timerFactory = mock(TimerFactory.class);
+        when(timerFactory.createTimer()).thenReturn(timer);
+        ApplicationContext.getInstance().setTimerFactory(timerFactory);
+
         HostRef ref = mock(HostRef.class);
+
         HostMemoryView view = mock(HostMemoryView.class);
+        ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(view).addActionListener(viewArgumentCaptor.capture());
+
         ViewFactory viewFactory = mock(ViewFactory.class);
         when(viewFactory.getView(eq(HostMemoryView.class))).thenReturn(view);
         ApplicationContext.getInstance().setViewFactory(viewFactory);
 
         HostMemoryController controller = new HostMemoryController(ref);
 
-        controller.start();
+        ActionListener<HostMemoryView.Action> l = viewArgumentCaptor.getValue();
+
+        l.actionPerformed(new ActionEvent<>(view, HostMemoryView.Action.VISIBLE));
+
+        verify(timer).start();
+        timerActionCaptor.getValue().run();
 
-        try {
-            Thread.sleep(500);
-        } catch (InterruptedException e) {
-            // Get out of here ASAP.
-            return;
-        }
+        verify(view, times(1)).setTotalMemory(any(String.class));
+        verify(view, times(6)).addMemoryData(any(String.class), any(List.class));
 
-        verify(view, atLeast(1)).setTotalMemory(any(String.class));
-        verify(view, atLeast(6)).addMemoryData(any(String.class), any(List.class));
+        l.actionPerformed(new ActionEvent<>(view, HostMemoryView.Action.HIDDEN));
+
+        verify(timer).stop();
+
     }
 }
--- a/client/src/test/java/com/redhat/thermostat/client/ui/VmClassStatControllerTest.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/test/java/com/redhat/thermostat/client/ui/VmClassStatControllerTest.java	Mon Apr 30 11:44:05 2012 -0400
@@ -38,7 +38,7 @@
 
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -47,9 +47,14 @@
 import java.util.List;
 
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
 
 import com.redhat.thermostat.client.ui.VmClassStatController;
 import com.redhat.thermostat.client.ui.VmClassStatView;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.TimerFactory;
 import com.redhat.thermostat.common.ViewFactory;
 import com.redhat.thermostat.common.appctx.ApplicationContext;
 import com.redhat.thermostat.common.dao.DAOFactory;
@@ -77,7 +82,17 @@
         ApplicationContext.getInstance().setDAOFactory(daoFactory);
         VmRef ref = mock(VmRef.class);
 
+        Timer timer = mock(Timer.class);
+        ArgumentCaptor<Runnable> timerActionCaptor = ArgumentCaptor.forClass(Runnable.class);
+        doNothing().when(timer).setAction(timerActionCaptor.capture());
+
+        TimerFactory timerFactory = mock(TimerFactory.class);
+        when(timerFactory.createTimer()).thenReturn(timer);
+        ApplicationContext.getInstance().setTimerFactory(timerFactory);
+
         VmClassStatView view = mock(VmClassStatView.class);
+        ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(view).addActionListener(viewArgumentCaptor.capture());
         ViewFactory viewFactory = mock(ViewFactory.class);
         when(viewFactory.getView(eq(VmClassStatView.class))).thenReturn(view);
 
@@ -85,17 +100,17 @@
 
         VmClassStatController controller = new VmClassStatController(ref);
 
-        controller.start();
+        ActionListener<VmClassStatView.Action> l = viewArgumentCaptor.getValue();
+
+        l.actionPerformed(new ActionEvent<>(view, VmClassStatView.Action.VISIBLE));
 
-        try {
-            Thread.sleep(500);
-        } catch (InterruptedException e) {
-            // Get out of here ASAP.
-            return;
-        }
+        verify(timer).start();
+        timerActionCaptor.getValue().run();
+        verify(view).addClassCount(any(List.class));
 
-        verify(view, atLeast(1)).addClassCount(any(List.class));
-        // We don't verify atMost() since we might increase the update rate in the future.
+        l.actionPerformed(new ActionEvent<>(view, VmClassStatView.Action.HIDDEN));
+
+        verify(timer).stop();
     }
 
 }
--- a/client/src/test/java/com/redhat/thermostat/client/ui/VmCpuControllerTest.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/test/java/com/redhat/thermostat/client/ui/VmCpuControllerTest.java	Mon Apr 30 11:44:05 2012 -0400
@@ -38,7 +38,7 @@
 
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -48,7 +48,12 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
 
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.TimerFactory;
 import com.redhat.thermostat.common.ViewFactory;
 import com.redhat.thermostat.common.appctx.ApplicationContext;
 import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
@@ -83,7 +88,17 @@
         ApplicationContext.getInstance().setDAOFactory(daoFactory);
         VmRef ref = mock(VmRef.class);
 
+        Timer timer = mock(Timer.class);
+        ArgumentCaptor<Runnable> timerActionCaptor = ArgumentCaptor.forClass(Runnable.class);
+        doNothing().when(timer).setAction(timerActionCaptor.capture());
+
+        TimerFactory timerFactory = mock(TimerFactory.class);
+        when(timerFactory.createTimer()).thenReturn(timer);
+        ApplicationContext.getInstance().setTimerFactory(timerFactory);
+
         final VmCpuView view = mock(VmCpuView.class);
+        ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(view).addActionListener(viewArgumentCaptor.capture());
         ViewFactory viewFactory = mock(ViewFactory.class);
         when(viewFactory.getView(eq(VmCpuView.class))).thenReturn(view);
 
@@ -91,16 +106,19 @@
 
         VmCpuController controller = new VmCpuController(ref);
 
-        controller.start();
+        ActionListener<VmCpuView.Action> l = viewArgumentCaptor.getValue();
+
+        l.actionPerformed(new ActionEvent<>(view, VmCpuView.Action.VISIBLE));
+
+        verify(timer).start();
 
-        try {
-            Thread.sleep(500);
-        } catch (InterruptedException e) {
-            // Get out of here ASAP.
-            return;
-        }
+        timerActionCaptor.getValue().run();
+
+        l.actionPerformed(new ActionEvent<>(viewFactory, VmCpuView.Action.HIDDEN));
 
-        verify(view, atLeast(1)).addData(any(List.class));
+        verify(timer).stop();
+
+        verify(view).addData(any(List.class));
         // We don't verify atMost() since we might increase the update rate in the future.
     }
 }
--- a/client/src/test/java/com/redhat/thermostat/client/ui/VmMemoryControllerTest.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/client/src/test/java/com/redhat/thermostat/client/ui/VmMemoryControllerTest.java	Mon Apr 30 11:44:05 2012 -0400
@@ -51,10 +51,11 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
-import org.mockito.Mockito;
 
+import com.redhat.thermostat.common.ActionEvent;
 import com.redhat.thermostat.common.Timer;
 import com.redhat.thermostat.common.Timer.SchedulingType;
+import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.TimerFactory;
 import com.redhat.thermostat.common.ViewFactory;
 import com.redhat.thermostat.common.appctx.ApplicationContext;
@@ -78,6 +79,7 @@
     private Generation gen;
     private VmMemoryController controller;
     private VmMemoryView view;
+    private ActionListener<VmMemoryView.Action> viewListener;
     private Runnable timerAction;
 
 
@@ -119,6 +121,9 @@
 
         // Setup view
         view = mock(VmMemoryView.class);
+        ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(view).addActionListener(viewArgumentCaptor.capture());
+
         ViewFactory viewFactory = mock(ViewFactory.class);
         when(viewFactory.getView(eq(VmMemoryView.class))).thenReturn(view);
         ApplicationContext.getInstance().setViewFactory(viewFactory);
@@ -128,6 +133,7 @@
 
         controller = new VmMemoryController(ref);
         timerAction = actionCaptor.getValue();
+        viewListener = viewArgumentCaptor.getValue();
 
     }
 
@@ -139,12 +145,12 @@
     @Test
     public void testTimer() {
 
-        controller.start();
+        viewListener.actionPerformed(new ActionEvent<>(view, VmMemoryView.Action.VISIBLE));
 
         verify(timer).start();
         verify(timer).setSchedulingType(SchedulingType.FIXED_RATE);
 
-        controller.stop();
+        viewListener.actionPerformed(new ActionEvent<>(view, VmMemoryView.Action.HIDDEN));
 
         verify(timer).stop();
     }
--- a/common/src/main/java/com/redhat/thermostat/common/ActionNotifier.java	Thu Apr 26 13:32:33 2012 -0400
+++ b/common/src/main/java/com/redhat/thermostat/common/ActionNotifier.java	Mon Apr 30 11:44:05 2012 -0400
@@ -58,8 +58,8 @@
         listeners.remove(listener);
     }
 
-    public void fireAction(T testId1) {
-        ActionEvent<T> action = new ActionEvent<>(source, testId1);
+    public void fireAction(T actionId) {
+        ActionEvent<T> action = new ActionEvent<>(source, actionId);
         for (ActionListener<T> listener : listeners) {
             listener.actionPerformed(action);
         }