changeset 1324:8e37e473ef52

Fix some memory leaks review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-November/008712.html reviewed-by: jerboaa, omajid
author Mario Torre <neugens.limasoftware@gmail.com>
date Thu, 14 Nov 2013 18:17:50 +0100
parents 2dea7ac8e42c
children 2228cf23604c
files client/living-vm-filter/swing/src/main/java/com/redhat/thermostat/client/filter/host/swing/HostInfoLabelDecorator.java client/living-vm-filter/swing/src/main/java/com/redhat/thermostat/client/filter/host/swing/HostLabelDecorator.java client/living-vm-filter/swing/src/main/java/com/redhat/thermostat/client/filter/vm/swing/VMFilterActivator.java client/living-vm-filter/swing/src/test/java/com/redhat/thermostat/client/filter/vm/swing/VMFilterActivatorTest.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/AccordionComponentFactory.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/controller/ContextActionController.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/controller/DecoratorManager.java client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/accordion/AccordionTest.java
diffstat 10 files changed, 303 insertions(+), 160 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/living-vm-filter/swing/src/main/java/com/redhat/thermostat/client/filter/host/swing/HostInfoLabelDecorator.java	Thu Nov 14 18:17:50 2013 +0100
@@ -0,0 +1,84 @@
+/*
+ * 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.filter.host.swing;
+
+import java.util.List;
+
+import com.redhat.thermostat.client.ui.ReferenceFieldLabelDecorator;
+import com.redhat.thermostat.storage.core.HostRef;
+import com.redhat.thermostat.storage.core.Ref;
+import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
+import com.redhat.thermostat.storage.model.NetworkInterfaceInfo;
+
+public class HostInfoLabelDecorator implements ReferenceFieldLabelDecorator {
+
+    private NetworkInterfaceInfoDAO dao;
+    
+    public HostInfoLabelDecorator(NetworkInterfaceInfoDAO  dao) {
+        this.dao = dao;
+    }
+    
+    @Override
+    public int getOrderValue() {
+        return ORDER_FIRST;
+    }
+    
+    @Override
+    public String getLabel(String originalLabel, Ref reference) {
+        
+        if (!(reference instanceof HostRef)) {
+            return originalLabel;
+        }
+        
+        List<NetworkInterfaceInfo> infos =
+                dao.getNetworkInterfaces((HostRef) reference);
+        StringBuilder result = new StringBuilder();
+        
+        for (NetworkInterfaceInfo info : infos) {
+            // filter out the loopbak
+            if (!info.getInterfaceName().equals("lo")) {
+                if (info.getIp4Addr() != null) {
+                    result.append(info.getIp4Addr()).append("; ");
+                } else if (info.getIp6Addr() != null) {
+                    result.append(info.getIp6Addr()).append("; ");
+                }
+            }
+        }
+        result.deleteCharAt(result.length() - 2);
+        return result.toString();
+    }
+}
--- a/client/living-vm-filter/swing/src/main/java/com/redhat/thermostat/client/filter/host/swing/HostLabelDecorator.java	Thu Nov 14 18:17:49 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +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.filter.host.swing;
-
-import java.util.List;
-
-import com.redhat.thermostat.client.ui.ReferenceFieldLabelDecorator;
-import com.redhat.thermostat.storage.core.HostRef;
-import com.redhat.thermostat.storage.core.Ref;
-import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
-import com.redhat.thermostat.storage.model.NetworkInterfaceInfo;
-
-public class HostLabelDecorator implements ReferenceFieldLabelDecorator {
-
-    private NetworkInterfaceInfoDAO dao;
-    
-    public HostLabelDecorator(NetworkInterfaceInfoDAO  dao) {
-        this.dao = dao;
-    }
-    
-    @Override
-    public int getOrderValue() {
-        return ORDER_FIRST;
-    }
-    
-    @Override
-    public String getLabel(String originalLabel, Ref reference) {
-        
-        if (!(reference instanceof HostRef)) {
-            return originalLabel;
-        }
-        
-        List<NetworkInterfaceInfo> infos =
-                dao.getNetworkInterfaces((HostRef) reference);
-        StringBuilder result = new StringBuilder();
-        
-        for (NetworkInterfaceInfo info : infos) {
-            // filter out the loopbak
-            if (!info.getInterfaceName().equals("lo")) {
-                if (info.getIp4Addr() != null) {
-                    result.append(info.getIp4Addr()).append("; ");
-                } else if (info.getIp6Addr() != null) {
-                    result.append(info.getIp6Addr()).append("; ");
-                }
-            }
-        }
-        result.deleteCharAt(result.length() - 2);
-        return result.toString();
-    }
-}
--- a/client/living-vm-filter/swing/src/main/java/com/redhat/thermostat/client/filter/vm/swing/VMFilterActivator.java	Thu Nov 14 18:17:49 2013 +0100
+++ b/client/living-vm-filter/swing/src/main/java/com/redhat/thermostat/client/filter/vm/swing/VMFilterActivator.java	Thu Nov 14 18:17:50 2013 +0100
@@ -50,16 +50,13 @@
 
 import com.redhat.thermostat.client.filter.host.swing.DeadHostIconDecorator;
 import com.redhat.thermostat.client.filter.host.swing.HostIconDecorator;
-import com.redhat.thermostat.client.filter.host.swing.HostLabelDecorator;
-
+import com.redhat.thermostat.client.filter.host.swing.HostInfoLabelDecorator;
+import com.redhat.thermostat.client.filter.host.swing.HostVmMainLabelDecorator;
 import com.redhat.thermostat.client.swing.ReferenceFieldDecoratorLayout;
 import com.redhat.thermostat.client.swing.UIDefaults;
-
 import com.redhat.thermostat.client.ui.ReferenceFieldIconDecorator;
 import com.redhat.thermostat.client.ui.ReferenceFieldLabelDecorator;
-
 import com.redhat.thermostat.common.MultipleServiceTracker;
-
 import com.redhat.thermostat.storage.dao.HostInfoDAO;
 import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
@@ -107,7 +104,8 @@
                 
                 VMLabelDecorator vmLabelDecorator = new VMLabelDecorator(vmDao);
                 decoratorProperties = new Hashtable<>();
-                decoratorProperties.put(ReferenceFieldLabelDecorator.ID, ReferenceFieldDecoratorLayout.LABEL_INFO.name());
+                decoratorProperties.put(ReferenceFieldLabelDecorator.ID,
+                                        ReferenceFieldDecoratorLayout.LABEL_INFO.name());
 
                 registration = context.registerService(ReferenceFieldLabelDecorator.class.getName(),
                         vmLabelDecorator, decoratorProperties);
@@ -117,25 +115,31 @@
                 NetworkInterfaceInfoDAO networkDao = (NetworkInterfaceInfoDAO)
                             services.get(NetworkInterfaceInfoDAO.class.getName());
                 
-                HostLabelDecorator hostLabelDecorator = new HostLabelDecorator(networkDao);
+                HostInfoLabelDecorator hostLabelDecorator =
+                            new HostInfoLabelDecorator(networkDao);
                 decoratorProperties = new Hashtable<>();
-                decoratorProperties.put(ReferenceFieldLabelDecorator.ID, ReferenceFieldDecoratorLayout.LABEL_INFO.name());
+                decoratorProperties.put(ReferenceFieldLabelDecorator.ID,
+                                        ReferenceFieldDecoratorLayout.LABEL_INFO.name());
                 
                 registration = context.registerService(ReferenceFieldLabelDecorator.class.getName(),
                                                        hostLabelDecorator, decoratorProperties);
                 registeredServices.add(registration);
                 
-                HostIconDecorator hostIconDecorator = HostIconDecorator.getInstance(uiDefaults);
+                HostIconDecorator hostIconDecorator =
+                            HostIconDecorator.getInstance(uiDefaults);
                 decoratorProperties = new Hashtable<>();
-                decoratorProperties.put(ReferenceFieldIconDecorator.ID, ReferenceFieldDecoratorLayout.ICON_MAIN.name());
+                decoratorProperties.put(ReferenceFieldIconDecorator.ID,
+                                        ReferenceFieldDecoratorLayout.ICON_MAIN.name());
                 
                 registration = context.registerService(ReferenceFieldIconDecorator.class.getName(),
                                                        hostIconDecorator, decoratorProperties);
                 registeredServices.add(registration);
                 
-                DeadHostIconDecorator deadHostIconDecorator = DeadHostIconDecorator.getInstance(hostDao, uiDefaults);
+                DeadHostIconDecorator deadHostIconDecorator =
+                            DeadHostIconDecorator.getInstance(hostDao, uiDefaults);
                 decoratorProperties = new Hashtable<>();
-                decoratorProperties.put(ReferenceFieldIconDecorator.ID, ReferenceFieldDecoratorLayout.ICON_MAIN.name());
+                decoratorProperties.put(ReferenceFieldIconDecorator.ID,
+                                        ReferenceFieldDecoratorLayout.ICON_MAIN.name());
                 
                 registration = context.registerService(ReferenceFieldIconDecorator.class.getName(),
                                                        deadHostIconDecorator, decoratorProperties);
@@ -143,19 +147,30 @@
                 
                 VMIconDecorator livingVMIconDecorator = VMIconDecorator.getInstance(uiDefaults);
                 decoratorProperties = new Hashtable<>();
-                decoratorProperties.put(ReferenceFieldIconDecorator.ID, ReferenceFieldDecoratorLayout.ICON_MAIN.name());
+                decoratorProperties.put(ReferenceFieldIconDecorator.ID,
+                                        ReferenceFieldDecoratorLayout.ICON_MAIN.name());
                 
                 registration = context.registerService(ReferenceFieldIconDecorator.class.getName(),
                                                        livingVMIconDecorator, decoratorProperties);
                 registeredServices.add(registration);
                 
-                DeadVMIconDecorator deadVMIconDecorator = DeadVMIconDecorator.getInstance(vmDao, hostDao, uiDefaults);
+                DeadVMIconDecorator deadVMIconDecorator =
+                            DeadVMIconDecorator.getInstance(vmDao, hostDao, uiDefaults);
                 decoratorProperties = new Hashtable<>();
-                decoratorProperties.put(ReferenceFieldIconDecorator.ID, ReferenceFieldDecoratorLayout.ICON_MAIN.name());
+                decoratorProperties.put(ReferenceFieldIconDecorator.ID,
+                                        ReferenceFieldDecoratorLayout.ICON_MAIN.name());
                 
                 registration = context.registerService(ReferenceFieldIconDecorator.class.getName(),
                                                        deadVMIconDecorator, decoratorProperties);
                 registeredServices.add(registration);
+                
+                HostVmMainLabelDecorator mainDecorator = new HostVmMainLabelDecorator();
+                decoratorProperties = new Hashtable<>();
+                decoratorProperties.put(ReferenceFieldLabelDecorator.ID,
+                                        ReferenceFieldDecoratorLayout.LABEL_MAIN.name());
+                
+                registration = context.registerService(ReferenceFieldLabelDecorator.class.getName(),
+                                                       mainDecorator, decoratorProperties);
             }
         });
         tracker.open();
--- a/client/living-vm-filter/swing/src/test/java/com/redhat/thermostat/client/filter/vm/swing/VMFilterActivatorTest.java	Thu Nov 14 18:17:49 2013 +0100
+++ b/client/living-vm-filter/swing/src/test/java/com/redhat/thermostat/client/filter/vm/swing/VMFilterActivatorTest.java	Thu Nov 14 18:17:50 2013 +0100
@@ -44,7 +44,7 @@
 
 import com.redhat.thermostat.client.filter.host.swing.DeadHostIconDecorator;
 import com.redhat.thermostat.client.filter.host.swing.HostIconDecorator;
-import com.redhat.thermostat.client.filter.host.swing.HostLabelDecorator;
+import com.redhat.thermostat.client.filter.host.swing.HostInfoLabelDecorator;
 import com.redhat.thermostat.client.swing.UIDefaults;
 import com.redhat.thermostat.client.ui.ReferenceFieldIconDecorator;
 import com.redhat.thermostat.client.ui.ReferenceFieldLabelDecorator;
@@ -74,7 +74,7 @@
         ctx.registerService(UIDefaults.class, uiDefaults, null);
 
         assertTrue(ctx.isServiceRegistered(ReferenceFieldLabelDecorator.class.getName(), VMLabelDecorator.class));
-        assertTrue(ctx.isServiceRegistered(ReferenceFieldLabelDecorator.class.getName(), HostLabelDecorator.class));
+        assertTrue(ctx.isServiceRegistered(ReferenceFieldLabelDecorator.class.getName(), HostInfoLabelDecorator.class));
         assertTrue(ctx.isServiceRegistered(ReferenceFieldIconDecorator.class.getName(), HostIconDecorator.class));
         assertTrue(ctx.isServiceRegistered(ReferenceFieldIconDecorator.class.getName(), DeadHostIconDecorator.class));
 
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/accordion/Accordion.java	Thu Nov 14 18:17:49 2013 +0100
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/accordion/Accordion.java	Thu Nov 14 18:17:50 2013 +0100
@@ -78,7 +78,7 @@
     
     private AccordionModel<H, C> model;
     private HashMap<H, TitledPane> panes;
-    private HashMap<H, Map<C, Component>> components;
+    private HashMap<H, Map<C, AccordionComponent>> components;
     
     private AccordionComponentFactory<H, C> componentFactory;
     
@@ -188,12 +188,12 @@
             content.add(contentUnit);
             content.revalidate();
             
-            Map<C, Component> componentsMap = components.get(header);
+            Map<C, AccordionComponent> componentsMap = components.get(header);
             if (componentsMap == null) {
                 componentsMap = new HashMap<>();
                 components.put(header, componentsMap);
             }
-            componentsMap.put(component, contentUnit);
+            componentsMap.put(component, comp);
         }
 
         @Override
@@ -201,16 +201,19 @@
             C component = e.getComponent();
             H header = e.getHeader();
             
-            Map<C, Component> componentsMap = components.get(header);
-            Component contentUnit = componentsMap.remove(component);
+            Map<C, AccordionComponent> componentsMap = components.get(header);
             if (componentsMap.isEmpty()) {
                 components.remove(header);
             }
+
+            AccordionComponent contentUnit = componentsMap.remove(component);
             
             TitledPane pane = panes.get(header);
             JComponent content = pane.getContent();
-            content.remove(contentUnit);
+            content.remove(contentUnit.getUiComponent());
             content.revalidate();
+
+            componentFactory.removeComponent(contentUnit, header, component);
             
             Accordion.this.contentPane.revalidate();
         }
@@ -219,9 +222,17 @@
         public void headerRemoved(AccordionHeaderEvent<H> e) {
             H header = e.getHeader();
             
-            components.remove(header);
             TitledPane pane = panes.remove(header);
             Accordion.this.contentPane.remove(pane);
+            
+            Map<C, AccordionComponent> componentsMap = components.remove(header);
+            if (componentsMap != null) {
+                for (C component : componentsMap.keySet()) {
+                    AccordionComponent contentUnit = componentsMap.get(component);
+                    componentFactory.removeComponent(contentUnit, header, component);
+                }
+            }
+            
             Accordion.this.contentPane.revalidate();
         }
     }
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/accordion/AccordionComponentFactory.java	Thu Nov 14 18:17:49 2013 +0100
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/accordion/AccordionComponentFactory.java	Thu Nov 14 18:17:50 2013 +0100
@@ -44,4 +44,7 @@
 
     TitledPane createHeader(H header);
     AccordionComponent createComponent(H header, C component);
+    
+    void removeHeader(TitledPane pane, H header);
+    void removeComponent(AccordionComponent accordionComponent, H header, C component);
 }
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/HostTreeComponentFactory.java	Thu Nov 14 18:17:49 2013 +0100
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/HostTreeComponentFactory.java	Thu Nov 14 18:17:50 2013 +0100
@@ -47,7 +47,7 @@
 import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.core.VmRef;
 
-public class HostTreeComponentFactory implements AccordionComponentFactory<HostRef, VmRef>{
+public class HostTreeComponentFactory implements AccordionComponentFactory<HostRef, VmRef> {
     
     private Map<VmRef, AccordionComponent> components;
     private Map<HostRef, ReferenceTitle> headers;
@@ -85,6 +85,23 @@
         return refComponent;
     }
     
+    @Override
+    public void removeComponent(AccordionComponent accordionComponent,
+                                HostRef header, VmRef component)
+    {
+        ReferenceComponent refComponent = (ReferenceComponent)
+                components.remove(component);
+        decoratorManager.unregister(refComponent);
+        contextActionController.unregister(refComponent, refComponent);
+    }
+    
+    @Override
+    public void removeHeader(TitledPane pane, HostRef header) {
+        ReferenceTitle title = headers.remove(header);
+        decoratorManager.unregister(title);
+        contextActionController.unregister(title, title);
+    }
+    
     public AccordionComponent getAccordionComponent(VmRef vm) {
         return components.get(vm);
     }
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/controller/ContextActionController.java	Thu Nov 14 18:17:49 2013 +0100
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/controller/ContextActionController.java	Thu Nov 14 18:17:50 2013 +0100
@@ -38,6 +38,7 @@
 
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
+import java.util.HashMap;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -69,8 +70,23 @@
     
     private ActionNotifier<ContextAction> notifier;
     
+    private HashMap<Ref, MenuAction> actions;
+    
     public ContextActionController() {
         notifier = new ActionNotifier<>(this);
+        actions = new HashMap<>();
+    }
+    
+    public void unregister(final AccordionComponent pane,
+                           final ReferenceProvider provider)
+    {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                MenuAction action = actions.remove(provider.getReference());
+                pane.getUiComponent().removeMouseListener(action);
+            }
+        });
     }
     
     public void register(final AccordionComponent pane,
@@ -79,19 +95,9 @@
         SwingUtilities.invokeLater(new Runnable() {
             @Override
             public void run() {
-                pane.getUiComponent().addMouseListener(new MouseAdapter() {
-                    @Override
-                    public void mousePressed(MouseEvent e) {                        
-                        if (e.isPopupTrigger()) {
-                            Payload payload = new Payload();
-                            payload.ref = provider.getReference();
-                            payload.component = pane;
-                            payload.x = e.getX();
-                            payload.y = e.getY();
-                            notifier.fireAction(ContextAction.SHOW_CONTEXT_MENU, payload);
-                      }
-                    }
-                });
+                MenuAction action = new MenuAction(pane, provider);
+                pane.getUiComponent().addMouseListener(action);
+                actions.put(provider.getReference(), action);
             }
         });
     }
@@ -104,7 +110,6 @@
         notifier.removeActionListener(l);
     }
     
-    @SuppressWarnings({ "unchecked", "rawtypes" })
     @Override
     public void actionPerformed(ActionEvent<ContextHandler.ContextHandlerAction> event) {
         ContextHandler.Payload payload = (ContextHandler.Payload) event.getPayload();
@@ -115,4 +120,26 @@
             logger.log(Level.SEVERE, "error invocating context action", error);
         }
     }
+    
+    private class MenuAction extends MouseAdapter {
+        private AccordionComponent pane;
+        private ReferenceProvider provider;
+        
+        public MenuAction(AccordionComponent pane, ReferenceProvider provider) {
+            this.pane = pane;
+            this.provider = provider;
+        }
+    
+        @Override
+        public void mousePressed(MouseEvent e) {
+            if (e.isPopupTrigger()) {
+                Payload payload = new Payload();
+                payload.ref = provider.getReference();
+                payload.component = pane;
+                payload.x = e.getX();
+                payload.y = e.getY();
+                notifier.fireAction(ContextAction.SHOW_CONTEXT_MENU, payload);
+            }
+        }
+    }
 }
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/controller/DecoratorManager.java	Thu Nov 14 18:17:49 2013 +0100
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/vmlist/controller/DecoratorManager.java	Thu Nov 14 18:17:50 2013 +0100
@@ -36,7 +36,10 @@
 
 package com.redhat.thermostat.client.swing.internal.vmlist.controller;
 
+import java.util.HashMap;
+
 import com.redhat.thermostat.client.swing.components.Icon;
+import com.redhat.thermostat.client.swing.internal.accordion.TitledPane;
 import com.redhat.thermostat.client.swing.internal.vmlist.ReferenceComponent;
 import com.redhat.thermostat.client.swing.internal.vmlist.ReferenceTitle;
 import com.redhat.thermostat.client.swing.internal.vmlist.controller.DecoratorNotifier.DecorationEvent;
@@ -53,54 +56,64 @@
         Icon selected;
     }
     
-    private DecoratorListener<ReferenceFieldLabelDecorator> infoLabelDecorator =
-            new DecoratorListener<>(ReferenceFieldLabelDecorator.class);
-    private DecoratorListener<ReferenceFieldLabelDecorator> mainLabelDecorator =
-            new DecoratorListener<>(ReferenceFieldLabelDecorator.class);
+    private DecoratorListener<ReferenceFieldLabelDecorator> infoLabelDecorator;
+    private DecoratorListener<ReferenceFieldLabelDecorator> mainLabelDecorator;
+
+    private DecoratorListener<ReferenceFieldIconDecorator> iconDecorator;
+
+    private HashMap<Ref, ListenerPayload> listeners;
+    
+    public DecoratorManager() {
+        mainLabelDecorator = new DecoratorListener<>(ReferenceFieldLabelDecorator.class);
+        infoLabelDecorator = new DecoratorListener<>(ReferenceFieldLabelDecorator.class);
+        iconDecorator = new DecoratorListener<>(ReferenceFieldIconDecorator.class);
+        
+        listeners = new HashMap<>();
+    }
 
-    private DecoratorListener<ReferenceFieldIconDecorator> iconDecorator =
-            new DecoratorListener<>(ReferenceFieldIconDecorator.class);
-
-    public void registerAndSetIcon(final ReferenceComponent component) {
+    public void unregister(ReferenceComponent component) {
         Ref ref = component.getReference();
-        component.setInfoLabelText(createComponentLabel(infoLabelDecorator, ref,
-                                                        component.getInfoLabelText()));
-        component.setMainLabelText(createComponentLabel(mainLabelDecorator, ref,
-                                                        component.getMainLabelText()));
+
+        ListenerPayload payload = listeners.remove(ref);
+        infoLabelDecorator.removeDecoratorChangeListener(payload.info);
+        mainLabelDecorator.removeDecoratorChangeListener(payload.main);
+        iconDecorator.removeDecoratorChangeListener(payload.icon);
+    }
+    
+    public void unregister(ReferenceTitle pane) {
+        unregister(pane.getReferenceComponent());
+    }
+    
+    public void registerAndSetIcon(ReferenceComponent component) {
+        Ref ref = component.getReference();
+        component.setInfoLabelText(createComponentLabel(infoLabelDecorator, ref, ""));
+        component.setMainLabelText(createComponentLabel(mainLabelDecorator, ref, ""));
         setIcons(component);
         
-        // FIXME: this is a leak
-        infoLabelDecorator.addDecoratorChangeListener(new ActionListener<DecoratorNotifier.DecorationEvent>() {
-            @Override
-            public void actionPerformed(ActionEvent<DecorationEvent> actionEvent) {
-                component.setInfoLabelText(createComponentLabel(infoLabelDecorator,
-                                                                component.getReference(),
-                                                                component.getInfoLabelText()));
-            }
-        });
-        mainLabelDecorator.addDecoratorChangeListener(new ActionListener<DecoratorNotifier.DecorationEvent>() {
-            @Override
-            public void actionPerformed(ActionEvent<DecorationEvent> actionEvent) {
-                component.setMainLabelText(createComponentLabel(mainLabelDecorator,
-                                                                component.getReference(),
-                                                                component.getMainLabelText()));
-            }
-        });
-        iconDecorator.addDecoratorChangeListener(new ActionListener<DecoratorNotifier.DecorationEvent>() {
-            @Override
-            public void actionPerformed(ActionEvent<DecorationEvent> actionEvent) {
-                setIcons(component);
-            }
-        });
+        ListenerPayload payload = new ListenerPayload();
+
+        InfoLabelListener info = new InfoLabelListener(component);
+        infoLabelDecorator.addDecoratorChangeListener(info);
+        payload.info = info;
+        
+        MainLabelListener main = new MainLabelListener(component);
+        mainLabelDecorator.addDecoratorChangeListener(main);
+        payload.main = main;
+        
+        MainIconListener icon = new MainIconListener(component);
+        iconDecorator.addDecoratorChangeListener(icon);
+        payload.icon = icon;
+        
+        listeners.put(ref, payload);
     }
 
-    private void setIcons(final ReferenceComponent component) {
+    private void setIcons(ReferenceComponent component) {
         Icons icons = createComponentIcon(iconDecorator, component.getReference());
         
         component.setIcon(icons.main, icons.selected);
     }
     
-    public void registerAndSetIcon(final ReferenceTitle pane) {
+    public void registerAndSetIcon(ReferenceTitle pane) {
         registerAndSetIcon(pane.getReferenceComponent());
     }
     
@@ -137,4 +150,53 @@
     public DecoratorListener<ReferenceFieldIconDecorator> getIconDecoratorListener() {
         return iconDecorator;
     }
+    
+    private class ListenerPayload {
+        ActionListener<DecoratorNotifier.DecorationEvent> main;
+        ActionListener<DecoratorNotifier.DecorationEvent> info;
+        ActionListener<DecoratorNotifier.DecorationEvent> icon;
+    }
+    
+    private class InfoLabelListener implements ActionListener<DecoratorNotifier.DecorationEvent> {
+        
+        private ReferenceComponent component;
+        InfoLabelListener(ReferenceComponent component) {
+            this.component = component;
+        }
+        
+        @Override
+        public void actionPerformed(ActionEvent<DecorationEvent> actionEvent) {
+            Ref ref = component.getReference();
+            String label = createComponentLabel(infoLabelDecorator, ref, "");
+            component.setInfoLabelText(label);
+        }
+    }
+    
+    private class MainLabelListener implements ActionListener<DecoratorNotifier.DecorationEvent> {
+        private ReferenceComponent component;
+
+        MainLabelListener(ReferenceComponent component) {
+            this.component = component;
+        }
+        
+        @Override
+        public void actionPerformed(ActionEvent<DecorationEvent> actionEvent) {
+            Ref ref = component.getReference();
+            String label = createComponentLabel(mainLabelDecorator, ref, "");
+            component.setMainLabelText(label);
+        }
+    }
+    
+    private class MainIconListener implements ActionListener<DecoratorNotifier.DecorationEvent> {
+        private ReferenceComponent component;
+        
+        MainIconListener(ReferenceComponent component) {
+            this.component = component;
+        }
+        
+        @Override
+        public void actionPerformed(ActionEvent<DecorationEvent> actionEvent) {
+            setIcons(component);
+        }
+    }
 }
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/accordion/AccordionTest.java	Thu Nov 14 18:17:49 2013 +0100
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/accordion/AccordionTest.java	Thu Nov 14 18:17:50 2013 +0100
@@ -120,6 +120,14 @@
         public void setModel(AccordionModel<String, String> model) {
             this.model = model;
         }
+        
+        @Override
+        public void removeComponent(AccordionComponent accordionComponent,
+                                    String header, String component)
+        {}
+        
+        @Override
+        public void removeHeader(TitledPane pane, String header) {}
     }
     
     @BeforeClass