changeset 1289:7a0ff324a833

Fix dead-vm (and other things) review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-October/008550.html reviewed-by: omajid
author Mario Torre <neugens.limasoftware@gmail.com>
date Mon, 28 Oct 2013 16:27:18 +0100
parents d09fd25379e8
children 5a545dca9fb5
files client/core/pom.xml client/core/src/main/java/com/redhat/thermostat/client/core/NameMatchingRefFilter.java client/core/src/main/java/com/redhat/thermostat/client/core/vmlist/HostFilter.java client/core/src/main/java/com/redhat/thermostat/client/core/vmlist/VMFilter.java client/core/src/main/java/com/redhat/thermostat/client/ui/MainWindowController.java client/living-vm-filter/core/src/main/java/com/redhat/thermostat/client/filter/vm/core/LivingVMFilter.java client/living-vm-filter/core/src/main/java/com/redhat/thermostat/client/filter/vm/core/internal/VMFilterActivator.java client/living-vm-filter/core/src/test/java/com/redhat/thermostat/client/filter/vm/core/internal/VMFilterActivatorTest.java client/living-vm-filter/swing/src/main/java/com/redhat/thermostat/client/filter/vm/swing/LivingVMDecoratorProvider.java client/living-vm-filter/swing/src/main/java/com/redhat/thermostat/client/filter/vm/swing/VMFilterActivator.java client/swing/pom.xml client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/HostFilterRegistry.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainView.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainWindow.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImpl.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/VMMonitorController.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/VmFilterRegistry.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/accordion/Accordion.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/accordion/AccordionComponentController.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/accordion/AccordionModel.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/HostTreeComponentFactory.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/ReferenceComponent.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/controller/DecoratorProviderExtensionListener.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/controller/FilterManager.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/controller/HostTreeController.java client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImplTest.java client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainWindowTest.java client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/VMMonitorControllerTest.java client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/accordion/AccordionModelTest.java client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/vmlist/controller/HostTreeControllerTest.java common/core/src/main/java/com/redhat/thermostat/common/AllPassFilter.java common/core/src/main/java/com/redhat/thermostat/common/Filter.java killvm/client-swing/src/main/java/com/redhat/thermostat/killvm/client/internal/KillVMAction.java storage/core/src/main/java/com/redhat/thermostat/storage/monitor/HostMonitor.java storage/core/src/main/java/com/redhat/thermostat/storage/monitor/NetworkMonitor.java storage/core/src/main/java/com/redhat/thermostat/storage/monitor/internal/HostMonitorImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/monitor/internal/NetworkMonitorImpl.java storage/core/src/test/java/com/redhat/thermostat/storage/monitor/internal/HostMonitorImplTest.java storage/core/src/test/java/com/redhat/thermostat/storage/monitor/internal/NetworkMonitorImplTest.java
diffstat 39 files changed, 1350 insertions(+), 261 deletions(-) [+]
line wrap: on
line diff
--- a/client/core/pom.xml	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/core/pom.xml	Mon Oct 28 16:27:18 2013 +0100
@@ -125,7 +125,8 @@
               com.redhat.thermostat.client.core,
               com.redhat.thermostat.client.core.progress,
               com.redhat.thermostat.client.core.controllers,
-              com.redhat.thermostat.client.core.views
+              com.redhat.thermostat.client.core.views,
+              com.redhat.thermostat.client.core.vmlist
             </Export-Package>
             <Private-Package>
               com.redhat.thermostat.client.core.internal
--- a/client/core/src/main/java/com/redhat/thermostat/client/core/NameMatchingRefFilter.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/core/NameMatchingRefFilter.java	Mon Oct 28 16:27:18 2013 +0100
@@ -45,12 +45,12 @@
  * A {@link Filter} that checks if the name of a {@link Ref} contains
  * the supplied character substring. This is case sensitive.
  */
