changeset 966:bab2eabfab98

Merge
author Elliott Baron <ebaron@redhat.com>
date Mon, 11 Feb 2013 16:56:46 -0500
parents f6bc84590701 (diff) 59dd66fbed14 (current diff)
children 2dc71d3fbeed
files
diffstat 17 files changed, 498 insertions(+), 733 deletions(-) [+]
line wrap: on
line diff
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/Backend.java	Mon Feb 11 22:03:47 2013 +0100
+++ b/agent/core/src/main/java/com/redhat/thermostat/backend/Backend.java	Mon Feb 11 16:56:46 2013 -0500
@@ -51,6 +51,8 @@
  * <p>
  * To register a new backend, register an instance of the class with the OSGi
  * service registry.
+ * 
+ * @see VmListenerBackend
  */
 @ExtensionPoint
 public abstract class Backend implements Ordered {
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/BackendRegistry.java	Mon Feb 11 22:03:47 2013 +0100
+++ b/agent/core/src/main/java/com/redhat/thermostat/backend/BackendRegistry.java	Mon Feb 11 16:56:46 2013 -0500
@@ -42,7 +42,6 @@
 import org.osgi.framework.Constants;
 import org.osgi.framework.InvalidSyntaxException;
 
-import com.redhat.thermostat.backend.Backend;
 import com.redhat.thermostat.common.ThermostatExtensionRegistry;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/main/java/com/redhat/thermostat/backend/VmListenerBackend.java	Mon Feb 11 16:56:46 2013 -0500
@@ -0,0 +1,213 @@
+/*
+ * 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.backend;
+
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import sun.jvmstat.monitor.HostIdentifier;
+import sun.jvmstat.monitor.MonitorException;
+import sun.jvmstat.monitor.MonitoredHost;
+import sun.jvmstat.monitor.MonitoredVm;
+import sun.jvmstat.monitor.VmIdentifier;
+import sun.jvmstat.monitor.event.VmListener;
+
+import com.redhat.thermostat.agent.VmStatusListener;
+import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
+import com.redhat.thermostat.common.Pair;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+
+/**
+ * This class is a convenient subclass of {@link Backend} for those that need to
+ * attach {@link VmListener} in response to starting and stopping of JVMs on a
+ * host.
+ * 
+ * @see VmStatusListener
+ * @see Backend
+ */
+public abstract class VmListenerBackend extends Backend implements VmStatusListener {
+    
+    private static final Logger logger = LoggingUtils.getLogger(VmListenerBackend.class);
+
+    private MonitoredHost host;
+    private Map<Integer, Pair<MonitoredVm, ? extends VmListener>> pidToData = new HashMap<>();
+    private final VmStatusListenerRegistrar registrar;
+    private boolean started;
+
+    public VmListenerBackend(BackendID id, VmStatusListenerRegistrar registrar) {
+        super(id);
+        this.registrar = registrar;
+        
+        try {
+            HostIdentifier hostId = new HostIdentifier((String) null);
+            host = MonitoredHost.getMonitoredHost(hostId);
+        } catch (MonitorException me) {
+            logger.log(Level.WARNING, "Problems with connecting jvmstat to local machine", me);
+        } catch (URISyntaxException use) {
+            logger.log(Level.WARNING, "Failed to create host identifier", use);
+        }
+    }
+    
+    /**
+     * {@inheritDoc}
+     * 
+     * <p>
+     * Registers a VmListener to begin receiving VM lifecycle events.
+     * Subclasses should call <code>super.activate()</code> when overriding this method.
+     * </p>
+     */
+    @Override
+    public boolean activate() {
+        if (!started && host != null) {
+            registrar.register(this);
+            started = true;
+        }
+        return started;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * <p>
+     * Unregisters the VmListener to stop receiving VM lifecycle events.
+     * Subclasses should call <code>super.deactivate()</code> when overriding this method.
+     * </p>
+     */
+    @Override
+    public boolean deactivate() {
+        if (started) {
+            registrar.unregister(this);
+            removeVmListeners();
+            started = false;
+        }
+        return !started;
+    }
+    
+    @Override
+    public boolean isActive() {
+        return started;
+    }
+
+    public void vmStatusChanged(Status newStatus, int pid) {
+        switch (newStatus) {
+        case VM_STARTED:
+            /* fall-through */
+        case VM_ACTIVE:
+            handleNewVm(pid);
+            break;
+        case VM_STOPPED:
+            handleStoppedVm(pid);
+            break;
+        default:
+            break;
+        }
+    }
+
+    private void handleNewVm(int pid) {
+        if (attachToNewProcessByDefault()) {
+            try {
+                MonitoredVm vm = host.getMonitoredVm(host.getHostIdentifier().resolve(new VmIdentifier(String.valueOf(pid))));
+                VmListener listener = createVmListener(pid);
+                vm.addVmListener(listener);
+    
+                pidToData.put(pid, new Pair<>(vm, listener));
+                logger.finer("Attached VmListener for VM: " + pid);
+            } catch (MonitorException | URISyntaxException e) {
+                logger.log(Level.WARNING, "unable to attach to vm " + pid, e);
+            }
+        } else {
+            logger.log(Level.FINE, "skipping new vm " + pid);
+        }
+    }
+
+    private void handleStoppedVm(int pid) {
+        Pair<MonitoredVm, ? extends VmListener> data = pidToData.remove(pid);
+        // we were not monitoring pid at all, so nothing to do
+        if (data == null) {
+            return;
+        }
+    
+        MonitoredVm vm = data.getFirst();
+        VmListener listener = data.getSecond();
+        try {
+            vm.removeVmListener(listener);
+        } catch (MonitorException e) {
+            logger.log(Level.WARNING, "can't remove vm listener", e);
+        }
+        vm.detach();
+    }
+
+    private void removeVmListeners() {
+        for (Pair<MonitoredVm, ? extends VmListener> data : pidToData.values()) {
+            MonitoredVm vm = data.getFirst();
+            VmListener listener = data.getSecond();
+            try {
+                vm.removeVmListener(listener);
+            } catch (MonitorException e) {
+                logger.log(Level.WARNING, "can't remove vm listener", e);
+            }
+        }
+    }
+    
+    /**
+     * Creates a new {@link VmListener} for the virtual machine
+     * specified by the pid. This method is called when a new
+     * JVM is started or for JVMs already active when this Backend
+     * was activated.
+     * @param pid the process ID of the JVM
+     * @return a new VmListener for the VM specified by pid
+     */
+    protected abstract VmListener createVmListener(int pid);
+    
+    /*
+     * For testing purposes only.
+     */
+    void setHost(MonitoredHost host) {
+        this.host = host;
+    }
+    
+    /*
+     * For testing purposes only.
+     */
+    Map<Integer, Pair<MonitoredVm, ? extends VmListener>> getPidToDataMap() {
+        return pidToData;
+    }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/test/java/com/redhat/thermostat/backend/VmListenerBackendTest.java	Mon Feb 11 16:56:46 2013 -0500
@@ -0,0 +1,242 @@
+/*
+ * 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.backend;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import java.net.URISyntaxException;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import sun.jvmstat.monitor.HostIdentifier;
+import sun.jvmstat.monitor.MonitorException;
+import sun.jvmstat.monitor.MonitoredHost;
+import sun.jvmstat.monitor.MonitoredVm;
+import sun.jvmstat.monitor.VmIdentifier;
+import sun.jvmstat.monitor.event.VmListener;
+
+import com.redhat.thermostat.agent.VmStatusListener.Status;
+import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
+
+public class VmListenerBackendTest {
+    
+    private VmListenerBackend backend;
+    private HostIdentifier hostIdentifier;
+    private MonitoredHost host;
+    private MonitoredVm monitoredVm;
+    private VmListener listener;
+    private VmStatusListenerRegistrar registrar;
+
+    @Before
+    public void setup() throws URISyntaxException, MonitorException {
+        BackendID id = mock(BackendID.class);
+        registrar = mock(VmStatusListenerRegistrar.class);
+        listener = mock(VmListener.class);
+        
+        hostIdentifier = mock(HostIdentifier.class);
+        when(hostIdentifier.resolve(isA(VmIdentifier.class))).then(new Answer<VmIdentifier>() {
+            @Override
+            public VmIdentifier answer(InvocationOnMock invocation) throws Throwable {
+                return (VmIdentifier) invocation.getArguments()[0];
+            }
+        });
+        host = mock(MonitoredHost.class);
+        when(host.getHostIdentifier()).thenReturn(hostIdentifier);
+        
+        monitoredVm = mock(MonitoredVm.class);
+        
+        backend = new TestBackend(id, registrar);
+        backend.setHost(host);
+    }
+    
+    @Test
+    public void testActivate() {
+        backend.activate();
+        assertTrue(backend.isActive());
+        verify(registrar).register(backend);
+    }
+
+    @Test
+    public void testActivateTwice() {
+        assertTrue(backend.activate());
+        assertTrue(backend.isActive());
+
+        assertTrue(backend.activate());
+        assertTrue(backend.isActive());
+    }
+
+    @Test
+    public void testCanNotActivateWithoutMonitoredHost() {
+        backend.setHost(null);
+
+        assertFalse(backend.activate());
+        assertFalse(backend.isActive());
+    }
+    
+    @Test
+    public void testDeactivate() {
+        backend.activate();
+        backend.deactivate();
+        verify(registrar).unregister(backend);
+        assertFalse(backend.isActive());
+    }
+
+    @Test
+    public void testDeactivateTwice() {
+        backend.activate();
+
+        assertTrue(backend.deactivate());
+        assertFalse(backend.isActive());
+        assertTrue(backend.deactivate());
+    }
+    
+    @Test
+    public void testNewVM() throws MonitorException, URISyntaxException {
+        final int VM_PID = 1;
+        VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID));
+        when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm);
+
+        backend.vmStatusChanged(Status.VM_STARTED, 1);
+
+        verify(monitoredVm).addVmListener(listener);
+    }
+
+    @Test
+    public void testAlreadyRunningVM() throws MonitorException, URISyntaxException {
+        final int VM_PID = 1;
+        VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID));
+        when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm);
+
+        backend.vmStatusChanged(Status.VM_ACTIVE, 1);
+
+        verify(monitoredVm).addVmListener(listener);
+    }
+
+    @Test
+    public void testStatVMGetMonitoredVmFails() throws MonitorException {
+        MonitorException monitorException = new MonitorException();
+        when(host.getMonitoredVm(isA(VmIdentifier.class))).thenThrow(monitorException);
+
+        backend.vmStatusChanged(Status.VM_STARTED, 1);
+
+        assertFalse(backend.getPidToDataMap().containsKey(1));
+    }
+
+    @Test
+    public void testStoppedVM() throws MonitorException, URISyntaxException {
+        final int VM_PID = 1;
+        VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID));
+        when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm);
+
+        backend.vmStatusChanged(Status.VM_STARTED, 1);
+        backend.vmStatusChanged(Status.VM_STOPPED, 1);
+
+        verify(monitoredVm).removeVmListener(listener);
+    }
+
+    @Test
+    public void testUnknownVMStopped() throws URISyntaxException, MonitorException {
+        final int VM_PID = 1;
+        VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID));
+        when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm);
+
+        backend.vmStatusChanged(Status.VM_STOPPED, 1);
+
+        verifyNoMoreInteractions(monitoredVm);
+    }
+
+    @Test
+    public void testErrorRemovingVmListener() throws URISyntaxException, MonitorException {
+        final int VM_PID = 1;
+        VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID));
+        when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm);
+        MonitorException monitorException = new MonitorException();
+        doThrow(monitorException).when(monitoredVm).removeVmListener(listener);
+
+        backend.vmStatusChanged(Status.VM_STARTED, 1);
+        backend.vmStatusChanged(Status.VM_STOPPED, 1);
+
+        verify(monitoredVm).detach();
+    }
+    
+    @Test
+    public void testDeactivateUnregistersListener() throws URISyntaxException, MonitorException {
+        final int VM_PID = 1;
+        backend.activate();
+        
+        VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID));
+        when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm);
+
+        backend.vmStatusChanged(Status.VM_STARTED, 1);
+        backend.deactivate();
+        verify(monitoredVm).removeVmListener(listener);
+    }
+    
+    private class TestBackend extends VmListenerBackend {
+
+        public TestBackend(BackendID id, VmStatusListenerRegistrar registrar) {
+            super(id, registrar);
+        }
+
+        @Override
+        public int getOrderValue() {
+            return 0;
+        }
+
+        @Override
+        protected VmListener createVmListener(int pid) {
+            return listener;
+        }
+
+        @Override
+        public boolean attachToNewProcessByDefault() {
+            return true;
+        }
+        
+    }
+
+}
--- a/common/core/src/main/java/com/redhat/thermostat/common/Ordered.java	Mon Feb 11 22:03:47 2013 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/Ordered.java	Mon Feb 11 16:56:46 2013 -0500
@@ -83,6 +83,8 @@
      * services. A service with a lower order value will
      * be processed before a service of a higher order value. This
      * ordering is used, for example, to sort views in a client's UI.
+     * Please take care to ensure the value returned by this
+     * implementation does not collide with other implementations.
      * 
      * The order value should be offset from one of the provided
      * constants in this class. Such as {@link #ORDER_DEFAULT_GROUP}.
--- a/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaBackend.java	Mon Feb 11 22:03:47 2013 +0100
+++ b/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaBackend.java	Mon Feb 11 16:56:46 2013 -0500
@@ -129,7 +129,7 @@
 
     @Override
     public int getOrderValue() {
-        return ORDER_CPU_GROUP;
+        return ORDER_MEMORY_GROUP + 80;
     }
 
 }
--- a/numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaBackendTest.java	Mon Feb 11 22:03:47 2013 +0100
+++ b/numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaBackendTest.java	Mon Feb 11 16:56:46 2013 -0500
@@ -46,7 +46,6 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
 import java.io.IOException;
@@ -168,7 +167,7 @@
 
     @Test
     public void testOrderValue() {
-        assertEquals(Ordered.ORDER_CPU_GROUP, backend.getOrderValue());
+        assertEquals(Ordered.ORDER_MEMORY_GROUP + 80, backend.getOrderValue());
     }
 }
 
--- a/numa/client-core/src/main/java/com/redhat/thermostat/numa/client/core/internal/NumaInformationServiceImpl.java	Mon Feb 11 22:03:47 2013 +0100
+++ b/numa/client-core/src/main/java/com/redhat/thermostat/numa/client/core/internal/NumaInformationServiceImpl.java	Mon Feb 11 16:56:46 2013 -0500
@@ -47,7 +47,7 @@
 
 public class NumaInformationServiceImpl implements NumaInformationService {
     
-    private static final int ORDER = ORDER_MEMORY_GROUP;
+    private static final int ORDER = ORDER_MEMORY_GROUP + 80;
     private static final Filter<HostRef> FILTER = new NameMatchingRefFilter<>();
 
     private ApplicationService appSvc;
--- a/numa/client-core/src/test/java/com/redhat/thermostat/numa/client/core/NumaInformationServiceTest.java	Mon Feb 11 22:03:47 2013 +0100
+++ b/numa/client-core/src/test/java/com/redhat/thermostat/numa/client/core/NumaInformationServiceTest.java	Mon Feb 11 16:56:46 2013 -0500
@@ -68,7 +68,7 @@
         NumaInformationServiceImpl numaInfoService = new NumaInformationServiceImpl(appSvc, numaDAO, numaViewProvider);
 
         int order = numaInfoService.getOrderValue();
-        assertEquals(Ordered.ORDER_MEMORY_GROUP, order);
+        assertEquals(Ordered.ORDER_MEMORY_GROUP + 80, order);
         HostRef ref = mock(HostRef.class);
         assertTrue(numaInfoService.getInformationServiceController(ref) instanceof NumaController);
         assertNotNull(numaInfoService.getFilter());
--- a/vm-classstat/agent/src/main/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatBackend.java	Mon Feb 11 22:03:47 2013 +0100
+++ b/vm-classstat/agent/src/main/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatBackend.java	Mon Feb 11 16:56:46 2013 -0500
@@ -36,86 +36,26 @@
 
 package com.redhat.thermostat.vm.classstat.agent.internal;
 
-import java.net.URISyntaxException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import sun.jvmstat.monitor.HostIdentifier;
-import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredHost;
-import sun.jvmstat.monitor.MonitoredVm;
-import sun.jvmstat.monitor.VmIdentifier;
 import sun.jvmstat.monitor.event.VmListener;
 
-import com.redhat.thermostat.agent.VmStatusListener;
 import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
-import com.redhat.thermostat.backend.Backend;
 import com.redhat.thermostat.backend.BackendID;
 import com.redhat.thermostat.backend.BackendsProperties;
-import com.redhat.thermostat.common.Pair;
+import com.redhat.thermostat.backend.VmListenerBackend;
 import com.redhat.thermostat.common.Version;
-import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.vm.classstat.common.VmClassStatDAO;
 
-public class VmClassStatBackend extends Backend implements VmStatusListener {
-
-    private static final Logger LOGGER = LoggingUtils.getLogger(VmClassStatBackend.class);
+public class VmClassStatBackend extends VmListenerBackend {
 
     private final VmClassStatDAO vmClassStats;
-    private final VmStatusListenerRegistrar registrar;
-
-    private final Map<Integer, Pair<MonitoredVm, ? extends VmListener>> pidToVmAndListener = new HashMap<>();
-
-    private MonitoredHost host;
-
-    private boolean started;
 
     public VmClassStatBackend(VmClassStatDAO vmClassStatDAO, Version version, VmStatusListenerRegistrar registrar) {
-        super(new BackendID("VM Classes Backend", VmClassStatBackend.class.getName()));
+        super(new BackendID("VM Classes Backend", VmClassStatBackend.class.getName()), registrar);
         this.vmClassStats = vmClassStatDAO;
-        this.registrar = registrar;
         
         setConfigurationValue(BackendsProperties.VENDOR.name(), "Red Hat, Inc.");
         setConfigurationValue(BackendsProperties.DESCRIPTION.name(), "Gathers class loading statistics about a JVM");
         setConfigurationValue(BackendsProperties.VERSION.name(), version.getVersionNumber());
-        
-        try {
-            HostIdentifier hostId = new HostIdentifier((String) null);
-            host = MonitoredHost.getMonitoredHost(hostId);
-        } catch (MonitorException me) {
-            LOGGER.log(Level.WARNING, "Problems with connecting jvmstat to local machine", me);
-        } catch (URISyntaxException use) {
-            LOGGER.log(Level.WARNING, "Failed to create host identifier", use);
-        }
-    }
-
-    /*
-     * Methods from Backend
-     */
-
-    @Override
-    public boolean activate() {
-        if (!started && host != null) {
-            registrar.register(this);
-            started = true;
-        }
-        return started;
-    }
-
-    @Override
-    public boolean deactivate() {
-        if (started) {
-            registrar.unregister(this);
-            started = false;
-        }
-        return !started;
-    }
-    
-    @Override
-    public boolean isActive() {
-        return started;
     }
     
     @Override
@@ -133,70 +73,9 @@
         return ORDER_MEMORY_GROUP + 30;
     }
 
-    /*
-     *  Methods from VmStatusListener
-     */
-
     @Override
-    public void vmStatusChanged(Status newStatus, int pid) {
-        switch (newStatus) {
-        case VM_STARTED:
-            /* fall-through */
-        case VM_ACTIVE:
-            vmStarted(pid);
-            break;
-        case VM_STOPPED:
-            vmStopped(pid);
-            break;
-        }
-    }
-
-    private void vmStarted(int pid) {
-        if (attachToNewProcessByDefault()) {
-            try {
-                MonitoredVm vm = host.getMonitoredVm(host.getHostIdentifier().resolve(new VmIdentifier(String.valueOf(pid))));
-                VmClassStatVmListener listener = new VmClassStatVmListener(vmClassStats, pid);
-                vm.addVmListener(listener);
-
-                pidToVmAndListener.put(pid, new Pair<>(vm, listener));
-                LOGGER.finer("Attached VmListener for VM: " + pid);
-            } catch (MonitorException | URISyntaxException e) {
-                LOGGER.log(Level.WARNING, "Could not attach to new vm " + pid, e);
-            }
-        } else {
-            LOGGER.log(Level.FINE, "skipping new vm " + pid);
-        }
-    }
-
-    private void vmStopped(Integer pid) {
-        Pair<MonitoredVm, ? extends VmListener> data = pidToVmAndListener.remove(pid);
-        // if there is no data, we must never have attached to the vm. Nothing to do.
-        if (data == null) {
-            return;
-        }
-
-        MonitoredVm vm = data.getFirst();
-        VmListener listener = data.getSecond();
-        try {
-            vm.removeVmListener(listener);
-        } catch (MonitorException e) {
-            LOGGER.log(Level.WARNING, "can't remove vm listener", e);
-        }
-        vm.detach();
-    }
-
-    /*
-     * For testing purposes only.
-     */
-    void setHost(MonitoredHost host) {
-        this.host = host;
-    }
-
-    /*
-     * For testing purposes only.
-     */
-    Map<Integer, Pair<MonitoredVm, ? extends VmListener>> getPidToDataMap() {
-        return pidToVmAndListener;
+    protected VmListener createVmListener(int pid) {
+        return new VmClassStatVmListener(vmClassStats, pid);
     }
 
 }
--- a/vm-classstat/agent/src/test/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatBackendTest.java	Mon Feb 11 22:03:47 2013 +0100
+++ b/vm-classstat/agent/src/test/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatBackendTest.java	Mon Feb 11 16:56:46 2013 -0500
@@ -36,31 +36,18 @@
 
 package com.redhat.thermostat.vm.classstat.agent.internal;
 
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import java.net.URISyntaxException;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
-import sun.jvmstat.monitor.HostIdentifier;
 import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredHost;
-import sun.jvmstat.monitor.MonitoredVm;
-import sun.jvmstat.monitor.VmIdentifier;
 
 import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
-import com.redhat.thermostat.agent.VmStatusListener.Status;
 import com.redhat.thermostat.common.Ordered;
 import com.redhat.thermostat.common.Version;
 import com.redhat.thermostat.vm.classstat.common.VmClassStatDAO;
@@ -68,10 +55,6 @@
 public class VmClassStatBackendTest {
     
     private VmClassStatBackend backend;
-    private MonitoredHost host;
-    private VmStatusListenerRegistrar registrar;
-    private HostIdentifier hostIdentifier;
-    private MonitoredVm monitoredVm1;
 
     @Before
     public void setup() throws MonitorException, URISyntaxException {
@@ -80,139 +63,15 @@
         Version version = mock(Version.class);
         when(version.getVersionNumber()).thenReturn("0.0.0");
         
-        registrar = mock(VmStatusListenerRegistrar.class);
-
-        hostIdentifier = mock(HostIdentifier.class);
-        when(hostIdentifier.resolve(isA(VmIdentifier.class))).then(new Answer<VmIdentifier>() {
-            @Override
-            public VmIdentifier answer(InvocationOnMock invocation) throws Throwable {
-                return (VmIdentifier) invocation.getArguments()[0];
-            }
-        });
-        host = mock(MonitoredHost.class);
-        when(host.getHostIdentifier()).thenReturn(hostIdentifier);
-
-        monitoredVm1 = mock(MonitoredVm.class);
+        VmStatusListenerRegistrar registrar = mock(VmStatusListenerRegistrar.class);
 
         backend = new VmClassStatBackend(vmClassStatDao, version, registrar);
-        
-        backend.setHost(host);
-    }
-
-    @Test
-    public void testActivate() {
-        backend.activate();
-        assertTrue(backend.isActive());
-        verify(registrar).register(backend);
-    }
-
-    @Test
-    public void testActivateTwice() {
-        assertTrue(backend.activate());
-        assertTrue(backend.isActive());
-
-        assertTrue(backend.activate());
-        assertTrue(backend.isActive());
-    }
-
-    @Test
-    public void testCanNotActivateWithoutMonitoredHost() {
-        backend.setHost(null);
-
-        assertFalse(backend.activate());
-        assertFalse(backend.isActive());
-    }
-    
-    @Test
-    public void testDeactivate() {
-        backend.activate();
-        backend.deactivate();
-        verify(registrar).unregister(backend);
-        assertFalse(backend.isActive());
-    }
-
-    @Test
-    public void testDeactivateTwice() {
-        backend.activate();
-
-        assertTrue(backend.deactivate());
-        assertFalse(backend.isActive());
-        assertTrue(backend.deactivate());
-    }
-
-    @Test
-    public void testNewVM() throws MonitorException, URISyntaxException {
-        int VM_PID = 1;
-        VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID));
-        when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm1);
-
-        backend.vmStatusChanged(Status.VM_STARTED, 1);
-
-        verify(monitoredVm1).addVmListener(isA(VmClassStatVmListener.class));
-    }
-
-    @Test
-    public void testAlreadyRunningVM() throws MonitorException, URISyntaxException {
-        int VM_PID = 1;
-        VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID));
-        when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm1);
-
-        backend.vmStatusChanged(Status.VM_ACTIVE, 1);
-
-        verify(monitoredVm1).addVmListener(isA(VmClassStatVmListener.class));
-    }
-
-    @Test
-    public void testStatVMGetMonitoredVmFails() throws MonitorException {
-        MonitorException monitorException = new MonitorException();
-        when(host.getMonitoredVm(isA(VmIdentifier.class))).thenThrow(monitorException);
-
-        backend.vmStatusChanged(Status.VM_STARTED, 1);
-
-        assertFalse(backend.getPidToDataMap().containsKey(1));
-    }
-
-    @Test
-    public void testStoppedVM() throws MonitorException, URISyntaxException {
-        int VM_PID = 1;
-        VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID));
-        when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm1);
-
-        backend.vmStatusChanged(Status.VM_STARTED, 1);
-        backend.vmStatusChanged(Status.VM_STOPPED, 1);
-
-        verify(monitoredVm1).removeVmListener(isA(VmClassStatVmListener.class));
-    }
-
-    @Test
-    public void testUnknownVMStopped() throws URISyntaxException, MonitorException {
-        int VM_PID = 1;
-        VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID));
-        when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm1);
-
-        backend.vmStatusChanged(Status.VM_STOPPED, 1);
-
-        verifyNoMoreInteractions(monitoredVm1);
-    }
-
-    @Test
-    public void testErrorRemovingVmListener() throws URISyntaxException, MonitorException {
-        int VM_PID = 1;
-        VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID));
-        when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm1);
-        MonitorException monitorException = new MonitorException();
-        doThrow(monitorException).when(monitoredVm1).removeVmListener(isA(VmClassStatVmListener.class));
-
-        backend.vmStatusChanged(Status.VM_STARTED, 1);
-        backend.vmStatusChanged(Status.VM_STOPPED, 1);
-
-        verify(monitoredVm1).detach();
     }
 
     @Test
     public void testOrderValue() {
         int orderValue = backend.getOrderValue();
-        assertTrue(orderValue > Ordered.ORDER_MEMORY_GROUP);
+        assertTrue(orderValue >= Ordered.ORDER_MEMORY_GROUP);
         assertTrue(orderValue < Ordered.ORDER_NETWORK_GROUP);
     }
 }
