changeset 1019:f84a49f6c797 0.6-branch

Remove UiFacadeFactory This commit removes UiFacadeFactory. Previous uses of this class have been converted to use trackers instead. This includes accessing the Host and VmInfoDAOs, and Host/VMContextActions. Instead of using UiFacadeFactory, these trackers now have getter methods for retrieving the list of tracked services. Trackers have been moved from ThermostatActivator to MainControllerImpl as neither the activator nor Main have any use for the tracked services. Shutdown has also been modified due to MainControllerImpl having trackers. When the shutdown latch in Main is triggered, Main then calls shutdownApplication in MainControllerImpl to close the trackers and perform other previously existing cleanup. I have also added a test for VMContextActionServiceTracker, since only the Host version was tested before. I have also encapsulated the runnable that instantiates MainControllerImpl in Main into a nested class, allowing us to use a mock in MainTest instead of actually instantiating it. Reviewed-by: neugens Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-February/005944.html
author Elliott Baron <ebaron@redhat.com>
date Mon, 04 Mar 2013 17:04:10 -0500
parents d33dc1c2d0ad
children 855b2ad34646
files client/core/src/main/java/com/redhat/thermostat/client/ui/HostInformationController.java client/core/src/main/java/com/redhat/thermostat/client/ui/UiFacadeFactory.java client/core/src/main/java/com/redhat/thermostat/client/ui/VmInformationController.java client/core/src/test/java/com/redhat/thermostat/client/ui/HostInformationControllerTest.java client/core/src/test/java/com/redhat/thermostat/client/ui/VmInformationControllerTest.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/Main.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/UiFacadeFactoryImpl.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/HostContextActionServiceTracker.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/InformationServiceTracker.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/ThermostatActivator.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/VMContextActionServiceTracker.java client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainTest.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/osgi/HostContextActionServiceTrackerTest.java client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/osgi/VMContextActionServiceTrackerTest.java
diffstat 16 files changed, 391 insertions(+), 535 deletions(-) [+]
line wrap: on
line diff
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/HostInformationController.java	Tue Feb 26 15:02:37 2013 -0500
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/HostInformationController.java	Mon Mar 04 17:04:10 2013 -0500
@@ -51,10 +51,10 @@
 
     private final HostInformationView view;
 