-public class NameMatchingRefFilter<T extends Ref> implements Filter<T> {
+public class NameMatchingRefFilter<T extends Ref> extends Filter<T> {
 
     private String pattern;
 
     public NameMatchingRefFilter() {
-        this(null);
+        this("");
     }
 
     public NameMatchingRefFilter(String pattern) {
@@ -67,7 +67,11 @@
     }
 
     public void setPattern(String pattern) {
+        String oldPattern = this.pattern;
         this.pattern = pattern;
+        if (!Objects.equals(oldPattern, this.pattern)) {
+            notify(FilterEvent.FILTER_CHANGED);
+        }
     }
 
     public String getPattern() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/core/src/main/java/com/redhat/thermostat/client/core/vmlist/HostFilter.java	Mon Oct 28 16:27:18 2013 +0100
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2012, 2013 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.core.vmlist;
+
+import com.redhat.thermostat.annotations.ExtensionPoint;
+import com.redhat.thermostat.common.Filter;
+import com.redhat.thermostat.storage.core.HostRef;
+
+/**
+ * Filter that controls if {@link HostRef}erences can be shown in the
+ * reference tree of this Swing Client.
+ */
+@ExtensionPoint
+public abstract class HostFilter extends Filter<HostRef>{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/core/src/main/java/com/redhat/thermostat/client/core/vmlist/VMFilter.java	Mon Oct 28 16:27:18 2013 +0100
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2012, 2013 Red Hat, Inc.
+ * 
+ * This file is part of Thermostat.
+ * 
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ * 
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ * 
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ * 
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.core.vmlist;
+
+import com.redhat.thermostat.annotations.ExtensionPoint;
+import com.redhat.thermostat.common.Filter;
+import com.redhat.thermostat.storage.core.VmRef;
+
+/**
+ * Filter that controls if {@link VmRef}erences can be shown in the
+ * reference tree of this Swing Client.
+ */
+@ExtensionPoint
+public abstract class VMFilter extends Filter<VmRef> {
+
+}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/MainWindowController.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/MainWindowController.java	Mon Oct 28 16:27:18 2013 +0100
@@ -39,9 +39,6 @@
 
 public interface MainWindowController {
 
-    public void setHostVmTreeFilter(String filter);
-
     public void showMainMainWindow();
-
 }
 
--- a/client/living-vm-filter/core/src/main/java/com/redhat/thermostat/client/filter/vm/core/LivingVMFilter.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/living-vm-filter/core/src/main/java/com/redhat/thermostat/client/filter/vm/core/LivingVMFilter.java	Mon Oct 28 16:27:18 2013 +0100
@@ -36,12 +36,12 @@
 
 package com.redhat.thermostat.client.filter.vm.core;
 
-import com.redhat.thermostat.common.Filter;
+import com.redhat.thermostat.client.core.vmlist.VMFilter;
 import com.redhat.thermostat.storage.core.VmRef;
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.storage.model.VmInfo;
 
-public class LivingVMFilter implements Filter<VmRef> {
+public class LivingVMFilter extends VMFilter {
 
     volatile boolean filterActive = true;
     
@@ -61,7 +61,11 @@
     }
 
     public void setActive(boolean active) {
+        boolean oldActive = this.filterActive;
         this.filterActive = active;
+        if (oldActive != filterActive) {
+            notify(FilterEvent.FILTER_CHANGED);
+        }
     }
 
     public boolean isActive() {
--- a/client/living-vm-filter/core/src/main/java/com/redhat/thermostat/client/filter/vm/core/internal/VMFilterActivator.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/living-vm-filter/core/src/main/java/com/redhat/thermostat/client/filter/vm/core/internal/VMFilterActivator.java	Mon Oct 28 16:27:18 2013 +0100
@@ -38,8 +38,6 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Dictionary;
-import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
 
@@ -49,41 +47,38 @@
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.util.tracker.ServiceTracker;
 
-import com.redhat.thermostat.common.Filter;
+import com.redhat.thermostat.client.core.vmlist.VMFilter;
 import com.redhat.thermostat.client.filter.vm.core.LivingVMFilter;
 import com.redhat.thermostat.client.ui.MenuAction;
-import com.redhat.thermostat.common.Constants;
-import com.redhat.thermostat.storage.core.VmRef;
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
 
 public class VMFilterActivator implements BundleActivator {
 
+    @SuppressWarnings("rawtypes")
     private final List<ServiceRegistration> registeredServices = Collections.synchronizedList(new ArrayList<ServiceRegistration>());
 
+    @SuppressWarnings("rawtypes")
     ServiceTracker vmInfoDaoTracker;
 
+    @SuppressWarnings({ "unchecked", "rawtypes" })
     @Override
     public void start(BundleContext context) throws Exception {
         
         vmInfoDaoTracker = new ServiceTracker(context, VmInfoDAO.class.getName(), null) {
             @Override
             public Object addingService(ServiceReference reference) {
+                ServiceRegistration registration = null;
+
                 VmInfoDAO dao = (VmInfoDAO) context.getService(reference);
 
                 LivingVMFilter filter = new LivingVMFilter(dao);
+                registration = context.registerService(VMFilter.class.getName(), filter, null);
                 
                 LivingVMFilterMenuAction menu = new LivingVMFilterMenuAction(filter);
 
-                ServiceRegistration registration = null;
-                
                 registration = context.registerService(MenuAction.class.getName(), menu, null);
                 registeredServices.add(registration);
 
-                Dictionary<String, String> properties = new Hashtable<>();
-                properties.put(Constants.GENERIC_SERVICE_CLASSNAME, VmRef.class.getName());
-                registration = context.registerService(Filter.class.getName(), filter, properties);
-                registeredServices.add(registration);
-
                 return super.addingService(reference);
             }
 
@@ -103,6 +98,7 @@
         vmInfoDaoTracker.open();
     }
     
+    @SuppressWarnings("rawtypes")
     @Override
     public void stop(BundleContext context) throws Exception {
         vmInfoDaoTracker.close();
--- a/client/living-vm-filter/core/src/test/java/com/redhat/thermostat/client/filter/vm/core/internal/VMFilterActivatorTest.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/living-vm-filter/core/src/test/java/com/redhat/thermostat/client/filter/vm/core/internal/VMFilterActivatorTest.java	Mon Oct 28 16:27:18 2013 +0100
@@ -44,6 +44,7 @@
 import org.osgi.framework.ServiceRegistration;
 
 import com.redhat.thermostat.common.Filter;
+import com.redhat.thermostat.client.core.vmlist.VMFilter;
 import com.redhat.thermostat.client.filter.vm.core.LivingVMFilter;
 import com.redhat.thermostat.client.filter.vm.core.internal.VMFilterActivator;
 import com.redhat.thermostat.client.ui.MenuAction;
@@ -66,7 +67,7 @@
         activator.vmInfoDaoTracker.addingService(ref);
         
         assertTrue(ctx.isServiceRegistered(MenuAction.class.getName(), LivingVMFilterMenuAction.class));
-        assertTrue(ctx.isServiceRegistered(Filter.class.getName(), LivingVMFilter.class));
+        assertTrue(ctx.isServiceRegistered(VMFilter.class.getName(), LivingVMFilter.class));
     }
 
 }
--- a/client/living-vm-filter/swing/src/main/java/com/redhat/thermostat/client/filter/vm/swing/LivingVMDecoratorProvider.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/living-vm-filter/swing/src/main/java/com/redhat/thermostat/client/filter/vm/swing/LivingVMDecoratorProvider.java	Mon Oct 28 16:27:18 2013 +0100
@@ -39,7 +39,6 @@
 import java.io.IOException;
 
 import com.redhat.thermostat.common.Filter;
-import com.redhat.thermostat.client.filter.vm.core.LivingVMFilter;
 import com.redhat.thermostat.client.swing.IconResource;
 import com.redhat.thermostat.client.ui.Decorator;
 import com.redhat.thermostat.client.ui.DecoratorProvider;
@@ -75,12 +74,12 @@
         }
     }
 
-    private LivingVMFilter decoratorFilter;
+    private com.redhat.thermostat.client.filter.vm.core.LivingVMFilter decoratorFilter;
     private LivingVMDecorator decorator;
     
     public LivingVMDecoratorProvider(VmInfoDAO dao) {
         decorator = new LivingVMDecorator();
-        decoratorFilter = new LivingVMFilter(dao);
+        decoratorFilter = new com.redhat.thermostat.client.filter.vm.core.LivingVMFilter(dao);
     }
     
     @Override
--- a/client/living-vm-filter/swing/src/main/java/com/redhat/thermostat/client/filter/vm/swing/VMFilterActivator.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/living-vm-filter/swing/src/main/java/com/redhat/thermostat/client/filter/vm/swing/VMFilterActivator.java	Mon Oct 28 16:27:18 2013 +0100
@@ -56,23 +56,26 @@
 
 public class VMFilterActivator implements BundleActivator {
 
+    @SuppressWarnings("rawtypes")
     private final List<ServiceRegistration> registeredServices = Collections.synchronizedList(new ArrayList<ServiceRegistration>());
 
+    @SuppressWarnings("rawtypes")
     ServiceTracker vmInfoDaoTracker;
 
+    @SuppressWarnings({ "rawtypes", "unchecked" })
     @Override
     public void start(BundleContext context) throws Exception {
         
         vmInfoDaoTracker = new ServiceTracker(context, VmInfoDAO.class.getName(), null) {
             @Override
             public Object addingService(ServiceReference reference) {
+                ServiceRegistration registration = null;
+
                 VmInfoDAO dao = (VmInfoDAO) context.getService(reference);
-
+                
                 LivingVMDecoratorProvider decorator = new LivingVMDecoratorProvider(dao);
                 DeadVMDecoratorProvider deadDecorator = new DeadVMDecoratorProvider(dao);
                 
-                ServiceRegistration registration = null;
-
                 Dictionary<String, String> decoratorProperties = new Hashtable<>();
                 decoratorProperties.put(Constants.GENERIC_SERVICE_CLASSNAME, VmRef.class.getName());
                 
@@ -101,6 +104,7 @@
         vmInfoDaoTracker.open();
     }
     
+    @SuppressWarnings("rawtypes")
     @Override
     public void stop(BundleContext context) throws Exception {
         vmInfoDaoTracker.close();
--- a/client/swing/pom.xml	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/swing/pom.xml	Mon Oct 28 16:27:18 2013 +0100
@@ -169,6 +169,7 @@
               com.redhat.thermostat.client.swing.components,
               com.redhat.thermostat.client.swing.components.models,
               com.redhat.thermostat.client.swing.components.timeline,
+              com.redhat.thermostat.client.swing.vmlist,
             </Export-Package>
             <Private-Package>
               com.redhat.thermostat.client.swing.internal,
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/HostFilterRegistry.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/HostFilterRegistry.java	Mon Oct 28 16:27:18 2013 +0100
@@ -40,19 +40,16 @@
 import org.osgi.framework.Constants;
 import org.osgi.framework.InvalidSyntaxException;
 
-import com.redhat.thermostat.common.Filter;
+import com.redhat.thermostat.client.core.vmlist.HostFilter;
 import com.redhat.thermostat.common.ThermostatExtensionRegistry;
-import com.redhat.thermostat.storage.core.HostRef;
 
-class HostFilterRegistry extends ThermostatExtensionRegistry<Filter> {
+public class HostFilterRegistry extends ThermostatExtensionRegistry<HostFilter> {
 
     private static final String FILTER = "(&(" + Constants.OBJECTCLASS + "=" +
-            Filter.class.getName() + ")(" +
-            com.redhat.thermostat.common.Constants.GENERIC_SERVICE_CLASSNAME + "=" +
-            HostRef.class.getName() + "))";
+            HostFilter.class.getName() + "))";
 
     public HostFilterRegistry(BundleContext context) throws InvalidSyntaxException {
-        super(context, FILTER, Filter.class);
+        super(context, FILTER, HostFilter.class);
     }
 }
 
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainView.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainView.java	Mon Oct 28 16:27:18 2013 +0100
@@ -56,10 +56,8 @@
     enum Action {
         VISIBLE,
         HIDDEN,
-        HOST_VM_TREE_FILTER,
         SHOW_AGENT_CONFIG,
         SHOW_CLIENT_CONFIG,
-        SWITCH_HISTORY_MODE,
         SHOW_ABOUT_DIALOG,
         SHUTDOWN,
         SHOW_HOST_VM_CONTEXT_MENU,
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainWindow.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainWindow.java	Mon Oct 28 16:27:18 2013 +0100
@@ -295,8 +295,10 @@
         
         DecoratorManager decoratorManager = new DecoratorManager();
         
-        hostTree = new Accordion<>(new HostTreeComponentFactory(decoratorManager));
-        hostTreeController = new HostTreeController(hostTree, decoratorManager);
+        HostTreeComponentFactory hostFactory = new HostTreeComponentFactory(decoratorManager);
+        hostTree = new Accordion<>(hostFactory);
+        hostTreeController = new HostTreeController(hostTree, decoratorManager,
+                                                    hostFactory);
         navigationPanel.addContent(hostTree);
         
         final JPanel collapsedPanel = new JPanel();
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImpl.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImpl.java	Mon Oct 28 16:27:18 2013 +0100
@@ -40,7 +40,6 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -48,9 +47,7 @@
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.InvalidSyntaxException;
 
-import com.redhat.thermostat.common.Filter;
 import com.redhat.thermostat.client.core.InformationService;
-import com.redhat.thermostat.client.core.NameMatchingRefFilter;
 import com.redhat.thermostat.client.core.progress.ProgressNotifier;
 import com.redhat.thermostat.client.core.views.AgentInformationDisplayView;
 import com.redhat.thermostat.client.core.views.AgentInformationViewProvider;
@@ -64,12 +61,12 @@
 import com.redhat.thermostat.client.swing.internal.osgi.InformationServiceTracker;
 import com.redhat.thermostat.client.swing.internal.osgi.VMContextActionServiceTracker;
 import com.redhat.thermostat.client.swing.internal.vmlist.controller.DecoratorProviderExtensionListener;
+import com.redhat.thermostat.client.swing.internal.vmlist.controller.FilterManager;
 import com.redhat.thermostat.client.swing.internal.vmlist.controller.HostTreeController;
 import com.redhat.thermostat.client.swing.internal.vmlist.controller.HostTreeController.ReferenceSelection;
 import com.redhat.thermostat.client.ui.AgentInformationDisplayController;
 import com.redhat.thermostat.client.ui.AgentInformationDisplayModel;
 import com.redhat.thermostat.client.ui.ClientConfigurationController;
-import com.redhat.thermostat.client.ui.DecoratorProvider;
 import com.redhat.thermostat.client.ui.HostInformationController;
 import com.redhat.thermostat.client.ui.MainWindowController;
 import com.redhat.thermostat.client.ui.MenuAction;
@@ -78,6 +75,7 @@
 import com.redhat.thermostat.client.ui.VmInformationController;
 import com.redhat.thermostat.common.ActionEvent;
 import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.AllPassFilter;
 import com.redhat.thermostat.common.ApplicationInfo;
 import com.redhat.thermostat.common.ApplicationService;
 import com.redhat.thermostat.common.MultipleServiceTracker;
@@ -102,9 +100,6 @@
     
     private static final Logger logger = LoggingUtils.getLogger(MainWindowControllerImpl.class);
 
-    private final CopyOnWriteArrayList<Filter<HostRef>> hostFilters = new CopyOnWriteArrayList<>();
-    private final CopyOnWriteArrayList<Filter<VmRef>> vmFilters = new CopyOnWriteArrayList<>();
-
     private final ApplicationInfo appInfo = new ApplicationInfo();
 
     private ApplicationService appSvc;
@@ -162,14 +157,6 @@
         }
     };
 
-    private NameMatchingRefFilter<HostRef> hostFilter;
-    private NameMatchingRefFilter<VmRef> vmFilter;
-    private VmFilterRegistry vmFilterRegistry;
-    private HostFilterRegistry hostFilterRegistry;
-
-    private ActionListener<ThermostatExtensionRegistry.Action> hostFilterListener = new FilterExtensionListener<HostRef>(hostFilters);
-    private ActionListener<ThermostatExtensionRegistry.Action> vmFilterListener = new FilterExtensionListener<VmRef>(vmFilters);
-
     private HostTreeDecoratorRegistry hostDecoratorRegistry;
     private VMTreeDecoratorRegistry vmDecoratorRegistry;
 
@@ -181,11 +168,14 @@
                                     actionEvent)
         {
             // TODO
-            //updateView();
+            // System.err.println(actionEvent.getPayload());
         };
     };
 
     private VmInformationControllerProvider vmInfoControllerProvider;
+    private VmFilterRegistry vmFilterRegistry;
+    private HostFilterRegistry hostFilterRegistry;
+    private FilterManager filterManager;
     
     public MainWindowControllerImpl(BundleContext context, ApplicationService appSvc,
             CountDownLatch shutdown) {
@@ -195,12 +185,16 @@
     MainWindowControllerImpl(final BundleContext context, ApplicationService appSvc,
             final MainView view,
             RegistryFactory registryFactory,
-            final CountDownLatch shutdown) {
+            final CountDownLatch shutdown)
+    {
         this.appSvc = appSvc;
         this.view = view;
+       
         try {
+            
             vmFilterRegistry = registryFactory.createVmFilterRegistry();
             hostFilterRegistry = registryFactory.createHostFilterRegistry();
+            
             hostDecoratorRegistry = registryFactory.createHostTreeDecoratorRegistry();
             vmDecoratorRegistry = registryFactory.createVMTreeDecoratorRegistry();
             menuRegistry = registryFactory.createMenuRegistry();
@@ -209,13 +203,7 @@
         } catch (InvalidSyntaxException e) {
             throw new RuntimeException(e);
         }
-
-        hostFilter = new NameMatchingRefFilter<>();
-        vmFilter = new NameMatchingRefFilter<>();
-        
-        hostFilters.add(hostFilter);
-        vmFilters.add(vmFilter);
-        
+                
         this.infoServiceTracker = new InformationServiceTracker(context);
         this.infoServiceTracker.open();
         
@@ -272,12 +260,12 @@
                 initView();
 
                 vmInfoControllerProvider = new VmInformationControllerProvider();
-
+                
+                installListenersAndStartRegistries();
+                
                 vmMonitor = initMonitors();
                 vmMonitor.start();
                 
-                installListenersAndStartRegistries();
-                
                 registerProgressNotificator(context);
             }
 
@@ -299,19 +287,6 @@
         return vmMonitor;
     }
     
-    /*
-     * This method is for testing purposes only
-     */
-    Filter<HostRef> getHostFilter() {
-        return hostFilter;
-    }
-    /*
-     * This also is for testing purposes.
-     */
-    Filter<VmRef> getVmFilter() {
-        return vmFilter;
-    }
-    
     /**
      * This method is for testing purposes only
      */
@@ -319,15 +294,27 @@
         return menuListener;
     }
     
-    @Override
-    public void setHostVmTreeFilter(String filter) {
-        this.hostFilter.setPattern(filter);
-        this.vmFilter.setPattern(filter);
+    private void initHostVMTree() {
+        HostTreeController hostController = view.getHostTreeController();
+        
+        // initially fill out with all known host and vms
+        List<HostRef> hosts = networkMonitor.getHosts(new AllPassFilter<HostRef>());
+        AllPassFilter<VmRef> vmFilter = new AllPassFilter<>();
+        for (HostRef host : hosts) {
+            hostController.registerHost(host);
+
+            // get the vm for this host
+            List<VmRef> vms = hostMonitor.getVirtualMachines(host, vmFilter);
+            for (VmRef vm : vms) {
+                hostController.registerVM(vm);
+            }
+        }
     }
+    
+    private void initView() {
+        view.setWindowTitle(appInfo.getName());
 
-    private void initView() {        
-        view.setWindowTitle(appInfo.getName());
-        
+        initHostVMTree();
         view.getHostTreeController().addReferenceSelectionChangeListener(new
                 ActionListener<HostTreeController.ReferenceSelection>() {
             @Override
@@ -347,21 +334,12 @@
                 case VISIBLE:
                     break;
                     
-                case HOST_VM_TREE_FILTER:
-                    // TODO
-//                    String filter = view.getHostVmTreeFilterText();
-//                    setHostVmTreeFilter(filter);
-                    break;
                 case SHOW_AGENT_CONFIG:
                     showAgentConfiguration();
                     break;
                 case SHOW_CLIENT_CONFIG:
                     showConfigureClientPreferences();
                     break;
-                case SWITCH_HISTORY_MODE:
-                    // TODO
-                    //switchHistoryMode();
-                    break;
                 case SHOW_ABOUT_DIALOG:
                     showAboutDialog();
                     break;
@@ -375,6 +353,7 @@
                     // Main will call shutdownApplication
                     shutdown.countDown();
                     break;
+                    
                 default:
                     throw new IllegalStateException("unhandled action");
                 }
@@ -403,13 +382,11 @@
         menuRegistry.addActionListener(menuListener);
         menuRegistry.start();
 
-        hostFilterRegistry.addActionListener(hostFilterListener);
-        hostFilterRegistry.start();
+        HostTreeController hostTreeController = view.getHostTreeController();
+        filterManager = new FilterManager(vmFilterRegistry, hostFilterRegistry,
+                                          hostTreeController);
 
-        vmFilterRegistry.addActionListener(vmFilterListener);
-        vmFilterRegistry.start();
-
-        HostTreeController hostTreeController = view.getHostTreeController();
+        filterManager.start();
         
         DecoratorProviderExtensionListener<HostRef> hostDecoratorListener =
                 hostTreeController.getHostDecoratorListener();
@@ -435,14 +412,8 @@
         menuListener = null;
         menuRegistry.stop();
 
-        hostFilterRegistry.removeActionListener(hostFilterListener);
-        hostFilterListener = null;
-        hostFilterRegistry.stop();
-
-        vmFilterRegistry.removeActionListener(vmFilterListener);
-        vmFilterListener = null;
-        vmFilterRegistry.stop();
-
+        filterManager.stop();
+        
         HostTreeController hostTreeController = view.getHostTreeController();
         
         DecoratorProviderExtensionListener<HostRef> hostDecoratorListener =
@@ -559,48 +530,6 @@
         }
     }
 
-    private class FilterExtensionListener<T> implements ActionListener<ThermostatExtensionRegistry.Action> {
-
-        private final CopyOnWriteArrayList<Filter<T>> extensionList;
-
-        public FilterExtensionListener(CopyOnWriteArrayList<Filter<T>> addRemoveExtensionsFrom) {
-            this.extensionList = addRemoveExtensionsFrom;
-        }
-
-        @SuppressWarnings("unchecked")
-        @Override
-        public void actionPerformed(ActionEvent<ThermostatExtensionRegistry.Action> actionEvent) {
-
-            Object payload = actionEvent.getPayload();
-            Filter<T> filter = null;
-
-            try {
-                filter = (Filter<T>) payload;
-            } catch (ClassCastException cce) {
-                throw new IllegalArgumentException("unexpected payload type. " +
-                            payload.getClass().getName() + " not allowed here.", cce);
-            }
-        
-
-            switch (actionEvent.getActionId()) {
-            case SERVICE_ADDED:
-                extensionList.add(filter);
-                //doUpdateTreeAsync();
-                break;
-
-            case SERVICE_REMOVED:
-                extensionList.remove(filter);
-                //doUpdateTreeAsync();
-                break;
-
-            default:
-                logger.log(Level.WARNING, "received unknown event from ExtensionRegistry: " +
-                                           actionEvent.getActionId());
-                break;
-            }
-        }
-    }
-
     private class VmInformationControllerProvider {
         private VmInformationController lastSelectedVM;
         private Map<VmRef, Integer> selectedForVM = new ConcurrentHashMap<>();
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/VMMonitorController.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/VMMonitorController.java	Mon Oct 28 16:27:18 2013 +0100
@@ -72,12 +72,12 @@
             HostRef host = (HostRef) actionEvent.getPayload();
             switch (actionEvent.getActionId()) {
             case HOST_ADDED:
-                view.getHostTreeController().addHost(host);
+                view.getHostTreeController().registerHost(host);
                 hostMonitor.addHostChangeListener(host, hostListener);
                 break;
 
             case HOST_REMOVED:
-                view.getHostTreeController().removeHost(host);
+                view.getHostTreeController().updateHostStatus(host);
                 hostMonitor.removeHostChangeListener(host, hostListener);
                 break;
                 
@@ -95,11 +95,11 @@
             VmRef vm = (VmRef) actionEvent.getPayload();
             switch (actionEvent.getActionId()) {
             case VM_ADDED:
-                view.getHostTreeController().addVM(vm);
+                view.getHostTreeController().registerVM(vm);
                 break;
             
             case VM_REMOVED:
-                view.getHostTreeController().removeVM(vm);
+                view.getHostTreeController().updateVMStatus(vm);
                 
             default:
                 break;
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/VmFilterRegistry.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/VmFilterRegistry.java	Mon Oct 28 16:27:18 2013 +0100
@@ -40,19 +40,15 @@
 import org.osgi.framework.Constants;
 import org.osgi.framework.InvalidSyntaxException;
 
-import com.redhat.thermostat.common.Filter;
+import com.redhat.thermostat.client.core.vmlist.VMFilter;
 import com.redhat.thermostat.common.ThermostatExtensionRegistry;
-import com.redhat.thermostat.storage.core.VmRef;
 
-class VmFilterRegistry extends ThermostatExtensionRegistry<Filter> {
+public class VmFilterRegistry extends ThermostatExtensionRegistry<VMFilter> {
 
     private static final String FILTER = "(&(" + Constants.OBJECTCLASS + "=" +
-            Filter.class.getName() + ")(" +
-            com.redhat.thermostat.common.Constants.GENERIC_SERVICE_CLASSNAME + "=" +
-            VmRef.class.getName() + "))";
+            VMFilter.class.getName() + "))";
 
     public VmFilterRegistry(BundleContext context) throws InvalidSyntaxException {
-        super(context, FILTER, Filter.class);
+        super(context, FILTER, VMFilter.class);
     }
 }
-
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/accordion/Accordion.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/accordion/Accordion.java	Mon Oct 28 16:27:18 2013 +0100
@@ -204,6 +204,8 @@
             JComponent content = pane.getContent();
             content.remove(contentUnit);
             content.revalidate();
+            
+            Accordion.this.contentPane.revalidate();
         }
 
         @Override
@@ -224,4 +226,23 @@
     public void removeAccordionItemSelectedChangeListener(AccordionItemSelectedChangeListener l) {
         componentController.removeAccordionItemSelectedChangeListener(l);
     }
+    
+    public AccordionComponent getSelectedComponent() {
+        return componentController.getSelectedComponent();
+    }
+
+    public void setSelectedComponent(AccordionComponent component) {
+        componentController.setSelectedItem(component);
+    }
+    
+    public boolean isExpanded(H header) {
+        return !panes.containsKey(header) || panes.get(header).isExpanded();
+    }
+    
+    public void setExpanded(H header, boolean expanded) {
+        if (panes.containsKey(header)) {
+            panes.get(header).setExpanded(expanded);
+            repaint();
+        }
+    }
 }
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/accordion/AccordionComponentController.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/accordion/AccordionComponentController.java	Mon Oct 28 16:27:18 2013 +0100
@@ -83,4 +83,8 @@
             }
         }
     }
+    
+    AccordionComponent getSelectedComponent() {
+        return selectedComponent;
+    }
 }
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/accordion/AccordionModel.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/accordion/AccordionModel.java	Mon Oct 28 16:27:18 2013 +0100
@@ -38,7 +38,9 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import javax.swing.event.EventListenerList;
 
@@ -50,23 +52,29 @@
  * {@link AccordionComponentFactory} is responsible to create the specific
  * widget to be used inside the Accordion. 
  * 
+ * <br /><br />
+ * 
  * <strong>Note</strong>: H and C must be usable as hash keys.
+ * 
+ * <br />
+ * 
+ * <strong>Note</strong>: This class is <strong>not</strong> thread safe.
  */
 public class AccordionModel<H, C> {
 
     protected EventListenerList listenerList;
     
-    private HashMap<H, List<C>> components;
+    private HashMap<H, Set<C>> components;
     
     public AccordionModel() {
         components = new HashMap<>();
         listenerList = new EventListenerList();
     }
    
-    private List<C> addOrGetHeader(H header) {
-        List<C> _components = components.get(header);
+    private Set<C> addOrGetHeader(H header) {
+        Set<C> _components = components.get(header);
         if (_components == null) {
-            _components = new ArrayList<>();
+            _components = new HashSet<>();
             components.put(header, _components);
 
             fireHeaderAddedEvent(header);
@@ -74,14 +82,62 @@
         return _components;
     }
     
+    /**
+     * Gets a {@link List} representation of all the headers currently
+     * held by this model. The {@link List} can be modified, however the
+     * headers are references to the actual headers contained in this model.
+     * 
+     * <br /><br />
+     * 
+     * If this model is currently empty, an emtpy {@link List} is returned.
+     */
+    public List<H> getHeaders() {
+        List<H> result = new ArrayList<>();
+        if (components.size() != 0) {
+            for (H header : components.keySet()) {
+                result.add(header);
+            }
+        }
+        return result;
+    }
+    
+   /**
+    * Gets a {@link List} representation of all the components currently
+    * held by this model and relative to the passed header. The {@link List}
+    * can be modified, however the components are references to the actual
+    * components contained in this model.
+    * 
+    * <br /><br />
+    * 
+    * If no components exist of the given header, an emtpy {@link List} is
+    * returned.
+    */
+    public List<C> getComponents(H header) {
+        List<C> result = new ArrayList<>();
+        if (components.containsKey(header)) {
+            Set<C> componentSet = components.get(header);
+            for (C component : componentSet) {
+                result.add(component);
+            }
+        }
+        return result;
+    }
+    
+    /**
+     * Adds this header to this model. If the header already exist in this
+     * model, this is a no-op.
+     */
     public boolean addHeader(H header) {
         boolean result = components.containsKey(header);
         addOrGetHeader(header);
         return result;
     }
     
+    /**
+     * Removes this header from this model.
+     */
     public boolean removeHeader(H header) {
-        List<C> _components = components.remove(header);
+        Set<C> _components = components.remove(header);
         boolean result = (_components != null);
         if (result) {
             for (C component :_components) {
@@ -92,15 +148,27 @@
         return result;
     }
     
+    /**
+     * Adds this component to the given header. If the header is not in the
+     * model already, it is also added.
+     */
     public boolean addComponent(H header, C component) {
-        List<C> _components = addOrGetHeader(header);
-        boolean result = _components.add(component);
-        fireComponentAddedEvent(header, component);
+        Set<C> _components = addOrGetHeader(header);
+        boolean result = false;
+        if (!_components.contains(component)) {
+            result = _components.add(component);
+            fireComponentAddedEvent(header, component);
+        }
         return result;
     }
     
+    /**
+     * Removes the current component from the given header. If the header
+     * is not contained in this model, or the component does not belong to
+     * the passed header, this is a no-op.
+     */
     public boolean removeComponent(H header, C component) {
-        List<C> _components = components.get(header);
+        Set<C> _components = components.get(header);
         boolean result = false;
         if (_components != null) {
             result = _components.remove(component);
@@ -109,22 +177,42 @@
         return result;
     }
     
+    /**
+     * Returns the total number of header objects contained in this model,
+     * not including their components.
+     */
     public int headerSize() {
         return components.size();
     }
     
+    /**
+     * Returns the total number of objects contained in this model. The total
+     * size is the sum of {@link #headerSize()} plus the number of components
+     * contained under each header. 
+     */
     public int size() {
         int size = components.size();
-        for (List<C> comp : components.values()) {
+        for (Set<C> comp : components.values()) {
             size += comp.size();
         }
         return size;
     }
     
-    public void addAccordionModelChangeListener(AccordionModelChangeListener l) {
-        listenerList.add(AccordionModelChangeListener.class, l);
+    /**
+     * Adds an {@link AccordionModelChangeListener} listener to this model.
+     */
+    public void addAccordionModelChangeListener(AccordionModelChangeListener<H, C> listener) {
+        listenerList.add(AccordionModelChangeListener.class, listener);
+    }
+
+    /**
+     * Removes this {@link AccordionModelChangeListener} listener from this model.
+     */
+    public void removeAccordionModelChangeListener(AccordionModelChangeListener<H, C> listener) {
+        listenerList.remove(AccordionModelChangeListener.class, listener);
     }
     
+    @SuppressWarnings({ "unchecked", "rawtypes" })
     private void fireHeaderRemovedEvent(H header) {
         Object[] listeners = listenerList.getListenerList();
 
@@ -137,6 +225,7 @@
         }
     }
     
+    @SuppressWarnings({ "unchecked", "rawtypes" })
     private void fireHeaderAddedEvent(H header) {
         Object[] listeners = listenerList.getListenerList();
 
@@ -149,6 +238,7 @@
         }
     }
     
+    @SuppressWarnings({ "unchecked", "rawtypes" })
     private void fireComponentAddedEvent(H header, C component) {
         Object[] listeners = listenerList.getListenerList();
 
@@ -161,6 +251,7 @@
         }
     }
     
+    @SuppressWarnings({ "unchecked", "rawtypes" })
     private void fireComponentRemovedEvent(H header, C component) {
         Object[] listeners = listenerList.getListenerList();
 
@@ -172,4 +263,15 @@
             }
         }
     }
+
+    /**
+     * Clears this accordion model. This will result in the removal of all the
+     * headers (and subsequently of the respective components) in this model,
+     * generating 
+     */
+    public void clear() {
+        for (H header : getHeaders()) {
+            removeHeader(header);
+        }
+    }
 }
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/HostTreeComponentFactory.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/HostTreeComponentFactory.java	Mon Oct 28 16:27:18 2013 +0100
@@ -36,6 +36,9 @@
 
 package com.redhat.thermostat.client.swing.internal.vmlist;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import com.redhat.thermostat.client.swing.internal.accordion.AccordionComponent;
 import com.redhat.thermostat.client.swing.internal.accordion.AccordionComponentFactory;
 import com.redhat.thermostat.client.swing.internal.accordion.TitledPane;
@@ -45,16 +48,23 @@
 
 public class HostTreeComponentFactory implements AccordionComponentFactory<HostRef, VmRef>{
     
+    private Map<VmRef, AccordionComponent> components;
+    private Map<HostRef, ReferenceTitle> headers;
+    
     private DecoratorManager decoratorManager;
     
     public HostTreeComponentFactory(DecoratorManager decoratorManager) {
         this.decoratorManager = decoratorManager;
+        components = new HashMap<>();
+        headers = new HashMap<>();
     }
 
     @Override
     public TitledPane createHeader(HostRef header) {
         ReferenceTitle pane = new ReferenceTitle(header);
         decoratorManager.registerAndSetIcon(pane);
+        headers.put(header, pane);
+
         return pane;
     }
 
@@ -62,6 +72,16 @@
     public AccordionComponent createComponent(HostRef header, VmRef component) {
         ReferenceComponent refComponent = new ReferenceComponent(component);
         decoratorManager.registerAndSetIcon(refComponent);
+        components.put(component, refComponent);
+
         return refComponent;
     }
+    
+    public AccordionComponent getAccordionComponent(VmRef vm) {
+        return components.get(vm);
+    }
+    
+    public ReferenceTitle getTitledPane(HostRef host) {
+        return headers.get(host);
+    }
 }
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/ReferenceComponent.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/ReferenceComponent.java	Mon Oct 28 16:27:18 2013 +0100
@@ -43,7 +43,6 @@
 import java.awt.Graphics2D;
 
 import javax.swing.Box;
-import javax.swing.JLabel;
 import javax.swing.JPanel;
 
 import com.redhat.thermostat.client.swing.components.CompositeIcon;
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/controller/DecoratorProviderExtensionListener.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/controller/DecoratorProviderExtensionListener.java	Mon Oct 28 16:27:18 2013 +0100
@@ -58,6 +58,7 @@
     public enum Action {
         DECORATOR_ADDED,
         DECORATOR_REMOVED,
+        DECORATION_CHANGED,
     }
     
     private final ActionNotifier<Action> decoratorChangeNotifier;
@@ -112,4 +113,8 @@
     CopyOnWriteArrayList<DecoratorProvider<T>> getDecorators() {
         return decorators;
     }
+
+    public void decorationChanged() {
+        decoratorChangeNotifier.fireAction(Action.DECORATION_CHANGED);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/controller/FilterManager.java	Mon Oct 28 16:27:18 2013 +0100
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2012, 2013 Red Hat, Inc.
+ * 
+ * This file is part of Thermostat.
+ * 
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ * 
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ * 
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ * 
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.swing.internal.vmlist.controller;
+
+import com.redhat.thermostat.client.core.vmlist.HostFilter;
+import com.redhat.thermostat.client.core.vmlist.VMFilter;
+import com.redhat.thermostat.client.swing.internal.HostFilterRegistry;
+import com.redhat.thermostat.client.swing.internal.VmFilterRegistry;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ThermostatExtensionRegistry;
+import com.redhat.thermostat.common.ThermostatExtensionRegistry.Action;
+
+public class FilterManager {
+    
+    private ActionListener<ThermostatExtensionRegistry.Action> hostFilterListener;
+    private ActionListener<ThermostatExtensionRegistry.Action> vmFilterListener;
+
+    private VmFilterRegistry vmFilterRegistry;
+    private HostFilterRegistry hostFilterRegistry;
+    
+    public FilterManager(VmFilterRegistry vmFilterRegistry,
+                         HostFilterRegistry hostFilterRegistry,
+                         final HostTreeController hostController)
+    {
+        
+        hostFilterListener = new ActionListener<ThermostatExtensionRegistry.Action>() {
+            @Override
+            public void actionPerformed(ActionEvent<Action> actionEvent) {
+                if (actionEvent.getActionId() == Action.SERVICE_ADDED){
+                    hostController.addHostFilter((HostFilter) actionEvent.getPayload());
+                } else {
+                    hostController.removeHostFilter((HostFilter) actionEvent.getPayload());
+                }
+            }
+        };
+        vmFilterListener = new  ActionListener<ThermostatExtensionRegistry.Action>() {
+            @Override
+            public void actionPerformed(ActionEvent<Action> actionEvent) {
+                if (actionEvent.getActionId() == Action.SERVICE_ADDED){
+                    hostController.addVMFilter((VMFilter) actionEvent.getPayload());
+                } else {
+                    hostController.removeVMFilter((VMFilter) actionEvent.getPayload());
+                }
+            }
+        };
+        
+        this.vmFilterRegistry = vmFilterRegistry;
+        this.hostFilterRegistry = hostFilterRegistry;
+    }
+    
+    public void start() {
+        hostFilterRegistry.addActionListener(hostFilterListener);
+        hostFilterRegistry.start();
+
+        vmFilterRegistry.addActionListener(vmFilterListener);
+        vmFilterRegistry.start();
+    }
+    
+    public void stop() {
+        hostFilterRegistry.removeActionListener(hostFilterListener);
+        hostFilterListener = null;
+        hostFilterRegistry.stop();
+
+        vmFilterRegistry.removeActionListener(vmFilterListener);
+        vmFilterListener = null;
+        vmFilterRegistry.stop();
+    }
+}
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/controller/HostTreeController.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/controller/HostTreeController.java	Mon Oct 28 16:27:18 2013 +0100
@@ -36,16 +36,30 @@
 
 package com.redhat.thermostat.client.swing.internal.vmlist.controller;
 
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
 import javax.swing.SwingUtilities;
 
+import com.redhat.thermostat.client.core.vmlist.HostFilter;
+import com.redhat.thermostat.client.core.vmlist.VMFilter;
 import com.redhat.thermostat.client.swing.internal.accordion.Accordion;
+import com.redhat.thermostat.client.swing.internal.accordion.AccordionComponent;
+import com.redhat.thermostat.client.swing.internal.accordion.AccordionComponentEvent;
+import com.redhat.thermostat.client.swing.internal.accordion.AccordionHeaderEvent;
 import com.redhat.thermostat.client.swing.internal.accordion.AccordionItemSelectedChangeListener;
 import com.redhat.thermostat.client.swing.internal.accordion.AccordionModel;
+import com.redhat.thermostat.client.swing.internal.accordion.AccordionModelChangeListener;
 import com.redhat.thermostat.client.swing.internal.accordion.ItemSelectedEvent;
+import com.redhat.thermostat.client.swing.internal.vmlist.HostTreeComponentFactory;
 import com.redhat.thermostat.client.swing.internal.vmlist.ReferenceProvider;
+import com.redhat.thermostat.common.ActionEvent;
 import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.ActionNotifier;
+import com.redhat.thermostat.common.Filter;
+import com.redhat.thermostat.common.Filter.FilterEvent;
 import com.redhat.thermostat.storage.core.HostRef;
+import com.redhat.thermostat.storage.core.Ref;
 import com.redhat.thermostat.storage.core.VmRef;
 
 public class HostTreeController {
@@ -55,15 +69,61 @@
     }
 
     private DecoratorManager decoratorManager;
-
+    private HostTreeComponentFactory componentFactory;
+    
     private final ActionNotifier<ReferenceSelection> referenceNotifier;
 
-    private AccordionModel<HostRef, VmRef> model;
+    private CopyOnWriteArrayList<Filter<HostRef>> hostFilters;
+    private CopyOnWriteArrayList<Filter<VmRef>> vmFilters;
+    
+    private FilterListener filterListener;
+    
+    private Accordion<HostRef, VmRef> accordion;
     
-    public HostTreeController(Accordion<HostRef, VmRef> accordion, DecoratorManager decoratorManager) {
+    // we keep a private fullModel updated with all the references, while we
+    // apply filters and decorations to the accordion original model only 
+    private AccordionModel<HostRef, VmRef> proxyModel;
+    private AccordionModel<HostRef, VmRef> fullModel;
+    private class AccordionModelProxy implements AccordionModelChangeListener<HostRef, VmRef> {
+        @Override
+        public synchronized void headerAdded(AccordionHeaderEvent<HostRef> e) {
+            proxyModel.addHeader(e.getHeader());
+        }
+
+        @Override
+        public synchronized void headerRemoved(AccordionHeaderEvent<HostRef> e) {
+            proxyModel.removeHeader(e.getHeader());
+        }
+
+        @Override
+        public synchronized void componentAdded(AccordionComponentEvent<HostRef, VmRef> e) {
+            proxyModel.addComponent(e.getHeader(), e.getComponent());
+        }
+
+        @Override
+        public synchronized void componentRemoved(AccordionComponentEvent<HostRef, VmRef> e) {
+            proxyModel.removeComponent(e.getHeader(), e.getComponent());
+        }
+    }
+    
+    public HostTreeController(Accordion<HostRef, VmRef> accordion,
+                              DecoratorManager decoratorManager,
+                              HostTreeComponentFactory componentFactory)
+    {
+        this.accordion = accordion;
+        this.componentFactory = componentFactory;
+        
+        filterListener = new FilterListener();
+        
+        hostFilters = new CopyOnWriteArrayList<>();
+        vmFilters = new CopyOnWriteArrayList<>();
+        
+        fullModel = new AccordionModel<>();
+        fullModel.addAccordionModelChangeListener(new AccordionModelProxy());
+        
         this.decoratorManager = decoratorManager;
         referenceNotifier = new ActionNotifier<>(this);
-        this.model = accordion.getModel();
+        this.proxyModel = accordion.getModel();
         accordion.addAccordionItemSelectedChangeListener(new AccordionItemSelectedChangeListener() {
             @Override
             public void itemSelected(ItemSelectedEvent event) {
@@ -81,38 +141,129 @@
         referenceNotifier.removeActionListener(listener);
     }
     
-    public void addHost(final HostRef host) {
+    public synchronized void registerHost(final HostRef host) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                fullModel.addHeader(host);
+                if (filter(hostFilters, host)) {
+                    proxyModel.removeHeader(host);
+                }
+            }
+        });
+    }
+    
+    public synchronized void updateHostStatus(final HostRef host) {
         SwingUtilities.invokeLater(new Runnable() {
             @Override
             public void run() {
-                model.addHeader(host);
+                if (filter(hostFilters, host)) {
+                    proxyModel.removeHeader(host);
+                }                
+                decoratorManager.getHostDecoratorListener().decorationChanged();
+            }
+        });
+    }
+    
+    private void addHostToProxy(final HostRef host) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                proxyModel.addHeader(host);
+            }
+        });
+    }
+    
+    private void setAccordionExpanded(final HostRef ref, final boolean expanded) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                accordion.setExpanded(ref, expanded);
+            }
+        });
+    }
+    
+    private void addVmToProxy(final VmRef vm) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                proxyModel.addComponent(vm.getHostRef(), vm);
             }
         });
     }
     