--- a/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackend.java	Mon Feb 11 22:03:47 2013 +0100
+++ b/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackend.java	Mon Feb 11 16:56:46 2013 -0500
@@ -36,85 +36,29 @@
 
 package com.redhat.thermostat.vm.gc.agent.internal;
 
-import java.net.URISyntaxException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import sun.jvmstat.monitor.HostIdentifier;
-import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredHost;
-import sun.jvmstat.monitor.MonitoredVm;
-import sun.jvmstat.monitor.VmIdentifier;
 import sun.jvmstat.monitor.event.VmListener;
 
-import com.redhat.thermostat.agent.VmStatusListener;
 import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
-import com.redhat.thermostat.backend.Backend;
 import com.redhat.thermostat.backend.BackendID;
 import com.redhat.thermostat.backend.BackendsProperties;
-import com.redhat.thermostat.common.Pair;
+import com.redhat.thermostat.backend.VmListenerBackend;
 import com.redhat.thermostat.common.Version;
-import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.vm.gc.common.VmGcStatDAO;
 
-public class VmGcBackend extends Backend implements VmStatusListener {
-
-    private static final Logger LOGGER = LoggingUtils.getLogger(VmGcBackend.class);
+public class VmGcBackend extends VmListenerBackend {
 
     private final VmGcStatDAO vmGcStats;
-    private final VmStatusListenerRegistrar registerer;
 
-    private final Map<Integer, Pair<MonitoredVm, ? extends VmListener>> pidToData = new HashMap<>();
-    private MonitoredHost host;
-    private boolean started;
-
-    public VmGcBackend(VmGcStatDAO vmGcStatDAO, Version version, VmStatusListenerRegistrar registerer) {
-        super(new BackendID("VM GC Backend", VmGcBackend.class.getName()));
+    public VmGcBackend(VmGcStatDAO vmGcStatDAO, Version version, VmStatusListenerRegistrar registrar) {
+        super(new BackendID("VM GC Backend", VmGcBackend.class.getName()), registrar);
         this.vmGcStats = vmGcStatDAO;
-        this.registerer = registerer;
         
         setConfigurationValue(BackendsProperties.VENDOR.name(), "Red Hat, Inc.");
         setConfigurationValue(BackendsProperties.DESCRIPTION.name(), "Gathers garbage collection statistics about a JVM");
         setConfigurationValue(BackendsProperties.VERSION.name(), version.getVersionNumber());
-        
-        try {
-            HostIdentifier hostId = new HostIdentifier((String) null);
-            host = MonitoredHost.getMonitoredHost(hostId);
-        } catch (MonitorException me) {
-            LOGGER.log(Level.WARNING, "Problems with connecting jvmstat to local machine", me);
-        } catch (URISyntaxException use) {
-            LOGGER.log(Level.WARNING, "Failed to create host identifier", use);
-        }
-    }
-
-    // Methods from Backend
-
-    @Override
-    public boolean activate() {
-        if (!started && host != null) {
-            registerer.register(this);
-            started = true;
-        }
-        return started;
-    }
-
-    @Override
-    public boolean deactivate() {
-        if (started) {
-            registerer.unregister(this);
-            started = false;
-        }
-        return !started;
     }
     
     @Override
-    public boolean isActive() {
-        return started;
-    }
-
-    @Override
     public String getConfigurationValue(String key) {
         return null;
     }
@@ -129,66 +73,9 @@
         return ORDER_MEMORY_GROUP + 20;
     }
 
-    // Methods from VmStatusListener
-
     @Override
-    public void vmStatusChanged(Status newStatus, int pid) {
-        switch (newStatus) {
-        case VM_STARTED:
-            /* fall-through */
-        case VM_ACTIVE:
-            vmStarted(pid);
-            break;
-        case VM_STOPPED:
-            vmStopped(pid);
-            break;
-        }
-    }
-
-    private void vmStarted(int pid) {
-        if (attachToNewProcessByDefault()) {
-            try {
-                MonitoredVm vm = host.getMonitoredVm(host.getHostIdentifier().resolve(new VmIdentifier(String.valueOf(pid))));
-                if (vm != null) {
-                    VmGcVmListener listener = new VmGcVmListener(vmGcStats, pid);
-                    vm.addVmListener(listener);
-                    pidToData.put(pid, new Pair<>(vm, listener));
-                    LOGGER.finer("Attached VmListener for VM: " + pid);
-                } else {
-                    LOGGER.warning("could not connect to vm " + pid);
-                }
-            } catch (MonitorException me) {
-                LOGGER.log(Level.WARNING, "could not connect to vm " + pid, me);
-            } catch (URISyntaxException e) {
-                throw new AssertionError("The URI for the monitored vm must be valid, but it is not.");
-            }
-        }
-    }
-
-    private void vmStopped(int pid) {
-        Pair<MonitoredVm, ? extends VmListener> data = pidToData.remove(pid);
-        // if there is no data, we must never have attached to it. Nothing to do.
-        if (data == null) {
-            return;
-        }
-
-        MonitoredVm vm = data.getFirst();
-        VmListener listener = data.getSecond();
-        try {
-            if (listener != null) {
-                vm.removeVmListener(listener);
-            }
-        } catch (MonitorException e) {
-            LOGGER.log(Level.WARNING, "can't remove vm listener", e);
-        }
-        vm.detach();
-    }
-
-    /*
-     * For testing purposes only.
-     */
-    void setHost(MonitoredHost host) {
-        this.host = host;
+    protected VmListener createVmListener(int pid) {
+        return new VmGcVmListener(vmGcStats, pid);
     }
 
 }
--- a/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackendTest.java	Mon Feb 11 22:03:47 2013 +0100
+++ b/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackendTest.java	Mon Feb 11 16:56:46 2013 -0500
@@ -36,39 +36,25 @@
 
 package com.redhat.thermostat.vm.gc.agent.internal;
 
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.isA;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import java.net.URISyntaxException;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
-import sun.jvmstat.monitor.HostIdentifier;
 import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredHost;
-import sun.jvmstat.monitor.MonitoredVm;
-import sun.jvmstat.monitor.VmIdentifier;
 
 import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
-import com.redhat.thermostat.agent.VmStatusListener.Status;
+import com.redhat.thermostat.common.Ordered;
 import com.redhat.thermostat.common.Version;
 import com.redhat.thermostat.vm.gc.common.VmGcStatDAO;
 
 public class VmGcBackendTest {
 
     private VmGcBackend backend;
-    private VmStatusListenerRegistrar registerer;
-
-    private MonitoredHost host;
-    private HostIdentifier hostIdentifier;
-    private MonitoredVm monitoredVm1;
 
     @Before
     public void setup() throws MonitorException, URISyntaxException {
@@ -77,62 +63,16 @@
         Version version = mock(Version.class);
         when(version.getVersionNumber()).thenReturn("0.0.0");
 
-        registerer = mock(VmStatusListenerRegistrar.class);
-
-        hostIdentifier = mock(HostIdentifier.class);
-        when(hostIdentifier.resolve(isA(VmIdentifier.class))).then(new Answer<VmIdentifier>() {
-            @Override
-            public VmIdentifier answer(InvocationOnMock invocation) throws Throwable {
-                return (VmIdentifier) invocation.getArguments()[0];
-            }
-        });
-        host = mock(MonitoredHost.class);
-        when(host.getHostIdentifier()).thenReturn(hostIdentifier);
+        VmStatusListenerRegistrar registrar = mock(VmStatusListenerRegistrar.class);
 
-        monitoredVm1 = mock(MonitoredVm.class);
-
-        backend = new VmGcBackend(vmGcStatDao, version, registerer);
-
-        backend.setHost(host);
-    }
-
-    @Test
-    public void testStart() throws MonitorException {
-        backend.activate();
-        verify(registerer).register(backend);
-        assertTrue(backend.isActive());
+        backend = new VmGcBackend(vmGcStatDao, version, registrar);
     }
 
     @Test
-    public void testStop() throws MonitorException {
-        backend.activate();
-        backend.deactivate();
-        verify(registerer).unregister(backend);
-        assertFalse(backend.isActive());
+    public void testOrderValue() {
+        int order = backend.getOrderValue();
+        assertTrue(order >= Ordered.ORDER_MEMORY_GROUP);
+        assertTrue(order < Ordered.ORDER_NETWORK_GROUP);
     }
-
-    @Test
-    public void testNewVM() throws InterruptedException, MonitorException, URISyntaxException {
-        int VM_PID = 1;
-        VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID));
-        when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm1);
-
-        backend.vmStatusChanged(Status.VM_STARTED, 1);
-
-        verify(monitoredVm1).addVmListener(isA(VmGcVmListener.class));
-    }
-
-    @Test
-    public void testStoppedVM() throws InterruptedException, MonitorException, URISyntaxException {
-        int VM_PID = 1;
-        VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID));
-        when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm1);
-
-        backend.vmStatusChanged(Status.VM_STARTED, 1);
-        backend.vmStatusChanged(Status.VM_STOPPED, 1);
-
-        verify(monitoredVm1).removeVmListener(isA(VmGcVmListener.class));
-    }
-
 }
 