-    public HostInformationController(UiFacadeFactory uiFacadeFactory, HostRef ref, HostInformationViewProvider provider) {
+    public HostInformationController(List<InformationService<HostRef>> hostInfoServices,
+            HostRef ref, HostInformationViewProvider provider) {
         view = provider.createView();
 
-        List<InformationService<HostRef>> hostInfoServices = uiFacadeFactory.getHostInformationServices();
         Collections.sort(hostInfoServices, new OrderedComparator<InformationService<HostRef>>());
         for (InformationService<HostRef> hostInfoService : hostInfoServices) {
             if (hostInfoService.getFilter().matches(ref)) {
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/UiFacadeFactory.java	Tue Feb 26 15:02:37 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * 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.ui;
-
-import java.util.Collection;
-import java.util.List;
-
-import com.redhat.thermostat.client.core.InformationService;
-import com.redhat.thermostat.client.osgi.service.HostContextAction;
-import com.redhat.thermostat.client.osgi.service.VMContextAction;
-import com.redhat.thermostat.storage.core.HostRef;
-import com.redhat.thermostat.storage.core.VmRef;
-import com.redhat.thermostat.storage.dao.HostInfoDAO;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
-
-public interface UiFacadeFactory {
-
-    void setHostInfoDao(HostInfoDAO hostInfoDao);
-
-    void setVmInfoDao(VmInfoDAO vmInfoDAO);
-
-    public MainWindowController getMainWindow();
-
-    public SummaryController getSummary();
-
-    public HostInformationController getHostController(HostRef ref);
-    
-    List<InformationService<HostRef>> getHostInformationServices();
-
-    void addHostInformationService(InformationService<HostRef> hostInfoService);
-
-    void removeHostInformationService(InformationService<HostRef> hostInfoService);
-
-    public VmInformationController getVmController(VmRef ref);
-
-    List<InformationService<VmRef>> getVmInformationServices();
-
-    void addVmInformationService(InformationService<VmRef> vmInfoService);
-
-    void removeVmInformationService(InformationService<VmRef> vmInfoService);
-
-    Collection<HostContextAction> getHostContextActions();
-    void addHostContextAction(HostContextAction action);
-    void removeHostContextAction(HostContextAction action);
-
-    Collection<VMContextAction> getVMContextActions();
-    void addVMContextAction(VMContextAction service);
-
-    public void shutdown();
-
-    public void shutdown(int exitCode);
-
-    public void awaitShutdown() throws InterruptedException;
-    
-    boolean isShutdown();
-
-}
-
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/VmInformationController.java	Tue Feb 26 15:02:37 2013 -0500
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/VmInformationController.java	Mon Mar 04 17:04:10 2013 -0500
@@ -45,21 +45,16 @@
 import com.redhat.thermostat.client.core.views.VmInformationView;
 import com.redhat.thermostat.client.core.views.VmInformationViewProvider;
 import com.redhat.thermostat.common.OrderedComparator;
-import com.redhat.thermostat.common.utils.OSGIUtils;
 import com.redhat.thermostat.storage.core.VmRef;
 
 public class VmInformationController {
 
     private final VmInformationView view;
 
-    public VmInformationController(UiFacadeFactory uiFacadeFactory, VmRef vmRef, VmInformationViewProvider provider) {
-        this(OSGIUtils.getInstance(), uiFacadeFactory, vmRef, provider);
-    }
-    
-    VmInformationController(OSGIUtils serviceProvider, UiFacadeFactory uiFacadeFactory, VmRef vmRef, VmInformationViewProvider provider) {
+    public VmInformationController(List<InformationService<VmRef>> vmInfoServices, 
+            VmRef vmRef, VmInformationViewProvider provider) {
         view = provider.createView();
 
-        List<InformationService<VmRef>> vmInfoServices = uiFacadeFactory.getVmInformationServices();
         Collections.sort(vmInfoServices, new OrderedComparator<InformationService<VmRef>>());
         for (InformationService<VmRef> vmInfoService : vmInfoServices) {
             if (vmInfoService.getFilter().matches(vmRef)) {
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/HostInformationControllerTest.java	Tue Feb 26 15:02:37 2013 -0500
+++ b/client/core/src/test/java/com/redhat/thermostat/client/ui/HostInformationControllerTest.java	Mon Mar 04 17:04:10 2013 -0500
@@ -59,14 +59,12 @@
 
     private static final Filter<HostRef> FILTER = new NameMatchingRefFilter<>();
 
-    private UiFacadeFactory uiFacadeFactory;
     private HostRef ref;
     private HostInformationViewProvider provider;
     private HostInformationView view;
 
     @Before
     public void setup() {
-        uiFacadeFactory = mock(UiFacadeFactory.class);
         ref = mock(HostRef.class);
         provider = mock(HostInformationViewProvider.class);
         view = mock(HostInformationView.class);
@@ -80,7 +78,7 @@
         // Mock services
         List<InformationService<HostRef>> services = mockServices(orderValues);
 
-        new HostInformationController(uiFacadeFactory, ref, provider);
+        new HostInformationController(new ArrayList<>(services), ref, provider);
 
         InOrder order = inOrder(services.get(0), services.get(1),
                 services.get(2), services.get(3), services.get(4));
@@ -102,8 +100,6 @@
             when(service.getOrderValue()).thenReturn(order);
             services.add(service);
         }
-        // Return copy
-        when(uiFacadeFactory.getHostInformationServices()).thenReturn(new ArrayList<>(services));
         return services;
     }
 
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/VmInformationControllerTest.java	Tue Feb 26 15:02:37 2013 -0500
+++ b/client/core/src/test/java/com/redhat/thermostat/client/ui/VmInformationControllerTest.java	Mon Mar 04 17:04:10 2013 -0500
@@ -59,14 +59,12 @@
 
     private static final Filter<VmRef> FILTER = new NameMatchingRefFilter<>();
 
-    private UiFacadeFactory uiFacadeFactory;
     private VmRef ref;
     private VmInformationViewProvider provider;
     private VmInformationView view;
 
     @Before
     public void setup() {
-        uiFacadeFactory = mock(UiFacadeFactory.class);
         ref = mock(VmRef.class);
         provider = mock(VmInformationViewProvider.class);
         view = mock(VmInformationView.class);
@@ -80,7 +78,7 @@
         // Mock services
         List<InformationService<VmRef>> services = mockServices(orderValues);
 
-        new VmInformationController(uiFacadeFactory, ref, provider);
+        new VmInformationController(new ArrayList<>(services), ref, provider);
 
         InOrder order = inOrder(services.get(0), services.get(1),
                 services.get(2), services.get(3), services.get(4));
@@ -102,8 +100,6 @@
             when(service.getOrderValue()).thenReturn(order);
             services.add(service);
         }
-        // Return copy
-        when(uiFacadeFactory.getVmInformationServices()).thenReturn(new ArrayList<>(services));
         return services;
     }
 
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/Main.java	Tue Feb 26 15:02:37 2013 -0500
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/Main.java	Mon Mar 04 17:04:10 2013 -0500
@@ -37,7 +37,8 @@
 package com.redhat.thermostat.client.swing.internal;
 
 import java.awt.EventQueue;
-import java.util.Map;
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -57,11 +58,7 @@
 import com.redhat.thermostat.client.swing.internal.views.ClientConfigurationSwing;
 import com.redhat.thermostat.client.ui.ClientConfigReconnector;
 import com.redhat.thermostat.client.ui.ClientConfigurationController;
-import com.redhat.thermostat.client.ui.MainWindowController;
-import com.redhat.thermostat.client.ui.UiFacadeFactory;
 import com.redhat.thermostat.common.ApplicationService;
-import com.redhat.thermostat.common.MultipleServiceTracker;
-import com.redhat.thermostat.common.MultipleServiceTracker.Action;
 import com.redhat.thermostat.common.config.ClientPreferences;
 import com.redhat.thermostat.common.locale.Translate;
 import com.redhat.thermostat.common.utils.LoggingUtils;
@@ -70,8 +67,6 @@
 import com.redhat.thermostat.storage.core.DbService;
 import com.redhat.thermostat.storage.core.DbServiceFactory;
 import com.redhat.thermostat.storage.core.StorageException;
-import com.redhat.thermostat.storage.dao.HostInfoDAO;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.utils.keyring.Keyring;
 
 public class Main {
@@ -82,34 +77,39 @@
 
     private BundleContext context;
     private ApplicationService appSvc;
-    private UiFacadeFactory uiFacadeFactory;
     private DbServiceFactory dbServiceFactory;
     private Keyring keyring;
-    private MultipleServiceTracker tracker;
+    private CountDownLatch shutdown;
+    private MainWindowControllerImpl mainController;
+    private MainWindowRunnable mainWindowRunnable;
     
     public Main(BundleContext context, Keyring keyring,
-            ApplicationService appSvc, UiFacadeFactory uiFacadeFactory,
-            String[] args) {
+            ApplicationService appSvc, String[] args) {
 
         DbServiceFactory dbServiceFactory = new DbServiceFactory();
+        CountDownLatch shutdown = new CountDownLatch(1);
+        MainWindowRunnable mainWindowRunnable = new MainWindowRunnable();
 
-        init(context, appSvc, uiFacadeFactory, dbServiceFactory, keyring);
+        init(context, appSvc, dbServiceFactory, keyring, shutdown,
+                mainWindowRunnable);
     }
 
     Main(BundleContext context, ApplicationService appSvc,
-            UiFacadeFactory uiFacadeFactory, DbServiceFactory dbServiceFactory,
-            Keyring keyring) {
-        init(context, appSvc, uiFacadeFactory, dbServiceFactory, keyring);
+            DbServiceFactory dbServiceFactory, Keyring keyring,
+            CountDownLatch shutdown, MainWindowRunnable mainWindowRunnable) {
+        init(context, appSvc, dbServiceFactory, keyring, shutdown,
+                mainWindowRunnable);
     }
 
     private void init(BundleContext context, ApplicationService appSvc,
-            UiFacadeFactory uiFacadeFactory, DbServiceFactory dbServiceFactory,
-            Keyring keyring) {
+            DbServiceFactory dbServiceFactory, Keyring keyring,
+            CountDownLatch shutdown, MainWindowRunnable mainWindowRunnable) {
         this.context = context;
         this.appSvc = appSvc;
-        this.uiFacadeFactory = uiFacadeFactory;
         this.dbServiceFactory = dbServiceFactory;
         this.keyring = keyring;
+        this.shutdown = shutdown;
+        this.mainWindowRunnable = mainWindowRunnable;
     }
 
     private void setLAF() {
@@ -174,7 +174,21 @@
         tryConnecting();
 
         try {
-            uiFacadeFactory.awaitShutdown();
+            shutdown.await();
+            
+            // Shutdown MainController
+            if (mainController != null) {
+                try {
+                    SwingUtilities.invokeAndWait(new Runnable() {
+                        @Override
+                        public void run() {
+                            mainController.shutdownApplication();
+                        }
+                    });
+                } catch (InvocationTargetException e) {
+                    logger.log(Level.WARNING, "Unable to shutdown MainWindowController", e);
+                }
+            }
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();
         }
@@ -212,7 +226,7 @@
             case JOptionPane.CANCEL_OPTION:
             case JOptionPane.CLOSED_OPTION:
             case JOptionPane.NO_OPTION:
-                shutdown();
+                shutdown.countDown();
                 break;
 
             case JOptionPane.YES_OPTION:
@@ -263,7 +277,7 @@
 
         @Override
         public void abort() {
-            shutdown();
+            shutdown.countDown();
         }
     }
     
@@ -291,32 +305,7 @@
         @Override
         public void changed(ConnectionStatus newStatus) {
             if (newStatus == ConnectionStatus.CONNECTED) {
-                Class<?>[] deps = new Class<?>[] {
-                        HostInfoDAO.class,
-                        VmInfoDAO.class
-                };
-                tracker = new MultipleServiceTracker(context, deps, new Action() {
-                    
-                    @Override
-                    public void dependenciesAvailable(Map<String, Object> services) {
-                        HostInfoDAO hostInfoDAO = (HostInfoDAO) services.get(HostInfoDAO.class.getName());
-                        uiFacadeFactory.setHostInfoDao(hostInfoDAO);
-                        VmInfoDAO vmInfoDAO = (VmInfoDAO) services.get(VmInfoDAO.class.getName());
-                        uiFacadeFactory.setVmInfoDao(vmInfoDAO);
-                        
-                        showMainWindow();
-                    }
-
-                    @Override
-                    public void dependenciesUnavailable() {
-                        if (!uiFacadeFactory.isShutdown()) {
-                            // In the rare case we lose one of our deps, gracefully shutdown
-                            logger.severe("Storage unexpectedly became unavailable");
-                            shutdown();
-                        }
-                    }
-                });
-                tracker.open();
+                SwingUtilities.invokeLater(mainWindowRunnable);
             } else if (newStatus == ConnectionStatus.FAILED_TO_CONNECT) {
                 if (retry) {
                     retry = false;
@@ -327,29 +316,26 @@
                             translator.localize(LocaleResources.CONNECTION_FAILED_TO_CONNECT_DESCRIPTION),
                             translator.localize(LocaleResources.CONNECTION_FAILED_TO_CONNECT_TITLE),
                             JOptionPane.ERROR_MESSAGE);
-                    shutdown();
+                    shutdown.countDown();
                 }
             }
         }
     }
     
     public void shutdown() {
-        uiFacadeFactory.shutdown();
-        
-        if (tracker != null) {
-            tracker.close();
+        shutdown.countDown();
+    }
+    
+    /*
+     * This Runnable is extracted to a class for testing purposes.
+     */
+    class MainWindowRunnable implements Runnable {
+
+        @Override
+        public void run() {
+            mainController = new MainWindowControllerImpl(context, appSvc, shutdown);
+            mainController.showMainMainWindow();
         }
     }
-
-    private void showMainWindow() {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                MainWindowController mainController = uiFacadeFactory.getMainWindow();
-                mainController.showMainMainWindow();
-            }
-        });
-    }
-
 }
 
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImpl.java	Tue Feb 26 15:02:37 2013 -0500
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImpl.java	Mon Mar 04 17:04:10 2013 -0500
@@ -40,38 +40,48 @@
 import java.util.ArrayList;
 import java.util.List;
 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.concurrent.TimeUnit;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.InvalidSyntaxException;
 
 import com.redhat.thermostat.client.core.Filter;
+import com.redhat.thermostat.client.core.InformationService;
 import com.redhat.thermostat.client.core.NameMatchingRefFilter;
 import com.redhat.thermostat.client.core.views.AgentInformationDisplayView;
 import com.redhat.thermostat.client.core.views.AgentInformationViewProvider;
 import com.redhat.thermostat.client.core.views.ClientConfigViewProvider;
 import com.redhat.thermostat.client.core.views.ClientConfigurationView;
+import com.redhat.thermostat.client.core.views.HostInformationViewProvider;
+import com.redhat.thermostat.client.core.views.SummaryViewProvider;
+import com.redhat.thermostat.client.core.views.VmInformationViewProvider;
 import com.redhat.thermostat.client.osgi.service.ContextAction;
 import com.redhat.thermostat.client.osgi.service.DecoratorProvider;
 import com.redhat.thermostat.client.osgi.service.HostContextAction;
 import com.redhat.thermostat.client.osgi.service.MenuAction;
 import com.redhat.thermostat.client.osgi.service.VMContextAction;
 import com.redhat.thermostat.client.swing.internal.MainView.Action;
+import com.redhat.thermostat.client.swing.internal.osgi.HostContextActionServiceTracker;
+import com.redhat.thermostat.client.swing.internal.osgi.InformationServiceTracker;
+import com.redhat.thermostat.client.swing.internal.osgi.VMContextActionServiceTracker;
 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.HostInformationController;
 import com.redhat.thermostat.client.ui.MainWindowController;
 import com.redhat.thermostat.client.ui.SummaryController;
-import com.redhat.thermostat.client.ui.UiFacadeFactory;
 import com.redhat.thermostat.client.ui.VmInformationController;
 import com.redhat.thermostat.common.ActionEvent;
 import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.ApplicationInfo;
 import com.redhat.thermostat.common.ApplicationService;
+import com.redhat.thermostat.common.MultipleServiceTracker;
 import com.redhat.thermostat.common.ThermostatExtensionRegistry;
 import com.redhat.thermostat.common.Timer;
 import com.redhat.thermostat.common.Timer.SchedulingType;
@@ -102,12 +112,21 @@
 
     private MainView view;
 
-    private final HostInfoDAO hostsDAO;
-    private final VmInfoDAO vmsDAO;
+    private HostInfoDAO hostInfoDAO;
+    private VmInfoDAO vmInfoDAO;
 
+    private SummaryViewProvider summaryViewProvider;
+    private HostInformationViewProvider hostInfoViewProvider;
+    private VmInformationViewProvider vmInfoViewProvider;
+    
     private ApplicationInfo appInfo;
 
-    private UiFacadeFactory facadeFactory;
+    private InformationServiceTracker infoServiceTracker;
+    private HostContextActionServiceTracker hostContextActionTracker;
+    private VMContextActionServiceTracker vmContextActionTracker;
+    private MultipleServiceTracker depTracker;
+    
+    private CountDownLatch shutdown;
 
     private MenuRegistry menuRegistry;
     private ActionListener<ThermostatExtensionRegistry.Action> menuListener =
@@ -163,9 +182,16 @@
     private boolean showHistory;
 
     private VmInformationControllerProvider vmInfoControllerProvider;
+    
+    public MainWindowControllerImpl(BundleContext context, ApplicationService appSvc,
+            CountDownLatch shutdown) {
+        this(context, appSvc, new MainWindow(), new RegistryFactory(context), shutdown);
+    }
 
-    public MainWindowControllerImpl(ApplicationService appSvc, UiFacadeFactory facadeFactory, MainView view, RegistryFactory registryFactory, HostInfoDAO hostsDao, VmInfoDAO vmsDAO)
-    {
+    MainWindowControllerImpl(BundleContext context, ApplicationService appSvc,
+            final MainView view,
+            RegistryFactory registryFactory,
+            final CountDownLatch shutdown) {
         this.appSvc = appSvc;
         try {
             vmFilterRegistry = registryFactory.createVmFilterRegistry();
@@ -185,22 +211,62 @@
         hostFilters.add(hostFilter);
         vmFilters.add(vmFilter);
         
-        this.facadeFactory = facadeFactory;
+        this.infoServiceTracker = new InformationServiceTracker(context);
+        this.infoServiceTracker.open();
+        
+        this.hostContextActionTracker = new HostContextActionServiceTracker(context);
+        this.hostContextActionTracker.open();
 
-        this.hostsDAO = hostsDao;
-        this.vmsDAO = vmsDAO;
-
-        initView(view);
+        this.vmContextActionTracker = new VMContextActionServiceTracker(context);
+        this.vmContextActionTracker.open();
+        
+        this.shutdown = shutdown;
 
-        vmInfoControllerProvider = new VmInformationControllerProvider();
+        Class<?>[] deps = new Class<?>[] {
+                HostInfoDAO.class,
+                VmInfoDAO.class,
+                SummaryViewProvider.class,
+                HostInformationViewProvider.class,
+                VmInformationViewProvider.class
+        };
+        depTracker = new MultipleServiceTracker(context, deps, new MultipleServiceTracker.Action() {
+            
+            @Override
+            public void dependenciesAvailable(Map<String, Object> services) {
+                hostInfoDAO = (HostInfoDAO) services.get(HostInfoDAO.class.getName());
+                Objects.requireNonNull(hostInfoDAO);
+                vmInfoDAO = (VmInfoDAO) services.get(VmInfoDAO.class.getName());
+                Objects.requireNonNull(vmInfoDAO);
+                summaryViewProvider = (SummaryViewProvider) services.get(SummaryViewProvider.class.getName());
+                Objects.requireNonNull(summaryViewProvider);
+                hostInfoViewProvider = (HostInformationViewProvider) services.get(HostInformationViewProvider.class.getName());
+                Objects.requireNonNull(hostInfoViewProvider);
+                vmInfoViewProvider = (VmInformationViewProvider) services.get(VmInformationViewProvider.class.getName());
+                Objects.requireNonNull(vmInfoViewProvider);
+                
+                initView(view);
 
-        appInfo = new ApplicationInfo();
-        view.setWindowTitle(appInfo.getName());
-        initializeTimer();
+                vmInfoControllerProvider = new VmInformationControllerProvider();
+
+                appInfo = new ApplicationInfo();
+                view.setWindowTitle(appInfo.getName());
+                initializeTimer();
+
+                updateView();
+
+                installListenersAndStartRegistries();
+            }
 
-        updateView();
-
-        installListenersAndStartRegistries();
+            @Override
+            public void dependenciesUnavailable() {
+                if (shutdown.getCount() > 0) {
+                    // In the rare case we lose one of our deps, gracefully shutdown
+                    logger.severe("Dependency unexpectedly became unavailable");
+                    shutdown.countDown();
+                }
+            }
+        });
+        depTracker.open();
     }
 
     /*
@@ -260,7 +326,7 @@
     }
 
     public void doUpdateTreeAsync() {
-        HostsVMsLoader loader = new DefaultHostsVMsLoader(hostsDAO, vmsDAO, !showHistory);
+        HostsVMsLoader loader = new DefaultHostsVMsLoader(hostInfoDAO, vmInfoDAO, !showHistory);
         view.updateTree(hostFilters, vmFilters, hostTreeDecorators, vmTreeDecorators, loader);
     }
 
@@ -304,7 +370,8 @@
                     handleVMHooks(evt);
                     break;
                 case SHUTDOWN:
-                    shutdownApplication();
+                    // Main will call shutdownApplication
+                    shutdown.countDown();
                     break;
                 default:
                     throw new IllegalStateException("unhandled action");
@@ -314,12 +381,19 @@
         });
     }
 
-    private void shutdownApplication() {
+    /*
+     * Called by Main to cleanup when shutting down
+     */
+    void shutdownApplication() {
         uninstallListenersAndStopRegistries();
 
         view.hideMainWindow();
         appSvc.getTimerFactory().shutdown();
-        shutdownOSGiFramework();
+        
+        depTracker.close();
+        infoServiceTracker.close();
+        hostContextActionTracker.close();
+        vmContextActionTracker.close();
     }
 
     private void installListenersAndStartRegistries() {
@@ -368,10 +442,6 @@
         vmInfoRegistry.stop();
     }
 
-    private void shutdownOSGiFramework() {
-        facadeFactory.shutdown();
-    }
-
     private void showContextMenu(ActionEvent<Action> evt) {
         List<ContextAction> toShow = new ArrayList<>();
 
@@ -381,7 +451,7 @@
 
             logger.log(Level.INFO, "registering applicable HostContextActions actions to show");
 
-            for (HostContextAction action : facadeFactory.getHostContextActions()) {
+            for (HostContextAction action : hostContextActionTracker.getHostContextActions()) {
                 if (action.getFilter().matches(vm)) {
                     toShow.add(action);
                 }
@@ -391,7 +461,7 @@
 
             logger.log(Level.INFO, "registering applicable VMContextActions actions to show");
 
-            for (VMContextAction action : facadeFactory.getVMContextActions()) {
+            for (VMContextAction action : vmContextActionTracker.getVmContextActions()) {
                 if (action.getFilter().matches(vm)) {
                     toShow.add(action);
                 }
@@ -455,11 +525,11 @@
         Ref ref = view.getSelectedHostOrVm();
 
         if (ref == null) {
-            SummaryController controller = facadeFactory.getSummary();
+            SummaryController controller = createSummaryController();
             view.setSubView(controller.getView());
         } else if (ref instanceof HostRef) {
             HostRef hostRef = (HostRef) ref;
-            HostInformationController hostController = facadeFactory.getHostController(hostRef);
+            HostInformationController hostController = createHostInformationController(hostRef);
             view.setSubView(hostController.getView());
             view.setStatusBarPrimaryStatus("host: " + hostRef.getHostName() + ", id: " + hostRef.getAgentId());
         } else if (ref instanceof VmRef) {
@@ -567,7 +637,7 @@
                 id = lastSelectedVM.getSelectedChildID();
             }
             
-            lastSelectedVM = facadeFactory.getVmController(vmRef);
+            lastSelectedVM = createVmController(vmRef);
             if (!lastSelectedVM.selectChildID(id)) {
                 Integer _id = selectedForVM.get(vmRef);
                 id = _id != null? _id : 0;
@@ -579,6 +649,20 @@
             return lastSelectedVM;
         }
     }
+    
+    private SummaryController createSummaryController() {
+        return new SummaryController(appSvc, hostInfoDAO, vmInfoDAO, summaryViewProvider);
+    }
+
+    private HostInformationController createHostInformationController(HostRef ref) {
+        List<InformationService<HostRef>> hostInfoServices = infoServiceTracker.getHostInformationServices();
+        return new HostInformationController(hostInfoServices, ref, hostInfoViewProvider);
+    }
+
+    private VmInformationController createVmController(VmRef ref) {
+        List<InformationService<VmRef>> vmInfoServices = infoServiceTracker.getVmInformationServices();
+        return new VmInformationController(vmInfoServices, ref, vmInfoViewProvider);
+    }
 
 }
 
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/UiFacadeFactoryImpl.java	Tue Feb 26 15:02:37 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,202 +0,0 @@
-/*
- * 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;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-
-import org.osgi.framework.BundleContext;
-
-import com.redhat.thermostat.client.core.InformationService;
-import com.redhat.thermostat.client.core.views.HostInformationViewProvider;
-import com.redhat.thermostat.client.core.views.SummaryViewProvider;
-import com.redhat.thermostat.client.core.views.VmInformationViewProvider;
-import com.redhat.thermostat.client.osgi.service.HostContextAction;
-import com.redhat.thermostat.client.osgi.service.VMContextAction;
-import com.redhat.thermostat.client.ui.HostInformationController;
-import com.redhat.thermostat.client.ui.MainWindowController;
-import com.redhat.thermostat.client.ui.SummaryController;
-import com.redhat.thermostat.client.ui.UiFacadeFactory;
-import com.redhat.thermostat.client.ui.VmInformationController;
-import com.redhat.thermostat.common.ApplicationService;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.storage.core.HostRef;
-import com.redhat.thermostat.storage.core.VmRef;
-import com.redhat.thermostat.storage.dao.HostInfoDAO;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
-
-public class UiFacadeFactoryImpl implements UiFacadeFactory {
-
-    private CountDownLatch shutdown = new CountDownLatch(1);
-
-    private List<InformationService<HostRef>> hostInformationServices = new ArrayList<>();
-    private List<InformationService<VmRef>> vmInformationServices = new ArrayList<>();
-    private Collection<HostContextAction> hostContextActions = new ArrayList<>();
-    private Collection<VMContextAction> vmContextActions = new ArrayList<>();
-
-    private BundleContext context;
-    private ApplicationService appSvc;
-
-    private HostInfoDAO hostInfoDao;
-    private VmInfoDAO vmInfoDao;
-
-    private OSGIUtils serviceProvider;
-    
-    UiFacadeFactoryImpl(OSGIUtils serviceProvider, BundleContext context) {
-        this.context = context;
-        this.serviceProvider = serviceProvider;
-        appSvc = serviceProvider.getService(ApplicationService.class);
-    }
-    
-    public UiFacadeFactoryImpl(BundleContext context) {
-        this(OSGIUtils.getInstance(), context);
-    }
-
-    @Override
-    public void setHostInfoDao(HostInfoDAO hostInfoDao) {
-        this.hostInfoDao = hostInfoDao;
-    }
-
-    public void setVmInfoDao(VmInfoDAO vmInfoDao) {
-        this.vmInfoDao = vmInfoDao;
-    }
-
-    @Override
-    public MainWindowController getMainWindow() {
-        MainView mainView = new MainWindow();
-        RegistryFactory registryFactory = new RegistryFactory(context);
-        return new MainWindowControllerImpl(appSvc, this, mainView, registryFactory, hostInfoDao, vmInfoDao);
-    }
-
-    @Override
-    public SummaryController getSummary() {
-        SummaryViewProvider viewProvider = serviceProvider.getService(SummaryViewProvider.class);
-        return new SummaryController(appSvc, hostInfoDao, vmInfoDao, viewProvider);
-    }
-
-    @Override
-    public HostInformationController getHostController(HostRef ref) {
-        HostInformationViewProvider viewProvider = serviceProvider.getService(HostInformationViewProvider.class);
-        return new HostInformationController(this, ref, viewProvider);
-    }
-
-    @Override
-    public VmInformationController getVmController(VmRef ref) {
-        VmInformationViewProvider viewProvider = serviceProvider.getService(VmInformationViewProvider.class);
-        return new VmInformationController(this, ref, viewProvider);
-    }
-
-    @Override
-    public List<InformationService<VmRef>> getVmInformationServices() {
-        return vmInformationServices;
-    }
-
-    @Override
-    public void addVmInformationService(InformationService<VmRef> vmInfoService) {
-        vmInformationServices.add(vmInfoService);
-    }
-
-    @Override
-    public void removeVmInformationService(InformationService<VmRef> vmInfoService) {
-        vmInformationServices.remove(vmInfoService);
-    }
-
-    @Override
-    public Collection<HostContextAction> getHostContextActions() {
-        return hostContextActions;
-    }
-
-    @Override
-    public void addHostContextAction(HostContextAction action) {
-        hostContextActions.add(action);
-    }
-
-    @Override
-    public void removeHostContextAction(HostContextAction action) {
-        hostContextActions.remove(action);
-    }
-
-    @Override
-    public Collection<VMContextAction> getVMContextActions() {
-        return vmContextActions;
-    }
-
-    @Override
-    public void addVMContextAction(VMContextAction service) {
-        vmContextActions.add(service);
-    }
-
-    @Override
-    public void shutdown() {
-        shutdown.countDown();
-    }
-
-    @Override
-    public void shutdown(int exitCode) {
-        // TODO implement returning exit codes
-        shutdown();
-    }
-
-    @Override
-    public void awaitShutdown() throws InterruptedException {
-        shutdown.await();
-    }
-
-    @Override
-    public List<InformationService<HostRef>> getHostInformationServices() {
-        return hostInformationServices;
-    }
-
-    @Override
-    public void addHostInformationService(InformationService<HostRef> hostInfoService) {
-        hostInformationServices.add(hostInfoService);
-    }
-
-    @Override
-    public void removeHostInformationService(InformationService<HostRef> hostInfoService) {
-        hostInformationServices.remove(hostInfoService);
-    }
-
-    @Override
-    public boolean isShutdown() {
-        return shutdown.getCount() == 0;
-    }
-
-}
-
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/HostContextActionServiceTracker.java	Tue Feb 26 15:02:37 2013 -0500
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/HostContextActionServiceTracker.java	Mon Mar 04 17:04:10 2013 -0500
@@ -36,39 +36,44 @@
 
 package com.redhat.thermostat.client.swing.internal.osgi;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.osgi.util.tracker.ServiceTracker;
 
 import com.redhat.thermostat.client.osgi.service.HostContextAction;
-import com.redhat.thermostat.client.ui.UiFacadeFactory;
 
 @SuppressWarnings("rawtypes")
-class HostContextActionServiceTracker extends ServiceTracker {
-
-    private UiFacadeFactory uiFacadeFactory;
-
-    private BundleContext context;
+public class HostContextActionServiceTracker extends ServiceTracker {
+    
+    private List<HostContextAction> hostContextActions;
 
     @SuppressWarnings("unchecked")
-    HostContextActionServiceTracker(BundleContext context, UiFacadeFactory uiFacadeFactory) {
+    public HostContextActionServiceTracker(BundleContext context) {
         super(context, HostContextAction.class.getName(), null);
-        this.context = context;
-        this.uiFacadeFactory = uiFacadeFactory;
+        this.hostContextActions = new ArrayList<>();
     }
 
     @Override
     public Object addingService(ServiceReference reference) {
         @SuppressWarnings("unchecked")
         HostContextAction service = (HostContextAction) super.addingService(reference);
-        uiFacadeFactory.addHostContextAction(service);
+        hostContextActions.add(service);
         return service;
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     public void removedService(ServiceReference reference, Object service) {
-        uiFacadeFactory.removeHostContextAction((HostContextAction)service);
+        hostContextActions.remove((HostContextAction)service);
         super.removedService(reference, service);
     }
+    
+    public List<HostContextAction> getHostContextActions() {
+        return new ArrayList<>(hostContextActions);
+    }
+    
 }
 
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/InformationServiceTracker.java	Tue Feb 26 15:02:37 2013 -0500
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/InformationServiceTracker.java	Mon Mar 04 17:04:10 2013 -0500
@@ -36,6 +36,8 @@
 
 package com.redhat.thermostat.client.swing.internal.osgi;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.logging.Logger;
 
 import org.osgi.framework.BundleContext;
@@ -43,7 +45,6 @@
 import org.osgi.util.tracker.ServiceTracker;
 
 import com.redhat.thermostat.client.core.InformationService;
-import com.redhat.thermostat.client.ui.UiFacadeFactory;
 import com.redhat.thermostat.common.Constants;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -52,13 +53,16 @@
 @SuppressWarnings("rawtypes")
 public class InformationServiceTracker extends ServiceTracker {
 
-    private UiFacadeFactory uiFacadeFactory;
     private static final Logger logger = LoggingUtils.getLogger(InformationServiceTracker.class);
+    
+    private List<InformationService<HostRef>> hostInfoServices;
+    private List<InformationService<VmRef>> vmInfoServices;
 
     @SuppressWarnings("unchecked")
-    public InformationServiceTracker(BundleContext context, UiFacadeFactory uiFacadeFactory) {
+    public InformationServiceTracker(BundleContext context) {
         super(context, InformationService.class.getName(), null);
-        this.uiFacadeFactory = uiFacadeFactory;
+        this.hostInfoServices = new ArrayList<>();
+        this.vmInfoServices = new ArrayList<>();
     }
 
     @Override
@@ -66,9 +70,9 @@
         Object service = super.addingService(reference);
         String genericType = (String) reference.getProperty(Constants.GENERIC_SERVICE_CLASSNAME);
         if (genericType.equals(HostRef.class.getName())) {
-            uiFacadeFactory.addHostInformationService((InformationService<HostRef>) service);
+            hostInfoServices.add((InformationService<HostRef>) service);
         } else if (genericType.equals(VmRef.class.getName())) {
-            uiFacadeFactory.addVmInformationService((InformationService<VmRef>) service);
+            vmInfoServices.add((InformationService<VmRef>) service);
         } else {
             logUnknownGenericServiceType(genericType);
         }
@@ -79,14 +83,22 @@
     public void removedService(ServiceReference reference, Object service) {
         String genericType = (String) reference.getProperty(Constants.GENERIC_SERVICE_CLASSNAME);
         if (genericType.equals(HostRef.class.getName())) {
-            uiFacadeFactory.removeHostInformationService((InformationService<HostRef>) service);
+            hostInfoServices.remove((InformationService<HostRef>) service);
         } else if (genericType.equals(VmRef.class.getName())) {
-            uiFacadeFactory.removeVmInformationService((InformationService<VmRef>) service);
+            vmInfoServices.remove((InformationService<VmRef>) service);
         } else {
             logUnknownGenericServiceType(genericType);
         }
         super.removedService(reference, service);
     }
+    
+    public List<InformationService<HostRef>> getHostInformationServices() {
+        return new ArrayList<>(hostInfoServices);
+    }
+    
+    public List<InformationService<VmRef>> getVmInformationServices() {
+        return new ArrayList<>(vmInfoServices);
+    }
 
     private void logUnknownGenericServiceType(String genericType) {
         logger.warning("InformationServiceTracker encountered an unknown generic type: " + genericType);
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/ThermostatActivator.java	Tue Feb 26 15:02:37 2013 -0500
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/ThermostatActivator.java	Mon Mar 04 17:04:10 2013 -0500
@@ -53,13 +53,11 @@
 import com.redhat.thermostat.client.swing.internal.GUIClientCommand;
 import com.redhat.thermostat.client.swing.internal.HostIconDecoratorProvider;
 import com.redhat.thermostat.client.swing.internal.Main;
-import com.redhat.thermostat.client.swing.internal.UiFacadeFactoryImpl;
 import com.redhat.thermostat.client.swing.internal.views.SwingAgentInformationViewProvider;
 import com.redhat.thermostat.client.swing.internal.views.SwingClientConfigurationViewProvider;
 import com.redhat.thermostat.client.swing.internal.views.SwingHostInformationViewProvider;
 import com.redhat.thermostat.client.swing.internal.views.SwingSummaryViewProvider;
 import com.redhat.thermostat.client.swing.internal.views.SwingVmInformationViewProvider;
-import com.redhat.thermostat.client.ui.UiFacadeFactory;
 import com.redhat.thermostat.common.ApplicationService;
 import com.redhat.thermostat.common.Constants;
 import com.redhat.thermostat.common.MultipleServiceTracker;
@@ -71,10 +69,6 @@
 
 public class ThermostatActivator implements BundleActivator {
 
-    private InformationServiceTracker infoServiceTracker;
-    private HostContextActionServiceTracker hostContextActionTracker;
-    private VMContextActionServiceTracker vmContextActionTracker;
-
     private CommandRegistry cmdReg;
     private MultipleServiceTracker dependencyTracker;
 
@@ -117,19 +111,8 @@
                 Keyring keyring = (Keyring) services.get(Keyring.class.getName());
                 ApplicationService appSvc = (ApplicationService) services.get(ApplicationService.class.getName());
                 
-                UiFacadeFactory uiFacadeFactory = new UiFacadeFactoryImpl(context);
-
-                infoServiceTracker = new InformationServiceTracker(context, uiFacadeFactory);
-                infoServiceTracker.open();
-
-                hostContextActionTracker = new HostContextActionServiceTracker(context, uiFacadeFactory);
-                hostContextActionTracker.open();
-
-                vmContextActionTracker = new VMContextActionServiceTracker(context, uiFacadeFactory);
-                vmContextActionTracker.open();
-
                 cmdReg = new CommandRegistryImpl(context);
-                main = new Main(context, keyring, appSvc, uiFacadeFactory, new String[0]);
+                main = new Main(context, keyring, appSvc, new String[0]);
                 
                 GUIClientCommand cmd = new GUIClientCommand(main);
                 cmdReg.registerCommands(Arrays.asList(cmd));
@@ -147,9 +130,6 @@
 
     @Override
     public void stop(BundleContext context) throws Exception {
-        infoServiceTracker.close();
-        hostContextActionTracker.close();
-        vmContextActionTracker.close();
         dependencyTracker.close();
         cmdReg.unregisterCommands();
     }
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/VMContextActionServiceTracker.java	Tue Feb 26 15:02:37 2013 -0500
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/VMContextActionServiceTracker.java	Mon Mar 04 17:04:10 2013 -0500
@@ -36,33 +36,43 @@
 
 package com.redhat.thermostat.client.swing.internal.osgi;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.osgi.util.tracker.ServiceTracker;
 
 import com.redhat.thermostat.client.osgi.service.VMContextAction;
-import com.redhat.thermostat.client.ui.UiFacadeFactory;
 
 @SuppressWarnings("rawtypes")
-class VMContextActionServiceTracker extends ServiceTracker {
+public class VMContextActionServiceTracker extends ServiceTracker {
 
-    private UiFacadeFactory uiFacadeFactory;
-
-    private BundleContext context;
+    private List<VMContextAction> vmContextActions;
 
     @SuppressWarnings("unchecked")
-    VMContextActionServiceTracker(BundleContext context, UiFacadeFactory uiFacadeFactory) {
+    public VMContextActionServiceTracker(BundleContext context) {
         super(context, VMContextAction.class.getName(), null);
-        this.context = context;
-        this.uiFacadeFactory = uiFacadeFactory;
+        this.vmContextActions = new ArrayList<>();
     }
 
     @Override
     public Object addingService(ServiceReference reference) {
         @SuppressWarnings("unchecked")
-        VMContextAction service = (VMContextAction) context.getService(reference);
-        uiFacadeFactory.addVMContextAction(service);
+        VMContextAction service = (VMContextAction) super.addingService(reference);
+        vmContextActions.add(service);
         return service;
     }
+    
+    @SuppressWarnings("unchecked")
+    @Override
+    public void removedService(ServiceReference reference, Object service) {
+        vmContextActions.remove((VMContextAction) service);
+        super.removedService(reference, service);
+    }
+    
+    public List<VMContextAction> getVmContextActions() {
+        return new ArrayList<>(vmContextActions);
+    }
 }
 
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainTest.java	Tue Feb 26 15:02:37 2013 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainTest.java	Mon Mar 04 17:04:10 2013 -0500
@@ -44,6 +44,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
 
 import javax.swing.SwingUtilities;
@@ -55,8 +56,7 @@
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
-import com.redhat.thermostat.client.ui.MainWindowController;
-import com.redhat.thermostat.client.ui.UiFacadeFactory;
+import com.redhat.thermostat.client.swing.internal.Main.MainWindowRunnable;
 import com.redhat.thermostat.common.ApplicationService;
 import com.redhat.thermostat.common.TimerFactory;
 import com.redhat.thermostat.storage.core.Connection.ConnectionListener;
@@ -72,8 +72,7 @@
 
     private ExecutorService executorService;
 
-    private MainWindowController mainWindowController;
-    private UiFacadeFactory uiFactory;
+    private MainWindowRunnable mainWindowRunnable;
 
     private ArgumentCaptor<ConnectionListener> connectionListenerCaptor;
 
@@ -84,6 +83,7 @@
     private StubBundleContext context;
     private ApplicationService appService;
     private Keyring keyring;
+    private CountDownLatch shutdown;
 
     @Before
     public void setUp() {
@@ -102,12 +102,9 @@
         }).when(executorService).execute(isA(Runnable.class));
 
         when(appService.getApplicationExecutor()).thenReturn(executorService);
-
-        mainWindowController = mock(MainWindowController.class);
-
-        uiFactory = mock(UiFacadeFactory.class);
-        when(uiFactory.getMainWindow()).thenReturn(mainWindowController);
-
+        
+        mainWindowRunnable = mock(MainWindowRunnable.class);
+        
         dbServiceFactory = mock(DbServiceFactory.class);
         dbService = mock(DbService.class);
         when(dbServiceFactory.createDbService(anyString(), anyString(), anyString())).thenReturn(dbService);
@@ -119,6 +116,7 @@
         when(appService.getTimerFactory()).thenReturn(timerFactory);
 
         keyring = mock(Keyring.class);
+        shutdown = mock(CountDownLatch.class);
     }
 
     /**
@@ -136,18 +134,18 @@
 
     @Test
     public void verifyRunWaitsForShutdown() throws Exception {
-        Main main = new Main(context, appService, uiFactory, dbServiceFactory, keyring);
+        Main main = new Main(context, appService, dbServiceFactory, keyring, shutdown, mainWindowRunnable);
 
         main.run();
 
         handleAllEdtEvents();
 
-        verify(uiFactory).awaitShutdown();
+        verify(shutdown).await();
     }
 
     @Test
     public void verifyConnectionIsMade() throws Exception {
-        Main main = new Main(context, appService, uiFactory, dbServiceFactory, keyring);
+        Main main = new Main(context, appService, dbServiceFactory, keyring, shutdown, mainWindowRunnable);
 
         main.run();
 
@@ -163,7 +161,7 @@
         context.registerService(HostInfoDAO.class, hostInfoDAO, null);
         VmInfoDAO vmInfoDAO = mock(VmInfoDAO.class);
         context.registerService(VmInfoDAO.class, vmInfoDAO, null);
-        Main main = new Main(context, appService, uiFactory, dbServiceFactory, keyring);
+        Main main = new Main(context, appService, dbServiceFactory, keyring, shutdown, mainWindowRunnable);
 
         main.run();
 
@@ -174,14 +172,14 @@
 
         handleAllEdtEvents();
 
-        verify(mainWindowController).showMainMainWindow();
+        verify(mainWindowRunnable).run();
     }
 
     @Ignore("this prompts the user with some gui")
     @Test
     public void verifyFailedConnectionTriggersShutdown() throws Exception {
 
-        Main main = new Main(context, appService, uiFactory, dbServiceFactory, keyring);
+        Main main = new Main(context, appService, dbServiceFactory, keyring, shutdown, mainWindowRunnable);
 
         main.run();
 
@@ -192,7 +190,7 @@
 
         handleAllEdtEvents();
 
-        verify(uiFactory).shutdown();
+        verify(shutdown).countDown();
     }
 }
 
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImplTest.java	Tue Feb 26 15:02:37 2013 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImplTest.java	Mon Mar 04 17:04:10 2013 -0500
@@ -51,9 +51,9 @@
 import java.awt.event.MouseEvent;
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
 import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
@@ -66,20 +66,25 @@
 
 import com.redhat.thermostat.client.core.Filter;
 import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.client.core.views.HostInformationView;
+import com.redhat.thermostat.client.core.views.HostInformationViewProvider;
+import com.redhat.thermostat.client.core.views.SummaryView;
+import com.redhat.thermostat.client.core.views.SummaryViewProvider;
+import com.redhat.thermostat.client.core.views.VmInformationView;
+import com.redhat.thermostat.client.core.views.VmInformationViewProvider;
 import com.redhat.thermostat.client.osgi.service.ContextAction;
 import com.redhat.thermostat.client.osgi.service.DecoratorProvider;
 import com.redhat.thermostat.client.osgi.service.HostContextAction;
 import com.redhat.thermostat.client.osgi.service.MenuAction;
 import com.redhat.thermostat.client.osgi.service.VMContextAction;
 import com.redhat.thermostat.client.ui.SummaryController;
-import com.redhat.thermostat.client.ui.UiFacadeFactory;
 import com.redhat.thermostat.client.ui.VmInformationController;
 import com.redhat.thermostat.common.ActionEvent;
 import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.ApplicationService;
 import com.redhat.thermostat.common.ThermostatExtensionRegistry;
+import com.redhat.thermostat.common.ThermostatExtensionRegistry.Action;
 import com.redhat.thermostat.common.Timer;
-import com.redhat.thermostat.common.ThermostatExtensionRegistry.Action;
 import com.redhat.thermostat.common.Timer.SchedulingType;
 import com.redhat.thermostat.common.TimerFactory;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -89,6 +94,7 @@
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.storage.model.VmInfo;
 import com.redhat.thermostat.test.Bug;
+import com.redhat.thermostat.testutils.StubBundleContext;
 
 public class MainWindowControllerImplTest {
 
@@ -96,8 +102,6 @@
 
     private MainWindowControllerImpl controller;
 
-    private UiFacadeFactory uiFacadeFactory;
-    
     private MainView view;
 
     private Timer mainWindowTimer;
@@ -121,6 +125,12 @@
     @SuppressWarnings("unused")
     private ActionListener<ThermostatExtensionRegistry.Action> vmFiltersListener;
     private ActionListener<ThermostatExtensionRegistry.Action> decoratorsListener;
+
+    private StubBundleContext context;
+    private CountDownLatch shutdown;
+
+    private VmInformationView vmInfoView;
+    private VmInformationViewProvider vmInfoViewProvider;
     
     @BeforeClass
     public static void setUpOnce() {
@@ -131,6 +141,8 @@
     @SuppressWarnings({ "unchecked", "rawtypes" }) // ActionListener fluff
     @Before
     public void setUp() throws Exception {
+        context = new StubBundleContext();
+        
         // Setup timers
         mainWindowTimer = mock(Timer.class);
         Timer otherTimer = mock(Timer.class); // FIXME needed for SummaryView; remove later
@@ -139,14 +151,25 @@
         ApplicationService appSvc = mock(ApplicationService.class);
         when (appSvc.getTimerFactory()).thenReturn(timerFactory);
 
-        SummaryController summaryController = mock(SummaryController.class);
-
-        uiFacadeFactory = mock(UiFacadeFactory.class);
+        mockHostsDAO = mock(HostInfoDAO.class);
+        context.registerService(HostInfoDAO.class, mockHostsDAO, null);
+        mockVmsDAO = mock(VmInfoDAO.class);
+        context.registerService(VmInfoDAO.class, mockVmsDAO, null);
+        
+        SummaryViewProvider summaryViewProvider = mock(SummaryViewProvider.class);
+        context.registerService(SummaryViewProvider.class, summaryViewProvider, null);
+        SummaryView summaryView = mock(SummaryView.class);
+        when(summaryViewProvider.createView()).thenReturn(summaryView);
         
-        when(uiFacadeFactory.getSummary()).thenReturn(summaryController);
-
-        mockHostsDAO = mock(HostInfoDAO.class);
-        mockVmsDAO = mock(VmInfoDAO.class);
+        HostInformationViewProvider hostInfoViewProvider = mock(HostInformationViewProvider.class);
+        context.registerService(HostInformationViewProvider.class, hostInfoViewProvider, null);
+        HostInformationView hostInfoView = mock(HostInformationView.class);
+        when(hostInfoViewProvider.createView()).thenReturn(hostInfoView);
+        
+        vmInfoViewProvider = mock(VmInformationViewProvider.class);
+        context.registerService(VmInformationViewProvider.class, vmInfoViewProvider, null);
+        vmInfoView = mock(VmInformationView.class);
+        when(vmInfoViewProvider.createView()).thenReturn(vmInfoView);
 
         // Setup View
         view = mock(MainView.class);
@@ -160,6 +183,7 @@
         vmDecoratorRegistry = mock(VMTreeDecoratorRegistry.class);
         vmInfoRegistry = mock(VMInformationRegistry.class);
         menus = mock(MenuRegistry.class);
+        shutdown = mock(CountDownLatch.class);
 
         when(registryFactory.createMenuRegistry()).thenReturn(menus);
         when(registryFactory.createHostTreeDecoratorRegistry()).thenReturn(hostDecoratorRegistry);
@@ -183,7 +207,7 @@
         setUpHostContextActions();
         setUpVMContextActions();
 
-        controller = new MainWindowControllerImpl(appSvc, uiFacadeFactory, view, registryFactory, mockHostsDAO, mockVmsDAO);
+        controller = new MainWindowControllerImpl(context, appSvc, view, registryFactory, shutdown);
         l = grabListener.getValue();
         
         hostFiltersListener = grabHostFiltersListener.getValue();
@@ -200,7 +224,7 @@
         when(hostContextAction1.getDescription()).thenReturn("action1desc");
         when(hostContextAction1.getFilter()).thenReturn(hostFilter1);
 
-        when(uiFacadeFactory.getHostContextActions()).thenReturn(Arrays.asList(hostContextAction1));
+        context.registerService(HostContextAction.class, hostContextAction1, null);
     }
 
     private void setUpVMContextActions() {
@@ -212,6 +236,8 @@
         when(vmContextAction1.getDescription()).thenReturn("action1desc");
         when(vmContextAction1.getFilter()).thenReturn(action1Filter);
         
+        context.registerService(VMContextAction.class, vmContextAction1, null);
+        
         vmContextAction2 = mock(VMContextAction.class);
         Filter action2Filter = mock(Filter.class);
         when(action2Filter.matches(isA(VmRef.class))).thenReturn(false);
@@ -220,11 +246,7 @@
         when(vmContextAction2.getDescription()).thenReturn("action2desc");
         when(vmContextAction2.getFilter()).thenReturn(action2Filter);
         
-        Collection<VMContextAction> actions = new ArrayList<>();
-        actions.add(vmContextAction1);
-        actions.add(vmContextAction2);
-        
-        when(uiFacadeFactory.getVMContextActions()).thenReturn(actions);
+        context.registerService(VMContextAction.class, vmContextAction2, null);
     }
 
     @After
@@ -411,17 +433,15 @@
         when(vmRef.getAgent()).thenReturn(ref);
         
         when(view.getSelectedHostOrVm()).thenReturn(vmRef);
-
-        VmInformationController vmInformationController = mock(VmInformationController.class);
-        when(vmInformationController.getSelectedChildID()).thenReturn(3);
-        when(uiFacadeFactory.getVmController(any(VmRef.class))).thenReturn(vmInformationController);
-        when(vmInformationController.selectChildID(anyInt())).thenReturn(true);
-
+        
+        when(vmInfoView.getSelectedChildID()).thenReturn(3);
+        when(vmInfoView.selectChildID(anyInt())).thenReturn(true);
+        
         l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_SELECTION_CHANGED));
-
+        
         ArgumentCaptor<Integer> arg = ArgumentCaptor.forClass(Integer.class);
-        verify(vmInformationController).selectChildID(arg.capture());
-        verify(vmInformationController, times(0)).getSelectedChildID();
+        verify(vmInfoView).selectChildID(arg.capture());
+        verify(vmInfoView, times(0)).getSelectedChildID();
 
         int id = arg.getValue();
 
@@ -430,8 +450,8 @@
         l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_SELECTION_CHANGED));
 
         arg = ArgumentCaptor.forClass(Integer.class);
-        verify(vmInformationController, times(1)).getSelectedChildID();
-        verify(vmInformationController, times(2)).selectChildID(arg.capture());
+        verify(vmInfoView, times(1)).getSelectedChildID();
+        verify(vmInfoView, times(2)).selectChildID(arg.capture());
         id = arg.getValue();
 
         assertEquals(3, id);
@@ -454,31 +474,28 @@
         when(vmRef2.getIdString()).thenReturn("testvmid");
         when(vmRef2.getAgent()).thenReturn(ref);
         
-        VmInformationController vmInformationController1 = mock(VmInformationController.class);
-        VmInformationController vmInformationController2 = mock(VmInformationController.class);
+        VmInformationView vmInfoView2 = mock(VmInformationView.class);
         
-        when(vmInformationController1.getSelectedChildID()).thenReturn(2).thenReturn(2);
-        when(vmInformationController2.getSelectedChildID()).thenReturn(3);
+        when(vmInfoView.getSelectedChildID()).thenReturn(2).thenReturn(2);
+        when(vmInfoView2.getSelectedChildID()).thenReturn(3);
         
-        when(vmInformationController1.selectChildID(0)).thenReturn(true);
-        when(vmInformationController1.selectChildID(2)).thenReturn(true);
-        when(vmInformationController1.selectChildID(3)).thenReturn(false);
+        when(vmInfoView.selectChildID(0)).thenReturn(true);
+        when(vmInfoView.selectChildID(2)).thenReturn(true);
+        when(vmInfoView.selectChildID(3)).thenReturn(false);
         
-        when(vmInformationController2.selectChildID(0)).thenReturn(true);
-        when(vmInformationController2.selectChildID(2)).thenReturn(true);
-        when(vmInformationController2.selectChildID(3)).thenReturn(true);
+        when(vmInfoView2.selectChildID(0)).thenReturn(true);
+        when(vmInfoView2.selectChildID(2)).thenReturn(true);
+        when(vmInfoView2.selectChildID(3)).thenReturn(true);
         
-        when(uiFacadeFactory.getVmController(any(VmRef.class))).
-                             thenReturn(vmInformationController1).
-                             thenReturn(vmInformationController2).
-                             thenReturn(vmInformationController2).
-                             thenReturn(vmInformationController1);
-
+        when(vmInfoViewProvider.createView()).thenReturn(vmInfoView)
+                .thenReturn(vmInfoView2).thenReturn(vmInfoView2)
+                .thenReturn(vmInfoView);
+        
         l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_SELECTION_CHANGED));
 
         ArgumentCaptor<Integer> arg = ArgumentCaptor.forClass(Integer.class);
-        verify(vmInformationController1).selectChildID(arg.capture());
-        verify(vmInformationController1, times(0)).getSelectedChildID();
+        verify(vmInfoView).selectChildID(arg.capture());
+        verify(vmInfoView, times(0)).getSelectedChildID();
 
         int id = arg.getValue();
 
@@ -487,8 +504,8 @@
         l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_SELECTION_CHANGED));
 
         arg = ArgumentCaptor.forClass(Integer.class);
-        verify(vmInformationController1).getSelectedChildID();
-        verify(vmInformationController2, times(1)).selectChildID(arg.capture());
+        verify(vmInfoView).getSelectedChildID();
+        verify(vmInfoView2, times(1)).selectChildID(arg.capture());
         id = arg.getValue();
 
         assertEquals(2, id);
@@ -496,8 +513,8 @@
         l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_SELECTION_CHANGED));
 
         arg = ArgumentCaptor.forClass(Integer.class);
-        verify(vmInformationController2, times(1)).getSelectedChildID();
-        verify(vmInformationController2, times(2)).selectChildID(arg.capture());
+        verify(vmInfoView2, times(1)).getSelectedChildID();
+        verify(vmInfoView2, times(2)).selectChildID(arg.capture());
         id = arg.getValue();
 
         assertEquals(3, id);
@@ -505,8 +522,8 @@
         l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_SELECTION_CHANGED));
 
         arg = ArgumentCaptor.forClass(Integer.class);
-        verify(vmInformationController2, times(2)).getSelectedChildID();
-        verify(vmInformationController1, times(3)).selectChildID(arg.capture());
+        verify(vmInfoView2, times(2)).getSelectedChildID();
+        verify(vmInfoView, times(3)).selectChildID(arg.capture());
         id = arg.getValue();
 
         assertEquals(2, id);
@@ -600,7 +617,7 @@
 
        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.SHUTDOWN));
 
-       verify(uiFacadeFactory).shutdown();
+       verify(shutdown).countDown();
    }
 }
 
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/osgi/HostContextActionServiceTrackerTest.java	Tue Feb 26 15:02:37 2013 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/osgi/HostContextActionServiceTrackerTest.java	Mon Mar 04 17:04:10 2013 -0500
@@ -36,14 +36,14 @@
 
 package com.redhat.thermostat.client.swing.internal.osgi;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
 
 import org.junit.Test;
 import org.osgi.framework.ServiceRegistration;
 
 import com.redhat.thermostat.client.osgi.service.HostContextAction;
-import com.redhat.thermostat.client.ui.UiFacadeFactory;
 import com.redhat.thermostat.testutils.StubBundleContext;
 
 public class HostContextActionServiceTrackerTest {
@@ -51,20 +51,20 @@
     @Test
     public void verifyHostActionIsAddedToAndRemovedFromUiModel() {
         StubBundleContext bundleContext = new StubBundleContext();
-        UiFacadeFactory applicationModel = mock(UiFacadeFactory.class);
 
         HostContextAction hostAction = mock(HostContextAction.class);
         ServiceRegistration registration = bundleContext.registerService(HostContextAction.class, hostAction, null);
 
-        HostContextActionServiceTracker tracker = new HostContextActionServiceTracker(bundleContext, applicationModel);
+        HostContextActionServiceTracker tracker = new HostContextActionServiceTracker(bundleContext);
         tracker.open();
+        
+        assertTrue(tracker.getHostContextActions().contains(hostAction));
 
         registration.unregister();
 
         tracker.close();
 
-        verify(applicationModel).addHostContextAction(hostAction);
-        verify(applicationModel).removeHostContextAction(hostAction);
+        assertFalse(tracker.getHostContextActions().contains(hostAction));
     }
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/osgi/VMContextActionServiceTrackerTest.java	Mon Mar 04 17:04:10 2013 -0500
@@ -0,0 +1,71 @@
+/*
+ * 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.osgi;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import org.junit.Test;
+import org.osgi.framework.ServiceRegistration;
+
+import com.redhat.thermostat.client.osgi.service.VMContextAction;
+import com.redhat.thermostat.testutils.StubBundleContext;
+
+public class VMContextActionServiceTrackerTest {
+
+    @Test
+    public void verifyHostActionIsAddedToAndRemovedFromUiModel() {
+        StubBundleContext bundleContext = new StubBundleContext();
+
+        VMContextAction vmAction = mock(VMContextAction.class);
+        ServiceRegistration registration = bundleContext.registerService(VMContextAction.class, vmAction, null);
+
+        VMContextActionServiceTracker tracker = new VMContextActionServiceTracker(bundleContext);
+        tracker.open();
+        
+        assertTrue(tracker.getVmContextActions().contains(vmAction));
+
+        registration.unregister();
+
+        tracker.close();
+
+        assertFalse(tracker.getVmContextActions().contains(vmAction));
+    }
+
+}
+