-    public void removeHost(final HostRef host) {
+    private void addVMImpl(final VmRef vm) {
         SwingUtilities.invokeLater(new Runnable() {
             @Override
             public void run() {
-                model.removeHeader(host);
+                fullModel.addComponent(vm.getHostRef(), vm);
+                if (filter(vmFilters, vm)) {
+                    proxyModel.removeComponent(vm.getHostRef(), vm);
+                }
+            }
+        });
+    }
+
+    private <R> boolean filter(CopyOnWriteArrayList<Filter<R>> filters, R ref) {
+        for (Filter<R> filter : filters) {
+            if (!filter.matches(ref)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    public synchronized void registerVM(final VmRef vm) {
+        addVMImpl(vm);
+    }
+
+    private AccordionComponent getHostComponent(HostRef reference) {
+        AccordionComponent component = null;
+        List<HostRef> hosts = proxyModel.getHeaders();
+        if (hosts.contains(reference)) {
+            component = componentFactory.getTitledPane(reference);
+        }
+        return component;
+    }
+    
+    private void selectComponent(final Ref _selected) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                Ref selected = _selected;
+                AccordionComponent component = null;
+                if (selected instanceof VmRef) {
+                    VmRef reference = (VmRef) selected;
+                    List<VmRef> vms = proxyModel.getComponents(reference.getHostRef());
+                    if (vms.contains(reference)) {
+                        component = componentFactory.getAccordionComponent(reference);
+                    } else {
+                        // try select the host relative to this vm then, since
+                        // the vm has been removed
+                        selected = reference.getHostRef();
+                    }
+                }
+                
+                if (selected instanceof HostRef) {
+                    component = getHostComponent((HostRef) selected);
+                }
+                
+                // if this is not the case, let's just not select anything
+                if (component != null) {
+                    accordion.setSelectedComponent(component);
+                }
             }
         });
     }
     