--- a/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/Activator.java	Mon Feb 11 22:03:47 2013 +0100
+++ b/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/Activator.java	Mon Feb 11 16:56:46 2013 -0500
@@ -45,6 +45,7 @@
 import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
 import com.redhat.thermostat.backend.Backend;
 import com.redhat.thermostat.backend.BackendService;
+import com.redhat.thermostat.backend.VmListenerBackend;
 import com.redhat.thermostat.common.MultipleServiceTracker;
 import com.redhat.thermostat.common.MultipleServiceTracker.Action;
 import com.redhat.thermostat.common.Version;
@@ -53,7 +54,7 @@
 public class Activator implements BundleActivator {
     
     private MultipleServiceTracker tracker;
-    private VmMemoryBackend backend;
+    private VmListenerBackend backend;
     private ServiceRegistration reg;
     
     @Override
@@ -94,7 +95,7 @@
     /*
      * For testing purposes only.
      */
-    VmMemoryBackend getBackend() {
+    VmListenerBackend getBackend() {
         return backend;
     }
 }
--- a/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackend.java	Mon Feb 11 22:03:47 2013 +0100
+++ b/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackend.java	Mon Feb 11 16:56:46 2013 -0500
@@ -36,83 +36,27 @@
 
 package com.redhat.thermostat.vm.memory.agent.internal;
 
-import java.net.URISyntaxException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import sun.jvmstat.monitor.HostIdentifier;
-import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredHost;
-import sun.jvmstat.monitor.MonitoredVm;
-import sun.jvmstat.monitor.VmIdentifier;
-import sun.jvmstat.monitor.event.VmListener;
-
-import com.redhat.thermostat.agent.VmStatusListener;
 import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
-import com.redhat.thermostat.backend.Backend;
 import com.redhat.thermostat.backend.BackendID;
 import com.redhat.thermostat.backend.BackendsProperties;
-import com.redhat.thermostat.common.Pair;
+import com.redhat.thermostat.backend.VmListenerBackend;
 import com.redhat.thermostat.common.Version;
-import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO;
 
-public class VmMemoryBackend extends Backend implements VmStatusListener {
-
-    private static final Logger LOGGER = LoggingUtils.getLogger(VmMemoryBackend.class);
+public class VmMemoryBackend extends VmListenerBackend {
 
     private VmMemoryStatDAO vmMemoryStats;
-    private MonitoredHost host;
-    private final VmStatusListenerRegistrar registrar;
-
-    private boolean started;
-    private Map<Integer, Pair<MonitoredVm, ? extends VmListener>> pidToData = new HashMap<>();
-
+    
     public VmMemoryBackend(VmMemoryStatDAO vmMemoryStatDAO, Version version, VmStatusListenerRegistrar registrar) {
-        super(new BackendID("VM Memory Backend", VmMemoryBackend.class.getName()));
+        super(new BackendID("VM Memory Backend", VmMemoryBackend.class.getName()), registrar);
         this.vmMemoryStats = vmMemoryStatDAO;
-        this.registrar = registrar;
         
         setConfigurationValue(BackendsProperties.VENDOR.name(), "Red Hat, Inc.");
         setConfigurationValue(BackendsProperties.DESCRIPTION.name(), "Gathers memory statistics about a JVM");
         setConfigurationValue(BackendsProperties.VERSION.name(), version.getVersionNumber());
-        
-        try {
-            HostIdentifier hostId = new HostIdentifier((String) null);
-            host = MonitoredHost.getMonitoredHost(hostId);
-        } catch (MonitorException me) {
-            LOGGER.log(Level.WARNING, "Problems with connecting jvmstat to local machine", me);
-        } catch (URISyntaxException use) {
-            LOGGER.log(Level.WARNING, "Failed to create host identifier", use);
-        }
-    }
-
-    @Override
-    public boolean activate() {
-        if (!started && host != null) {
-            registrar.register(this);
-            started = true;
-        }
-        return started;
-    }
-
-    @Override
-    public boolean deactivate() {
-        if (started) {
-            registrar.unregister(this);
-            started = false;
-        }
-        return !started;
     }
     
     @Override
-    public boolean isActive() {
-        return started;
-    }
-
-    @Override
     public String getConfigurationValue(String key) {
         return null;
     }
@@ -127,63 +71,9 @@
         return ORDER_MEMORY_GROUP + 40;
     }
 
-    /*
-     * Methods for VmStatusListener
-     */
-    public void vmStatusChanged(Status newStatus, int pid) {
-        switch (newStatus) {
-        case VM_STARTED:
-            /* fall-through */
-        case VM_ACTIVE:
-            handleNewVm(pid);
-            break;
-        case VM_STOPPED:
-            handleStoppedVm(pid);
-            break;
-        default:
-            break;
-        }
-    };
-
-    private void handleNewVm(int pid) {
-        if (attachToNewProcessByDefault()) {
-            try {
-                MonitoredVm vm = host.getMonitoredVm(host.getHostIdentifier().resolve(new VmIdentifier(String.valueOf(pid))));
-                VmMemoryVmListener listener = new VmMemoryVmListener(vmMemoryStats, pid);
-                vm.addVmListener(listener);
-
-                pidToData.put(pid, new Pair<>(vm, listener));
-                LOGGER.finer("Attached VmListener for VM: " + pid);
-            } catch (MonitorException | URISyntaxException e) {
-                LOGGER.log(Level.WARNING, "unable to attach to vm " + pid, e);
-            }
-        } else {
-            LOGGER.log(Level.FINE, "skipping new vm " + pid);
-        }
-    }
-
-    private void handleStoppedVm(int pid) {
-        Pair<MonitoredVm, ? extends VmListener> data = pidToData.remove(pid);
-        // we were not monitoring pid at all, so nothing to do
-        if (data == null) {
-            return;
-        }
-
-        MonitoredVm vm = data.getFirst();
-        VmListener listener = data.getSecond();
-        try {
-            vm.removeVmListener(listener);
-        } catch (MonitorException e) {
-            LOGGER.log(Level.WARNING, "can't remove vm listener", e);
-        }
-        vm.detach();
-    }
-
-    /*
-     * For testing purposes only.
-     */
-    void setHost(MonitoredHost host) {
-        this.host = host;
+    @Override
+    protected VmMemoryVmListener createVmListener(int pid) {
+        return new VmMemoryVmListener(vmMemoryStats, pid);
     }
     
 }
--- a/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/ActivatorTest.java	Mon Feb 11 22:03:47 2013 +0100
+++ b/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/ActivatorTest.java	Mon Feb 11 16:56:46 2013 -0500
@@ -49,6 +49,7 @@
 
 import com.redhat.thermostat.backend.Backend;
 import com.redhat.thermostat.backend.BackendService;
+import com.redhat.thermostat.backend.VmListenerBackend;
 import com.redhat.thermostat.testutils.StubBundleContext;
 import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO;
 
@@ -90,7 +91,7 @@
         activator.start(context);
 
         assertTrue(context.isServiceRegistered(Backend.class.getName(), VmMemoryBackend.class));
-        VmMemoryBackend backend = activator.getBackend();
+        VmListenerBackend backend = activator.getBackend();
         assertNotNull(backend);
 
         // core thermostat activates the backend when the backend is detected
--- a/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackendTest.java	Mon Feb 11 22:03:47 2013 +0100
+++ b/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackendTest.java	Mon Feb 11 16:56:46 2013 -0500
@@ -36,31 +36,17 @@
 
 package com.redhat.thermostat.vm.memory.agent.internal;
 
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import java.net.URISyntaxException;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
-import sun.jvmstat.monitor.HostIdentifier;
 import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredHost;
-import sun.jvmstat.monitor.MonitoredVm;
-import sun.jvmstat.monitor.VmIdentifier;
-import sun.jvmstat.monitor.event.VmListener;
 
-import com.redhat.thermostat.agent.VmStatusListener.Status;
 import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
 import com.redhat.thermostat.common.Ordered;
 import com.redhat.thermostat.common.Version;
@@ -69,159 +55,24 @@
 public class VmMemoryBackendTest {
     
     private VmMemoryBackend backend;
-    private MonitoredHost host;
-    private VmStatusListenerRegistrar registrar;
-    private VmMemoryStatDAO vmMemoryStatDao;
 
     @Before
     public void setup() throws MonitorException, URISyntaxException {
-        vmMemoryStatDao = mock(VmMemoryStatDAO.class);
+        VmMemoryStatDAO vmMemoryStatDao = mock(VmMemoryStatDAO.class);
         
         Version version = mock(Version.class);
         when(version.getVersionNumber()).thenReturn("0.0.0");
 
-        registrar = mock(VmStatusListenerRegistrar.class);
+        VmStatusListenerRegistrar registrar = mock(VmStatusListenerRegistrar.class);
 
         backend = new VmMemoryBackend(vmMemoryStatDao, version, registrar);
-        
-        HostIdentifier hostIdentifier = mock(HostIdentifier.class);
-        when(hostIdentifier.resolve(isA(VmIdentifier.class))).then(new Answer<VmIdentifier>() {
-            @Override
-            public VmIdentifier answer(InvocationOnMock invocation) throws Throwable {
-                return (VmIdentifier) invocation.getArguments()[0];
-            }
-        });
-        host = mock(MonitoredHost.class);
-        when(host.getHostIdentifier()).thenReturn(hostIdentifier);
-
-        backend.setHost(host);
-    }
-
-    @Test
-    public void testActivate() {
-        assertTrue(backend.activate());
-
-        verify(registrar).register(backend);
-        assertTrue(backend.isActive());
-    }
-
-    @Test
-    public void testActivateTwice() {
-        assertTrue(backend.activate());
-        assertTrue(backend.isActive());
-
-        assertTrue(backend.activate());
-        assertTrue(backend.isActive());
-
-        verify(registrar).register(backend);
-    }
-
-    @Test
-    public void testActivateFailsIfHostIsNull() {
-        backend.setHost(null);
-
-        assertFalse(backend.activate());
-    }
-
-    @Test
-    public void testDeactivate() {
-        backend.activate();
-        backend.deactivate();
-
-        verify(registrar).unregister(backend);
-        assertFalse(backend.isActive());
-    }
-
-    @Test
-    public void testDeactiveTwice() {
-        assertTrue(backend.activate());
-
-        assertTrue(backend.deactivate());
-        assertFalse(backend.isActive());
-
-        assertTrue(backend.deactivate());
-        assertFalse(backend.isActive());
-
-        verify(registrar).unregister(backend);
-    }
-
-    @Test
-    public void testNewVmStarted() throws URISyntaxException, MonitorException {
-        int VM_PID = 10;
-        VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID));
-        MonitoredVm monitoredVm = mock(MonitoredVm.class);
-
-        when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm);
-
-        backend.vmStatusChanged(Status.VM_STARTED, VM_PID);
-
-        verify(monitoredVm).addVmListener(isA(VmMemoryVmListener.class));
-    }
-
-    @Test
-    public void testErrorInAttachingToNewVm() throws MonitorException, URISyntaxException {
-        int VM_PID = 10;
-        VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID));
-
-        when(host.getMonitoredVm(VM_ID)).thenThrow(new MonitorException());
-
-        backend.vmStatusChanged(Status.VM_STARTED, VM_PID);
-    }
-
-    @Test
-    public void testVmStopped() throws URISyntaxException, MonitorException {
-        int VM_PID = 10;
-        VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID));
-        MonitoredVm monitoredVm = mock(MonitoredVm.class);
-
-        when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm);
-
-        backend.vmStatusChanged(Status.VM_STARTED, VM_PID);
-
-        ArgumentCaptor<VmListener> listenerCaptor = ArgumentCaptor.forClass(VmListener.class);
-        verify(monitoredVm).addVmListener(listenerCaptor.capture());
-
-        backend.vmStatusChanged(Status.VM_STOPPED, VM_PID);
-
-        verify(monitoredVm).removeVmListener(listenerCaptor.getValue());
-        verify(monitoredVm).detach();
-    }
-
-    @Test
-    public void testUnknownVmStoppedIsIgnored() {
-        int VM_PID = 10;
-
-        backend.vmStatusChanged(Status.VM_STOPPED, VM_PID);
-
-        verifyNoMoreInteractions(host, vmMemoryStatDao);
-    }
-
-    @Test
-    public void testStoppedVmIsDetachedEvenInPresenceOfErrors() throws URISyntaxException, MonitorException {
-        int VM_PID = 10;
-        VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID));
-        MonitoredVm monitoredVm = mock(MonitoredVm.class);
-
-        when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm);
-
-        backend.vmStatusChanged(Status.VM_STARTED, VM_PID);
-
-        ArgumentCaptor<VmListener> listenerCaptor = ArgumentCaptor.forClass(VmListener.class);
-        verify(monitoredVm).addVmListener(listenerCaptor.capture());
-
-        VmListener vmListener = listenerCaptor.getValue();
-        doThrow(new MonitorException("test")).when(monitoredVm).removeVmListener(vmListener);
-
-        backend.vmStatusChanged(Status.VM_STOPPED, VM_PID);
-
-        verify(monitoredVm).detach();
     }
 
     @Test
     public void testOrderValue() {
         int orderValue = backend.getOrderValue();
 
-        assertTrue(orderValue > Ordered.ORDER_MEMORY_GROUP);
+        assertTrue(orderValue >= Ordered.ORDER_MEMORY_GROUP);
         assertTrue(orderValue < Ordered.ORDER_NETWORK_GROUP);
     }
 }