-    public void addVM(final VmRef vm) {
+    public synchronized void updateVMStatus(final VmRef vm) {
         SwingUtilities.invokeLater(new Runnable() {
             @Override
             public void run() {
-                model.addComponent(vm.getHostRef(), vm);
-            }
-        });
-    }
-
-    public void removeVM(final VmRef vm) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                model.removeComponent(vm.getHostRef(), vm);
+                if (filter(vmFilters, vm)) {
+                    proxyModel.removeComponent(vm.getHostRef(), vm);
+                }
+                decoratorManager.getVmDecoratorListener().decorationChanged();
             }
         });
     }
@@ -124,4 +275,97 @@
     public DecoratorProviderExtensionListener<VmRef> getVmDecoratorListener() {
         return decoratorManager.getVmDecoratorListener();
     }
+
+    public void addHostFilter(HostFilter filter) {
+        hostFilters.add(filter);
+        filter.addFilterEventListener(filterListener);
+        rebuildTree();
+    }
+
+    public void removeHostFilter(HostFilter filter) {
+        hostFilters.remove(filter);
+        filter.removeFilterEventListener(filterListener);
+        rebuildTree();
+    }
+
+    public void addVMFilter(VMFilter filter) {
+        vmFilters.add(filter);
+        filter.addFilterEventListener(filterListener);
+        rebuildTree();
+    }
+
+    public void removeVMFilter(VMFilter filter) {
+        vmFilters.remove(filter);
+        filter.removeFilterEventListener(filterListener);
+        rebuildTree();
+    }
+    
+    private synchronized void rebuildTree() {
+        Ref selected = null;
+        AccordionComponent component = accordion.getSelectedComponent();
+        if (component instanceof ReferenceProvider) {
+            // we know this is the case, because we gave the factory
+            // in the first place, but anyway... 
+            selected = ((ReferenceProvider) component).getReference();
+        }
+        
+        // operate on a copy first since we need to know which of the ones we
+        // have now was previously collapsed/expanded, we can't do this
+        // if we empty the model first
+        AccordionModel<RefPayload<HostRef>, RefPayload<VmRef>> _model = new AccordionModel<>();
+        List<HostRef> hosts = fullModel.getHeaders();
+        for (HostRef host : hosts) {
+            if (!filter(hostFilters, host)) {
+                
+                RefPayload<HostRef> hostPayload = new RefPayload<>(); 
+                hostPayload.reference = host;
+                hostPayload.expanded = accordion.isExpanded(host);
+
+                _model.addHeader(hostPayload);
+                List<VmRef> vms = fullModel.getComponents(host);
+                for (VmRef vm : vms) {
+                    if (!filter(vmFilters, vm)) {
+                        
+                        RefPayload<VmRef> vmPayload = new RefPayload<>(); 
+                        vmPayload.reference = vm;                        
+                        _model.addComponent(hostPayload, vmPayload);
+                    }
+                }
+            }
+        }
+        
+        // clear and refill, then expand as appropriate
+        proxyModel.clear();
+        List<RefPayload<HostRef>> payloadsHosts = _model.getHeaders();
+        for (RefPayload<HostRef> host : payloadsHosts) {
+            addHostToProxy(host.reference);
+            
+            List<RefPayload<VmRef>> vms = _model.getComponents(host);
+            for (RefPayload<VmRef> vm : vms) {
+                addVmToProxy(vm.reference);
+            }
+            
+            // need to do this after we add content to the host
+            // or it won't take effect
+            setAccordionExpanded(host.reference, host.expanded);
+        }
+        
+        // now select the entry that was originally selected, or its parent...
+        // ... or nothing
+        if (selected != null) {
+            selectComponent(selected);
+        }
+    }
+    
+    private class FilterListener implements ActionListener<Filter.FilterEvent> {
+        @Override
+        public void actionPerformed(ActionEvent<FilterEvent> actionEvent) {
+            rebuildTree();
+        }
+    }
+    
+    private class RefPayload<R extends Ref> {
+        R reference;
+        boolean expanded;
+    }
 }
\ No newline at end of file
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImplTest.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImplTest.java	Mon Oct 28 16:27:18 2013 +0100
@@ -315,23 +315,23 @@
         verify(view).showMainWindow();
     }
     
-    @Test
-    public void verifyUpdateHostsVMsLoadsCorrectVMWithFilter() {
-
-        VmRef ref1 = mock(VmRef.class);
-        when(ref1.getStringID()).thenReturn("test1");
-        when(ref1.getName()).thenReturn("test1");
-        
-        VmRef ref2 = mock(VmRef.class);
-        when(ref2.getStringID()).thenReturn("test2");
-        when(ref2.getName()).thenReturn("test2");
-        
-        controller.setHostVmTreeFilter("test1");
-                
-        Filter<VmRef> filter = controller.getVmFilter();
-        assertTrue(filter.matches(ref1));
-        assertFalse(filter.matches(ref2));
-    }
+//    @Test
+//    public void verifyUpdateHostsVMsLoadsCorrectVMWithFilter() {
+//
+//        VmRef ref1 = mock(VmRef.class);
+//        when(ref1.getStringID()).thenReturn("test1");
+//        when(ref1.getName()).thenReturn("test1");
+//        
+//        VmRef ref2 = mock(VmRef.class);
+//        when(ref2.getStringID()).thenReturn("test2");
+//        when(ref2.getName()).thenReturn("test2");
+//        
+//        controller.setHostVmTreeFilter("test1");
+//                
+//        Filter<VmRef> filter = controller.getVmFilter();
+//        assertTrue(filter.matches(ref1));
+//        assertFalse(filter.matches(ref2));
+//    }
     
 //    private void assertEqualCollection(Collection<?> expected, Collection<?> actual) {
 //        assertEquals(expected.size(), actual.size());
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainWindowTest.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainWindowTest.java	Mon Oct 28 16:27:18 2013 +0100
@@ -36,10 +36,8 @@
 
 package com.redhat.thermostat.client.swing.internal;
 
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.isA;
 import static org.mockito.Mockito.atLeastOnce;
@@ -48,7 +46,6 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import java.awt.event.MouseEvent;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -65,25 +62,19 @@
 import org.fest.swing.exception.ComponentLookupException;
 import org.fest.swing.fixture.FrameFixture;
 import org.fest.swing.fixture.JMenuItemFixture;
-import org.fest.swing.fixture.JTextComponentFixture;
-import org.fest.swing.fixture.JTreeFixture;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
 
-import com.redhat.thermostat.common.Filter;
-import com.redhat.thermostat.client.swing.components.SearchField;
-import com.redhat.thermostat.client.ui.ContextAction;
 import com.redhat.thermostat.client.ui.Decorator;
 import com.redhat.thermostat.client.ui.DecoratorProvider;
-import com.redhat.thermostat.client.ui.HostContextAction;
 import com.redhat.thermostat.client.ui.MenuAction;
 import com.redhat.thermostat.common.ActionEvent;
 import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.Filter;
 import com.redhat.thermostat.shared.locale.LocalizedString;
 import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.core.HostsVMsLoader;
@@ -163,17 +154,6 @@
         verify(decorator, atLeastOnce()).getLabel("fluffhost2");
     }
     
-//    @Category(GUITest.class)
-//    @Test
-//    public void testHostVMTreeFilterPropertySupport() {
-//        String SEARCH_TEXT = "test";
-//        frameFixture.show();
-//        JTextComponentFixture hostVMTreeFilterField = frameFixture.textBox(SearchField.VIEW_NAME);
-//        hostVMTreeFilterField.enterText(SEARCH_TEXT);
-//
-//        verify(l, times(SEARCH_TEXT.length())).actionPerformed(new ActionEvent<MainView.Action>(window, MainView.Action.HOST_VM_TREE_FILTER));
-//    }
-
     @Category(GUITest.class)
     @Test
     public void verifyThatCloseFiresShutdownEvent() {
@@ -235,20 +215,6 @@
         verify(l).actionPerformed(new ActionEvent<MainView.Action>(window, MainView.Action.SHOW_AGENT_CONFIG));
     }
 
-
-    // FIXME: re-add when history mode is back
-    //@Category(GUITest.class)
-    //@Test
-    public void verifyThatHistorySwitchTriggersEvent() {
-        frameFixture.show();
-        JMenuItemFixture menuItem = frameFixture.menuItem("historyModeSwitch");
-        menuItem.click();
-        frameFixture.close();
-        frameFixture.requireNotVisible();
-
-        verify(l).actionPerformed(new ActionEvent<MainView.Action>(window, MainView.Action.SWITCH_HISTORY_MODE));
-    }
-
     @Category(GUITest.class)
     @Test
     public void addRemoveMenu() {
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/VMMonitorControllerTest.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/VMMonitorControllerTest.java	Mon Oct 28 16:27:18 2013 +0100
@@ -95,13 +95,13 @@
         
         networkListener.actionPerformed(event);
         
-        verify(treeController).addHost(host1);
+        verify(treeController).registerHost(host1);
         
         event = new ActionEvent<NetworkMonitor.Action>(networkMonitor,
                                                        Action.HOST_REMOVED);
         event.setPayload(host1);
         networkListener.actionPerformed(event);
 
-        verify(treeController).removeHost(host1);
+        verify(treeController).updateHostStatus(host1);
     }
 }
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/accordion/AccordionModelTest.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/accordion/AccordionModelTest.java	Mon Oct 28 16:27:18 2013 +0100
@@ -36,13 +36,92 @@
 
 package com.redhat.thermostat.client.swing.internal.accordion;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.List;
 
 import org.junit.Test;
 
 public class AccordionModelTest {
     
     @Test
+    public void testAccessHeader() {
+        AccordionModel<String, String> testModel = new AccordionModel<>();
+        testModel.addComponent("test0", "testComponent0");
+        testModel.addComponent("test0", "testComponent1");
+        testModel.addComponent("test0", "testComponent2");
+        testModel.addComponent("test1", "testComponent3");
+        testModel.addHeader("test2");
+        
+        List<String> result = testModel.getHeaders();
+        assertEquals(3, result.size());
+
+        assertTrue(result.contains("test0"));
+        assertTrue(result.contains("test1"));
+        assertTrue(result.contains("test2"));
+        
+        testModel.addHeader("test3");
+        testModel.addHeader("test4");
+        testModel.addHeader("test5");
+
+        result = testModel.getHeaders();
+        assertEquals(6, result.size());
+
+        assertTrue(result.contains("test0"));
+        assertTrue(result.contains("test1"));
+        assertTrue(result.contains("test2"));
+        assertTrue(result.contains("test3"));
+        assertTrue(result.contains("test4"));
+        assertTrue(result.contains("test5"));
+        
+        testModel.removeHeader("test0");
+        
+        result = testModel.getHeaders();
+        assertEquals(5, result.size());
+        assertFalse(result.contains("test0"));
+    }
+
+    @Test
+    public void testAccessComponents() {
+        AccordionModel<String, String> testModel = new AccordionModel<>();
+        testModel.addComponent("test0", "testComponent0");
+        testModel.addComponent("test0", "testComponent1");
+        testModel.addComponent("test0", "testComponent2");
+        testModel.addComponent("test1", "testComponent3");
+        testModel.addComponent("test1", "testComponent4");
+        
+        List<String> result = testModel.getComponents("test0");
+        assertEquals(3, result.size());
+        
+        assertTrue(result.contains("testComponent0"));
+        assertTrue(result.contains("testComponent1"));
+        assertTrue(result.contains("testComponent2"));
+        
+        result = testModel.getComponents("test1");
+        assertEquals(2, result.size());
+        
+        assertTrue(result.contains("testComponent3"));
+        assertTrue(result.contains("testComponent4"));
+        
+        result = testModel.getComponents("test2");
+        assertNotNull(result);
+        assertTrue(result.isEmpty());
+        
+        testModel.addComponent("test1", "testComponent5");
+        result = testModel.getComponents("test1");
+        assertEquals(3, result.size());
+        
+        testModel.removeComponent("test0", "testComponent1");
+        
+        result = testModel.getComponents("test0");
+        assertEquals(2, result.size());
+        assertFalse(result.contains("testComponent1"));
+    }
+    
+    @Test
     public void testAddRemove() {
         
         final int [] results = new int[4];
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/vmlist/controller/HostTreeControllerTest.java	Mon Oct 28 16:27:18 2013 +0100
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2012, 2013 Red Hat, Inc.
+ * 
+ * This file is part of Thermostat.
+ * 
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ * 
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ * 
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ * 
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.swing.internal.vmlist.controller;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+import java.util.List;
+
+import javax.swing.RepaintManager;
+import javax.swing.SwingUtilities;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.redhat.thermostat.client.core.vmlist.HostFilter;
+import com.redhat.thermostat.client.core.vmlist.VMFilter;
+import com.redhat.thermostat.client.swing.internal.accordion.Accordion;
+import com.redhat.thermostat.client.swing.internal.accordion.AccordionModel;
+import com.redhat.thermostat.client.swing.internal.vmlist.HostTreeComponentFactory;
+import com.redhat.thermostat.storage.core.HostRef;
+import com.redhat.thermostat.storage.core.VmRef;
+
+public class HostTreeControllerTest {
+
+    private Accordion<HostRef, VmRef> accordion;
+    private DecoratorManager decoratorManager;
+    private HostTreeComponentFactory componentFactory;
+    private AccordionModel<HostRef, VmRef> proxyModel;
+    private DecoratorProviderExtensionListener hostDecoratorListener;
+    private DecoratorProviderExtensionListener vmDecoratorListener;
+    
+    @BeforeClass
+    public static void setUpOnce() {
+        // This is needed because some other test may have installed the
+        // EDT violation checker repaint manager.
+        RepaintManager.setCurrentManager(new RepaintManager());
+    }
+    
+    @Before
+    @SuppressWarnings("unchecked")
+    public void setup() {
+        accordion = mock(Accordion.class);
+        decoratorManager = mock(DecoratorManager.class);
+        componentFactory = mock(HostTreeComponentFactory.class);
+        
+        proxyModel = new AccordionModel<>();
+        when(accordion.getModel()).thenReturn(proxyModel);
+        
+        hostDecoratorListener = mock(DecoratorProviderExtensionListener.class);
+        vmDecoratorListener = mock(DecoratorProviderExtensionListener.class);
+        when(decoratorManager.getVmDecoratorListener()).thenReturn(vmDecoratorListener);
+        when(decoratorManager.getHostDecoratorListener()).thenReturn(hostDecoratorListener);
+    }
+    
+    private void waitForSwing() {
+        try {
+            SwingUtilities.invokeAndWait(new Runnable() {
+                @Override
+                public void run() {
+                    // just wait :)
+                }
+            });
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+    
+    private abstract class TestHostFilter extends HostFilter {
+        boolean filter;
+        @Override
+        public final boolean matches(HostRef toMatch) {
+            if (!filter) return true;
+            
+            return matchesImpl(toMatch);
+        }
+        
+        protected abstract boolean matchesImpl(HostRef toMatch);
+        
+        public void toggle() {
+            filter = !this.filter;
+            notify(FilterEvent.FILTER_CHANGED);
+        }
+    }
+    
+    private abstract class TestVMFilter extends VMFilter {
+        boolean filter;
+        @Override
+        public final boolean matches(VmRef toMatch) {
+            if (!filter) return true;
+            
+            return matchesImpl(toMatch);
+        }
+        
+        protected abstract boolean matchesImpl(VmRef toMatch);
+        
+        public void toggle() {
+            filter = !this.filter;
+            notify(FilterEvent.FILTER_CHANGED);
+        }
+    }
+    
+    @Test
+    public void testController() {
+        HostTreeController controller =
+                new HostTreeController(accordion, decoratorManager,
+                                       componentFactory);
+ 
+        // Add without filters
+        
+        HostRef host0 = new HostRef("0", "0");
+        HostRef host1 = new HostRef("1", "1");
+        
+        controller.registerHost(host0);
+        controller.registerHost(host1);
+        
+        waitForSwing();
+        
+        // check if our model contains everything it's supposed to
+        List<HostRef> headers = proxyModel.getHeaders();
+        assertEquals(2, headers.size());
+        assertTrue(headers.contains(host0));
+        assertTrue(headers.contains(host1));
+        
+        // now with filter
+        
+        TestHostFilter filter1 = new TestHostFilter() {
+            @Override
+            protected boolean matchesImpl(HostRef toMatch) {
+                return (toMatch.getName().equals("0"));
+            }
+        };
+        // enable the filter first
+        filter1.toggle();
+        
+        controller.addHostFilter(filter1);
+        
+        waitForSwing();
+        
+        // we need to check that the model is rebuild with the appropriate
+        // hosts, the filter should only let one host in
+        headers = proxyModel.getHeaders();
+        assertEquals(1, headers.size());
+        assertTrue(headers.contains(host0));
+        assertFalse(headers.contains(host1));
+                
+        // this should cause the tree to rebuild with all hosts in place again
+        filter1.toggle();
+        
+        waitForSwing();
+        
+        headers = proxyModel.getHeaders();
+        assertEquals(2, headers.size());
+        assertTrue(headers.contains(host0));
+        assertTrue(headers.contains(host1));
+        
+        // now on with vms, filter not enabled at first
+        TestVMFilter filter2 = new TestVMFilter() {
+            @Override
+            protected boolean matchesImpl(VmRef toMatch) {
+                return (toMatch.getName().equals("vm0"));
+            }
+        };
+        
+        controller.addVMFilter(filter2);
+        
+        waitForSwing();
+        
+        headers = proxyModel.getHeaders();
+        assertEquals(2, headers.size());
+        
+        VmRef vm0 = new VmRef(host0, "0", 0, "vm0");
+        VmRef vm1 = new VmRef(host0, "1", 1, "vm1");
+        VmRef vm2 = new VmRef(host1, "2", 2, "vm2");
+
+        controller.registerVM(vm0);
+        controller.registerVM(vm1);
+        controller.registerVM(vm2);
+        
+        waitForSwing();
+        
+        List<VmRef> components  = proxyModel.getComponents(host0);
+        assertEquals(2, components.size());
+        assertTrue(components.contains(vm0));
+        assertTrue(components.contains(vm1));
+        
+        components  = proxyModel.getComponents(host1);
+        assertEquals(1, components.size());
+        assertTrue(components.contains(vm2));
+
+        filter2.toggle();
+
+        waitForSwing();
+
+        components  = proxyModel.getComponents(host0);
+        assertEquals(1, components.size());
+        assertTrue(components.contains(vm0));
+        assertFalse(components.contains(vm1));
+        
+        components  = proxyModel.getComponents(host1);
+        assertTrue(components.isEmpty());
+        
+        // now test if controller reacts to updates
+        
+        controller.updateVMStatus(vm0);
+        
+        waitForSwing();
+
+        verify(vmDecoratorListener).decorationChanged();
+        
+        controller.updateHostStatus(host0);
+
+        waitForSwing();
+        
+        verify(hostDecoratorListener).decorationChanged();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/AllPassFilter.java	Mon Oct 28 16:27:18 2013 +0100
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2012, 2013 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.common;
+
+/**
+ * A {@link Filter} that passes everything.
+ */
+public class AllPassFilter<T> extends Filter<T> {
+    public boolean matches(T toMatch) {
+        return true;
+    };
+}
--- a/common/core/src/main/java/com/redhat/thermostat/common/Filter.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/Filter.java	Mon Oct 28 16:27:18 2013 +0100
@@ -36,13 +36,67 @@
 
 package com.redhat.thermostat.common;
 
+import com.redhat.thermostat.annotations.ExtensionPoint;
+
 /**
  * A {@link Filter} decides if some information matches what this
- * {@link Filter} is designed to work with.
+ * filter is designed to work with. The exact meaning of the
+ * word "match" depends on the context this filter is applied.
+ * 
+ * <br /><br />
+ * 
+ * For example, a {@link String} filter that match for all the input containing
+ * the word "test" would return {@code true} for both "a test" or "testing",
+ * but {@code false} for the mispelled word "tesst". This example filter could
+ * then be used to implement a search function, by testing various strings
+ * and only showing the ones that match this filter.
+ * 
+ * <br /><br />
+ * 
+ * Filters may change their behavior due to external events in a certain
+ * context. In such cases, the filter managers specific to those context should
+ * register as {@link FilterEvent} listeners and the {@link Filter}
+ * implementation should notify of {@link FilterEvent#FILTER_CHANGED} events.
+ * 
+ * <br /><br />
+ * 
+ * As an example let's take again our {@link String} filter. If such filter
+ * was used in a search context, the filter could react to user input and
+ * change the string to be used as matcher. At each matcher change, it should
+ * notify its listeners that such change occurred in order to allow correct
+ * re-processing of the filter.
  */
-public interface Filter<T> {
+@ExtensionPoint
+public abstract class Filter<T> {
 
-    boolean matches(T toMatch);
+    public enum FilterEvent {
+        FILTER_CHANGED,
+    }
+    
+    private final ActionNotifier<FilterEvent> notifier;
+    public Filter() {
+        notifier = new ActionNotifier<>(this);
+    }
+    
+    /**
+     * Return {@code true} if this filter match the given input, {@code false}
+     * otherwise. 
+     */
+    public abstract boolean matches(T toMatch);
 
+    public void addFilterEventListener(ActionListener<FilterEvent> listener) {
+        notifier.addActionListener(listener);
+    }
+    
+    public void removeFilterEventListener(ActionListener<FilterEvent> listener) {
+        notifier.removeActionListener(listener);
+    }
+    
+    /**
+     * Notify all the listeners that a change occurred in this filter.
+     */
+    protected void notify(FilterEvent action) {
+        notifier.fireAction(action);
+    }    
 }
 
--- a/killvm/client-swing/src/main/java/com/redhat/thermostat/killvm/client/internal/KillVMAction.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/killvm/client-swing/src/main/java/com/redhat/thermostat/killvm/client/internal/KillVMAction.java	Mon Oct 28 16:27:18 2013 +0100
@@ -111,7 +111,7 @@
         return new LocalAndAliveFilter();
     }
 
-    private class LocalAndAliveFilter implements Filter<VmRef> {
+    private class LocalAndAliveFilter extends Filter<VmRef> {
 
         @Override
         public boolean matches(VmRef ref) {
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/monitor/HostMonitor.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/monitor/HostMonitor.java	Mon Oct 28 16:27:18 2013 +0100
@@ -36,7 +36,10 @@
 
 package com.redhat.thermostat.storage.monitor;
 
+import java.util.List;
+
 import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.Filter;
 import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.core.VmRef;
 
@@ -59,4 +62,10 @@
      * Removes the listener to the given {@link HostRef}
      */
     void removeHostChangeListener(HostRef host, ActionListener<Action> listener);
+
+    /**
+     * Returns all the {@link VmRef} tracked by the given host and matching the
+     * given {@link Filter}.
+     */
+    List<VmRef> getVirtualMachines(HostRef host, Filter<VmRef> matcher);
 }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/monitor/NetworkMonitor.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/monitor/NetworkMonitor.java	Mon Oct 28 16:27:18 2013 +0100
@@ -36,7 +36,10 @@
 
 package com.redhat.thermostat.storage.monitor;
 
+import java.util.List;
+
 import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.Filter;
 import com.redhat.thermostat.storage.core.HostRef;
 
 /**
@@ -48,7 +51,12 @@
         HOST_ADDED,
         HOST_REMOVED,
     }
-     
+
+    /**
+     * Returns all the {@link HostRef} tracked matching the given {@link Filter}.
+     */
+    List<HostRef> getHosts(Filter<HostRef> matcher);
+    
     void addNetworkChangeListener(ActionListener<Action> listener);
     void removeNetworkChangeListener(ActionListener<Action> listener);
 }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/monitor/internal/HostMonitorImpl.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/monitor/internal/HostMonitorImpl.java	Mon Oct 28 16:27:18 2013 +0100
@@ -36,16 +36,21 @@
 
 package com.redhat.thermostat.storage.monitor.internal;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.TimeUnit;
 
 import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.ActionNotifier;
+import com.redhat.thermostat.common.Filter;
 import com.redhat.thermostat.common.Pair;
 import com.redhat.thermostat.common.Timer;
 import com.redhat.thermostat.common.TimerFactory;
 import com.redhat.thermostat.storage.core.HostRef;
+import com.redhat.thermostat.storage.core.VmRef;
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.storage.monitor.HostMonitor;
 
@@ -69,6 +74,18 @@
     }
     
     @Override
+    public List<VmRef> getVirtualMachines(HostRef host, Filter<VmRef> matcher) {
+        List<VmRef> vms = new ArrayList<>();
+        Collection<VmRef> _vms = vmDao.getVMs(host);
+        for (VmRef vm : _vms) {
+            if (matcher.matches(vm)) {
+                vms.add(vm);
+            }
+        }
+        return vms;
+    }
+    
+    @Override
     public void addHostChangeListener(HostRef host,
                                       ActionListener<Action> listener)
     {
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/monitor/internal/NetworkMonitorImpl.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/monitor/internal/NetworkMonitorImpl.java	Mon Oct 28 16:27:18 2013 +0100
@@ -36,12 +36,17 @@
 
 package com.redhat.thermostat.storage.monitor.internal;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 
 import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.ActionNotifier;
+import com.redhat.thermostat.common.Filter;
 import com.redhat.thermostat.common.Timer;
 import com.redhat.thermostat.common.TimerFactory;
+import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.dao.HostInfoDAO;
 import com.redhat.thermostat.storage.monitor.NetworkMonitor;
 
@@ -52,9 +57,12 @@
     protected final ActionNotifier<NetworkMonitor.Action> notifier;
     
     private Timer timer;
+    private HostInfoDAO hostDAO;
     
     public NetworkMonitorImpl(TimerFactory timerFactory, HostInfoDAO hostDAO) {
         
+        this.hostDAO = hostDAO;
+
         notifier = new ActionNotifier<>(this);
         
         timer = timerFactory.createTimer();
@@ -65,6 +73,18 @@
     }
     
     @Override
+    public List<HostRef> getHosts(Filter<HostRef> matcher) {
+        List<HostRef> hosts = new ArrayList<>();
+        Collection<HostRef> _hosts = hostDAO.getHosts();
+        for (HostRef host : _hosts) {
+            if (matcher.matches(host)) {
+                hosts.add(host);
+            }
+        }
+        return hosts;
+    }
+    
+    @Override
     public void addNetworkChangeListener(ActionListener<Action> listener) {
         notifier.addActionListener(listener);
         if (notifier.listenersCount() == 1) {
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/monitor/internal/HostMonitorImplTest.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/monitor/internal/HostMonitorImplTest.java	Mon Oct 28 16:27:18 2013 +0100
@@ -45,6 +45,8 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertEquals;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
@@ -53,10 +55,13 @@
 
 import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.ActionNotifier;
+import com.redhat.thermostat.common.AllPassFilter;
+import com.redhat.thermostat.common.Filter;
 import com.redhat.thermostat.common.Pair;
 import com.redhat.thermostat.common.Timer;
 import com.redhat.thermostat.common.TimerFactory;
 import com.redhat.thermostat.storage.core.HostRef;
+import com.redhat.thermostat.storage.core.VmRef;
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.storage.monitor.HostMonitor;
 
@@ -64,11 +69,66 @@
 
     private VmInfoDAO vmDao;
     private TimerFactory timerFactory;
+    private Timer timer1;
     
     @Before
     public void setup() {
         vmDao = mock(VmInfoDAO.class);
         timerFactory = mock(TimerFactory.class);
+        timer1 = mock(Timer.class);
+        when(timerFactory.createTimer()).thenReturn(timer1);
+    }
+    
+    @Test
+    public void testGetVirtualMachines() {
+        List<VmRef> testData = new ArrayList<>(); 
+        List<VmRef> testData2 = new ArrayList<>(); 
+
+        HostRef host0 = new HostRef("0", "0");
+        HostRef host1 = new HostRef("1", "1");
+        
+        VmRef vm0 = new VmRef(host0, "0", 0, "0");
+        VmRef vm1 = new VmRef(host0, "1", 1, "2");
+        VmRef vm2 = new VmRef(host0, "2", 2, "3");
+        VmRef vm3 = new VmRef(host0, "3", 3, "3");
+        VmRef vm4 = new VmRef(host0, "4", 4, "4");
+        VmRef vm5 = new VmRef(host0, "5", 5, "5");
+    
+        testData.add(vm0);
+        testData.add(vm1);
+        testData.add(vm2);
+        testData.add(vm3);
+        testData.add(vm4);
+        testData.add(vm5);
+        
+        when(vmDao.getVMs(host0)).thenReturn(testData);
+        when(vmDao.getVMs(host1)).thenReturn(testData2);
+
+        HostMonitor monitor = new HostMonitorImpl(timerFactory, vmDao);
+        List<VmRef> vms = monitor.getVirtualMachines(host0, new AllPassFilter<VmRef>());
+        assertEquals(testData.size(), vms.size());
+        for (VmRef ref : testData) {
+            assertTrue(vms.contains(ref));
+        }
+        
+        vms = monitor.getVirtualMachines(host1, new AllPassFilter<VmRef>());
+        assertEquals(0, vms.size());
+
+        Filter<VmRef> bandFilter = new Filter<VmRef>() {
+            @Override
+            public boolean matches(VmRef toMatch) {
+                return toMatch.getName().equals("1") ||
+                       toMatch.getName().equals("2") ||
+                       toMatch.getName().equals("3");
+            }
+        };
+        
+        vms = monitor.getVirtualMachines(host0, bandFilter);
+        assertEquals(3, vms.size());
+        
+        assertTrue(vms.contains(vm1));
+        assertTrue(vms.contains(vm2));
+        assertTrue(vms.contains(vm3));
     }
     
     @SuppressWarnings("unchecked")
@@ -77,9 +137,6 @@
         ActionListener<HostMonitor.Action> listener1 = mock(ActionListener.class);
         ActionListener<HostMonitor.Action> listener2 = mock(ActionListener.class);
 
-        Timer timer1 = mock(Timer.class);
-        when(timerFactory.createTimer()).thenReturn(timer1);
-        
         HostRef host1 = new HostRef("0", "0");
 
         HostMonitor monitor = new HostMonitorImpl(timerFactory, vmDao);
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/monitor/internal/NetworkMonitorImplTest.java	Tue Oct 22 17:48:37 2013 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/monitor/internal/NetworkMonitorImplTest.java	Mon Oct 28 16:27:18 2013 +0100
@@ -40,15 +40,22 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.mockito.Mockito.times;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 
 import org.junit.Before;
 import org.junit.Test;
 
 import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.AllPassFilter;
+import com.redhat.thermostat.common.Filter;
 import com.redhat.thermostat.common.Timer;
 import com.redhat.thermostat.common.TimerFactory;
+import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.dao.HostInfoDAO;
 import com.redhat.thermostat.storage.monitor.NetworkMonitor;
 import com.redhat.thermostat.storage.monitor.NetworkMonitor.Action;
@@ -57,11 +64,58 @@
 
     private HostInfoDAO hostDao;
     private TimerFactory timerFactory;
-    
+    private Timer timer;
+
     @Before
     public void setup() {
         hostDao = mock(HostInfoDAO.class);
         timerFactory = mock(TimerFactory.class);
+        timer = mock(Timer.class);
+        when(timerFactory.createTimer()).thenReturn(timer);
+    }
+    
+    @Test
+    public void testGetHost() {
+        List<HostRef> testData = new ArrayList<>();
+        HostRef ref0 = new HostRef("0", "test#0");
+        HostRef ref1 = new HostRef("1", "test#1");
+        HostRef ref2 = new HostRef("2", "test#2");
+        HostRef ref3 = new HostRef("3", "test#3");
+        HostRef ref4 = new HostRef("4", "test#4");
+        HostRef ref5 = new HostRef("5", "test#5");
+        
+        testData.add(ref0);
+        testData.add(ref1);
+        testData.add(ref2);
+        testData.add(ref3);
+        testData.add(ref4);
+        testData.add(ref5);
+        
+        when(hostDao.getHosts()).thenReturn(testData);
+        
+        NetworkMonitor monitor = new NetworkMonitorImpl(timerFactory, hostDao);
+        List<HostRef> hosts = monitor.getHosts(new AllPassFilter<HostRef>());
+        assertEquals(testData.size(), hosts.size());
+        
+        for (HostRef ref : testData) {
+            assertTrue(hosts.contains(ref));
+        }
+        
+        Filter<HostRef> bandFilter = new Filter<HostRef>() {
+            @Override
+            public boolean matches(HostRef toMatch) {
+                return toMatch.getName().equals("test#1") ||
+                       toMatch.getName().equals("test#2") ||
+                       toMatch.getName().equals("test#3");
+            }
+        };
+        
+        hosts = monitor.getHosts(bandFilter);
+        assertEquals(3, hosts.size());
+        
+        assertTrue(hosts.contains(ref1));
+        assertTrue(hosts.contains(ref2));
+        assertTrue(hosts.contains(ref3));
     }
     
     @SuppressWarnings("unchecked")
@@ -70,9 +124,6 @@
         
         ActionListener<Action> listener1 = mock(ActionListener.class);
         ActionListener<Action> listener2 = mock(ActionListener.class);
-
-        Timer timer = mock(Timer.class);
-        when(timerFactory.createTimer()).thenReturn(timer);
         
         NetworkMonitor monitor = new NetworkMonitorImpl(timerFactory, hostDao);
         monitor.addNetworkChangeListener(listener1);