changeset 1032:b269be10beb4

Wrap sun.jvmstat class usage Omair had pointed out that the VmListenerBackend exposes sun.jvmstat classes as API. These classes are subject to change and are not part of the Java specification. This commit resolves this issue by wrapping Thermostat's usage of these classes in a new set of API classes. A new VmUpdateListener is used in place of sun.jvmstat.monitor.VmListener. A new internal VmListenerWrapper class maps this class to the underlying VmListener. Performance counters retrieved from s.j.m.MonitoredVm can now be accessed through a new type-safe VmUpdate interface. Finally VmMonitor extracts some of the logic out of VmListenerBackend. With this commit, none of our plugins use any sun.jvmstat classes directly anymore. Reviewed-by: omajid Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-March/006072.html
author Elliott Baron <ebaron@redhat.com>
date Fri, 15 Mar 2013 14:01:22 -0400
parents f3549c0a0eb6
children 29e79f1daae2
files agent/core/pom.xml agent/core/src/main/java/com/redhat/thermostat/backend/VmListenerBackend.java agent/core/src/main/java/com/redhat/thermostat/backend/VmUpdate.java agent/core/src/main/java/com/redhat/thermostat/backend/VmUpdateException.java agent/core/src/main/java/com/redhat/thermostat/backend/VmUpdateListener.java agent/core/src/main/java/com/redhat/thermostat/backend/internal/BackendException.java agent/core/src/main/java/com/redhat/thermostat/backend/internal/VmListenerWrapper.java agent/core/src/main/java/com/redhat/thermostat/backend/internal/VmMonitor.java agent/core/src/main/java/com/redhat/thermostat/backend/internal/VmUpdateImpl.java agent/core/src/test/java/com/redhat/thermostat/backend/VmListenerBackendTest.java agent/core/src/test/java/com/redhat/thermostat/backend/internal/VmListenerWrapperTest.java agent/core/src/test/java/com/redhat/thermostat/backend/internal/VmMonitorTest.java agent/core/src/test/java/com/redhat/thermostat/backend/internal/VmUpdateImplTest.java vm-classstat/agent/src/main/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatBackend.java vm-classstat/agent/src/main/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatDataExtractor.java vm-classstat/agent/src/main/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatVmListener.java vm-classstat/agent/src/test/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatBackendTest.java vm-classstat/agent/src/test/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatDataExtractorTest.java vm-classstat/agent/src/test/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatVmListenerTest.java vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackend.java vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcDataExtractor.java vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcVmListener.java vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackendTest.java vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcDataExtractorTest.java vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcVmListenerTest.java vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackend.java vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryDataExtractor.java vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryVmListener.java vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackendTest.java vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryDataExtractorTest.java vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryVmListenerTest.java
diffstat 31 files changed, 1258 insertions(+), 572 deletions(-) [+]
line wrap: on
line diff
--- a/agent/core/pom.xml	Thu Mar 14 14:37:34 2013 +0100
+++ b/agent/core/pom.xml	Fri Mar 15 14:01:22 2013 -0400
@@ -112,6 +112,9 @@
               com.redhat.thermostat.utils,
               com.redhat.thermostat.utils.management,
             </Export-Package>
+            <Private-Package>
+              com.redhat.thermostat.backend.internal,
+            </Private-Package>
             <!-- Do not autogenerate uses clauses in Manifests -->
             <_nouses>true</_nouses>
           </instructions>
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/VmListenerBackend.java	Thu Mar 14 14:37:34 2013 +0100
+++ b/agent/core/src/main/java/com/redhat/thermostat/backend/VmListenerBackend.java	Fri Mar 15 14:01:22 2013 -0400
@@ -36,27 +36,18 @@
 
 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.backend.internal.BackendException;
+import com.redhat.thermostat.backend.internal.VmMonitor;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 
 /**
  * This class is a convenient subclass of {@link Backend} (via {@link BaseBackend}) for those
- * that need to attach {@link VmListener} in response to starting and stopping of JVMs on a
+ * that need to attach {@link VmUpdateListener} in response to starting and stopping of JVMs on a
  * host.
  * 
  * @see VmStatusListener
@@ -66,10 +57,9 @@
 public abstract class VmListenerBackend extends BaseBackend 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 VmMonitor monitor;
     private boolean started;
 
     public VmListenerBackend(String backendName, String description,
@@ -80,14 +70,10 @@
             String vendor, String version, boolean observeNewJvm, VmStatusListenerRegistrar registrar) {
         super(backendName, description, vendor, version, observeNewJvm);
         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);
+            this.monitor = new VmMonitor();
+        } catch (BackendException e) {
+            logger.log(Level.SEVERE, "Unable to create backend", e);
         }
     }
     
@@ -95,13 +81,13 @@
      * {@inheritDoc}
      * 
      * <p>
-     * Registers a VmListener to begin receiving VM lifecycle events.
+     * Registers a VmUpdateListener 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) {
+        if (!started && monitor != null) {
             registrar.register(this);
             started = true;
         }
@@ -112,15 +98,15 @@
      * {@inheritDoc}
      * 
      * <p>
-     * Unregisters the VmListener to stop receiving VM lifecycle events.
+     * Unregisters the VmUpdateListener to stop receiving VM lifecycle events.
      * Subclasses should call <code>super.deactivate()</code> when overriding this method.
      * </p>
      */
     @Override
     public boolean deactivate() {
-        if (started) {
+        if (started && monitor != null) {
             registrar.unregister(this);
-            removeVmListeners();
+            monitor.removeVmListeners();
             started = false;
         }
         return !started;
@@ -136,84 +122,35 @@
         case VM_STARTED:
             /* fall-through */
         case VM_ACTIVE:
-            handleNewVm(pid);
+            if (getObserveNewJvm()) {
+                VmUpdateListener listener = createVmListener(pid);
+                monitor.handleNewVm(listener, pid);
+            } else {
+                logger.log(Level.FINE, "skipping new vm " + pid);
+            }
             break;
         case VM_STOPPED:
-            handleStoppedVm(pid);
+            monitor.handleStoppedVm(pid);
             break;
         default:
             break;
         }
     }
 
-    private void handleNewVm(int pid) {
-        if (getObserveNewJvm()) {
-            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
+     * Creates a new {@link VmUpdateListener} 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
+     * @return a new listener for the VM specified by pid
      */
-    protected abstract VmListener createVmListener(int pid);
+    protected abstract VmUpdateListener createVmListener(int pid);
     
     /*
      * For testing purposes only.
      */
-    void setHost(MonitoredHost host) {
-        this.host = host;
+    void setMonitor(VmMonitor monitor) {
+        this.monitor = monitor;
     }
-    
-    /*
-     * 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/main/java/com/redhat/thermostat/backend/VmUpdate.java	Fri Mar 15 14:01:22 2013 -0400
@@ -0,0 +1,68 @@
+/*
+ * 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;
+
+/**
+ * This interface can be used to query the performance counters
+ * of a monitored JVM when they are updated.
+ * @see VmUpdateListener#countersUpdated(VmUpdate)
+ */
+public interface VmUpdate {
+
+    /**
+     * Queries the specified JVM performance counter with a Long data type.
+     * @param name - The name of the performance counter
+     * @return The current value of the requested counter, or null if no
+     * such counter exists
+     * @throws VmUpdateException if there is a problem communicating with
+     * the JVM
+     * @throws ClassCastException if the value of the counter is not a Long
+     */
+    Long getPerformanceCounterLong(String name) throws VmUpdateException;
+    
+    /**
+     * Queries the specified JVM performance counter with a String data type.
+     * @param name - The name of the performance counter
+     * @return The current value of the requested counter, or null if no
+     * such counter exists
+     * @throws VmUpdateException if there is a problem communicating with
+     * the JVM
+     * @throws ClassCastException if the value of the counter is not a String
+     */
+    String getPerformanceCounterString(String name) throws VmUpdateException;
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/main/java/com/redhat/thermostat/backend/VmUpdateException.java	Fri Mar 15 14:01:22 2013 -0400
@@ -0,0 +1,75 @@
+/*
+ * 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;
+
+/**
+ * Exception class indicating that a problem occurred accessing
+ * a monitored JVM's performance counters.
+ */
+public class VmUpdateException extends Exception {
+
+    private static final long serialVersionUID = 7644805109896007513L;
+
+    /**
+     * Constructs a VmUpdateException with no message.
+     */
+    public VmUpdateException() {
+        super();
+    }
+    
+    /**
+     * Constructs a VmUpdateException with an error message.
+     */
+    public VmUpdateException(String msg) {
+        super(msg);
+    }
+    
+    /**
+     * Constructs a VmUpdateException with a cause.
+     */
+    public VmUpdateException(Throwable cause) {
+        super(cause);
+    }
+    
+    /**
+     * Constructs a VmUpdateException with an error message and cause.
+     */
+    public VmUpdateException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/main/java/com/redhat/thermostat/backend/VmUpdateListener.java	Fri Mar 15 14:01:22 2013 -0400
@@ -0,0 +1,53 @@
+/*
+ * 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;
+
+/**
+ * A listener that can be registered to receive updates for a
+ * JVM's performance counters.
+ * @see VmListenerBackend#createVmListener(int)
+ */
+public interface VmUpdateListener {
+    
+    /**
+     * This method is called when the performance counters
+     * are updated for the JVM this listener is attached to.
+     * @param update - object to query performance counter values
+     */
+    public void countersUpdated(VmUpdate update);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/main/java/com/redhat/thermostat/backend/internal/BackendException.java	Fri Mar 15 14:01:22 2013 -0400
@@ -0,0 +1,59 @@
+/*
+ * 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.internal;
+
+public class BackendException extends Exception {
+
+    private static final long serialVersionUID = 5575912008800705065L;
+
+    public BackendException() {
+        super();
+    }
+    
+    public BackendException(String msg) {
+        super(msg);
+    }
+    
+    public BackendException(Throwable cause) {
+        super(cause);
+    }
+    
+    public BackendException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/main/java/com/redhat/thermostat/backend/internal/VmListenerWrapper.java	Fri Mar 15 14:01:22 2013 -0400
@@ -0,0 +1,97 @@
+/*
+ * 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.internal;
+
+import sun.jvmstat.monitor.Monitor;
+import sun.jvmstat.monitor.MonitorException;
+import sun.jvmstat.monitor.MonitoredVm;
+import sun.jvmstat.monitor.event.MonitorStatusChangeEvent;
+import sun.jvmstat.monitor.event.VmEvent;
+import sun.jvmstat.monitor.event.VmListener;
+
+import com.redhat.thermostat.backend.VmUpdate;
+import com.redhat.thermostat.backend.VmUpdateException;
+import com.redhat.thermostat.backend.VmUpdateListener;
+
+public class VmListenerWrapper implements VmListener {
+    
+    private VmUpdateListener listener;
+    private MonitoredVm vm;
+    private VmUpdate update;
+
+    public VmListenerWrapper(VmUpdateListener listener, MonitoredVm vm) {
+        this.listener = listener;
+        this.vm = vm;
+        this.update = new VmUpdateImpl(this);
+    }
+
+    @Override
+    public void monitorsUpdated(VmEvent event) {
+        if (!vm.equals(event.getMonitoredVm())) {
+            throw new AssertionError("Received change event for wrong VM");
+        }
+        listener.countersUpdated(update);
+    }
+
+    @Override
+    public void monitorStatusChanged(MonitorStatusChangeEvent event) {
+        // Nothing to do here
+    }
+
+    @Override
+    public void disconnected(VmEvent event) {
+        // Nothing to do here
+    }
+    
+    public Monitor getMonitor(String name) throws VmUpdateException {
+        Monitor result;
+        try {
+            result = vm.findByName(name);
+        } catch (MonitorException e) {
+            throw new VmUpdateException("Error communicating with monitored VM", e);
+        }
+        return result;
+    }
+    
+    /*
+     * For testing purposes only.
+     */
+    VmUpdateListener getVmUpdateListener() {
+        return listener;
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/main/java/com/redhat/thermostat/backend/internal/VmMonitor.java	Fri Mar 15 14:01:22 2013 -0400
@@ -0,0 +1,129 @@
+/*
+ * 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.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 com.redhat.thermostat.backend.VmUpdateListener;
+import com.redhat.thermostat.common.Pair;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+
+public class VmMonitor {
+    
+    private final Logger logger = LoggingUtils.getLogger(VmMonitor.class);
+    private MonitoredHost host;
+    private Map<Integer, Pair<MonitoredVm, VmListenerWrapper>> pidToData = new HashMap<>();
+    
+    public VmMonitor() throws BackendException {
+        try {
+            HostIdentifier hostId = new HostIdentifier((String) null);
+            host = MonitoredHost.getMonitoredHost(hostId);
+        } catch (MonitorException me) {
+            throw new BackendException("Problems with connecting jvmstat to local machine", me);
+        } catch (URISyntaxException use) {
+            throw new BackendException("Failed to create host identifier", use);
+        }
+    }
+    
+    public void handleNewVm(VmUpdateListener listener, int pid) {
+        try {
+            MonitoredVm vm = host.getMonitoredVm(host.getHostIdentifier().resolve(new VmIdentifier(String.valueOf(pid))));
+            VmListenerWrapper wrapper = new VmListenerWrapper(listener, vm);
+            vm.addVmListener(wrapper);
+
+            pidToData.put(pid, new Pair<>(vm, wrapper));
+            logger.finer("Attached " + listener.getClass().getName() + " for VM: " + pid);
+        } catch (MonitorException | URISyntaxException e) {
+            logger.log(Level.WARNING, "unable to attach to vm " + pid, e);
+        }
+    }
+
+    public void handleStoppedVm(int pid) {
+        Pair<MonitoredVm, VmListenerWrapper> data = pidToData.remove(pid);
+        // we were not monitoring pid at all, so nothing to do
+        if (data == null) {
+            return;
+        }
+    
+        MonitoredVm vm = data.getFirst();
+        VmListenerWrapper listener = data.getSecond();
+        try {
+            vm.removeVmListener(listener);
+        } catch (MonitorException e) {
+            logger.log(Level.WARNING, "can't remove vm listener", e);
+        }
+        vm.detach();
+    }
+
+    public void removeVmListeners() {
+        for (Pair<MonitoredVm, VmListenerWrapper> data : pidToData.values()) {
+            MonitoredVm vm = data.getFirst();
+            VmListenerWrapper listener = data.getSecond();
+            try {
+                vm.removeVmListener(listener);
+            } catch (MonitorException e) {
+                logger.log(Level.WARNING, "can't remove vm listener", e);
+            }
+        }
+        pidToData.clear();
+    }
+    
+    /*
+     * For testing purposes only.
+     */
+    void setHost(MonitoredHost host) {
+        this.host = host;
+    }
+    
+    /*
+     * For testing purposes only.
+     */
+    Map<Integer, Pair<MonitoredVm, VmListenerWrapper>> getPidToDataMap() {
+        return pidToData;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/main/java/com/redhat/thermostat/backend/internal/VmUpdateImpl.java	Fri Mar 15 14:01:22 2013 -0400
@@ -0,0 +1,80 @@
+/*
+ * 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.internal;
+
+import sun.jvmstat.monitor.Monitor;
+
+import com.redhat.thermostat.backend.VmUpdate;
+import com.redhat.thermostat.backend.VmUpdateException;
+
+
+public class VmUpdateImpl implements VmUpdate {
+    
+    private VmListenerWrapper wrapper;
+
+    VmUpdateImpl(VmListenerWrapper wrapper) {
+        this.wrapper = wrapper;
+    }
+    
+    @Override
+    public Long getPerformanceCounterLong(String name) throws VmUpdateException {
+        return (Long) getPerformanceCounter(name);
+    }
+
+    @Override
+    public String getPerformanceCounterString(String name)
+            throws VmUpdateException {
+        return (String) getPerformanceCounter(name);
+    }
+    
+    private Object getPerformanceCounter(String name) throws VmUpdateException {
+        Object result = null;
+        Monitor monitor = wrapper.getMonitor(name);
+        if (monitor != null) {
+            result = monitor.getValue();
+        }
+        return result;
+    }
+
+    /*
+     * For testing purposes only.
+     */
+    VmListenerWrapper getWrapper() {
+        return wrapper;
+    }
+
+}
--- a/agent/core/src/test/java/com/redhat/thermostat/backend/VmListenerBackendTest.java	Thu Mar 14 14:37:34 2013 +0100
+++ b/agent/core/src/test/java/com/redhat/thermostat/backend/VmListenerBackendTest.java	Fri Mar 15 14:01:22 2013 -0400
@@ -38,61 +38,37 @@
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.doThrow;
+import static org.mockito.Matchers.same;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 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;
+import com.redhat.thermostat.backend.internal.VmMonitor;
 
 public class VmListenerBackendTest {
     
     private VmListenerBackend backend;
-    private HostIdentifier hostIdentifier;
-    private MonitoredHost host;
-    private MonitoredVm monitoredVm;
-    private VmListener listener;
     private VmStatusListenerRegistrar registrar;
+    private VmMonitor monitor;
+    private VmUpdateListener listener;
 
     @Before
-    public void setup() throws URISyntaxException, MonitorException {
+    public void setup() {
         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("Test Backend", "Backend for test", "Test Co.",
                 "0.0.0", registrar);
-        backend.setHost(host);
+        monitor = mock(VmMonitor.class);
+        listener = mock(VmUpdateListener.class);
+        backend.setMonitor(monitor);
     }
     
     @Test
@@ -112,8 +88,8 @@
     }
 
     @Test
-    public void testCanNotActivateWithoutMonitoredHost() {
-        backend.setHost(null);
+    public void testCanNotActivateWithoutMonitor() {
+        backend.setMonitor(null);
 
         assertFalse(backend.activate());
         assertFalse(backend.isActive());
@@ -137,94 +113,49 @@
     }
     
     @Test
-    public void testNewVM() throws MonitorException, URISyntaxException {
+    public void testNewVM() {
         final int VM_PID = 1;
-        VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID));
-        when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm);
 
         // Should be no response if not observing new jvm.
         backend.setObserveNewJvm(false);
-        backend.vmStatusChanged(Status.VM_STARTED, 1);
-        verify(monitoredVm, times(0)).addVmListener(any(VmListener.class));
+        backend.vmStatusChanged(Status.VM_STARTED, VM_PID);
+        verify(monitor, times(0)).handleNewVm(same(listener), same(VM_PID));
 
         backend.setObserveNewJvm(true);
-        backend.vmStatusChanged(Status.VM_STARTED, 1);
-        verify(monitoredVm).addVmListener(listener);
+        backend.vmStatusChanged(Status.VM_STARTED, VM_PID);
+        verify(monitor).handleNewVm(listener, VM_PID);
     }
 
     @Test
-    public void testAlreadyRunningVM() throws MonitorException, URISyntaxException {
+    public void testAlreadyRunningVM() {
         final int VM_PID = 1;
-        VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID));
-        when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm);
 
         backend.setObserveNewJvm(true);
-        backend.vmStatusChanged(Status.VM_ACTIVE, 1);
-
-        verify(monitoredVm).addVmListener(listener);
-    }
+        backend.vmStatusChanged(Status.VM_ACTIVE, VM_PID);
 
-    @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));
+        verify(monitor).handleNewVm(listener, VM_PID);
     }
 
     @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.setObserveNewJvm(true);
-        backend.vmStatusChanged(Status.VM_STARTED, 1);
-        backend.vmStatusChanged(Status.VM_STOPPED, 1);
+        backend.vmStatusChanged(Status.VM_STARTED, VM_PID);
+        backend.vmStatusChanged(Status.VM_STOPPED, VM_PID);
 
-        verify(monitoredVm).removeVmListener(listener);
+        verify(monitor).handleStoppedVm(VM_PID);
     }
 
     @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.setObserveNewJvm(true);
-        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.setObserveNewJvm(true);
-        backend.vmStatusChanged(Status.VM_STARTED, 1);
+        backend.vmStatusChanged(Status.VM_STARTED, VM_PID);
         backend.deactivate();
-        verify(monitoredVm).removeVmListener(listener);
+        verify(monitor).removeVmListeners();
     }
     
     private class TestBackend extends VmListenerBackend {
@@ -240,7 +171,7 @@
         }
 
         @Override
-        protected VmListener createVmListener(int pid) {
+        protected VmUpdateListener createVmListener(int pid) {
             return listener;
         }
         
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/test/java/com/redhat/thermostat/backend/internal/VmListenerWrapperTest.java	Fri Mar 15 14:01:22 2013 -0400
@@ -0,0 +1,122 @@
+/*
+ * 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.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import sun.jvmstat.monitor.Monitor;
+import sun.jvmstat.monitor.MonitorException;
+import sun.jvmstat.monitor.MonitoredVm;
+import sun.jvmstat.monitor.event.VmEvent;
+
+import com.redhat.thermostat.backend.VmUpdateException;
+import com.redhat.thermostat.backend.VmUpdateListener;
+
+public class VmListenerWrapperTest {
+
+    private VmListenerWrapper wrapper;
+    private MonitoredVm monitoredVm;
+    private VmUpdateListener listener;
+
+    @Before
+    public void setUp() throws Exception {
+        listener = mock(VmUpdateListener.class);
+        monitoredVm = mock(MonitoredVm.class);
+        wrapper = new VmListenerWrapper(listener, monitoredVm);
+    }
+
+    @Test
+    public void testMonitorsUpdated() {
+        VmEvent event = mock(VmEvent.class);
+        when(event.getMonitoredVm()).thenReturn(monitoredVm);
+        
+        wrapper.monitorsUpdated(event);
+        
+        ArgumentCaptor<VmUpdateImpl> captor = ArgumentCaptor.forClass(VmUpdateImpl.class);
+        verify(listener).countersUpdated(captor.capture());
+        VmUpdateImpl update = captor.getValue();
+        assertEquals(wrapper, update.getWrapper());
+    }
+    
+    @Test(expected=AssertionError.class)
+    public void testMonitorsUpdatedWrongVm() {
+        VmEvent event = mock(VmEvent.class);
+        MonitoredVm badVm = mock(MonitoredVm.class);
+        when(event.getMonitoredVm()).thenReturn(badVm);
+        
+        wrapper.monitorsUpdated(event);
+    }
+
+    @Test
+    public void testGetCounter() throws MonitorException, VmUpdateException {
+        final String counter = "myCounter";
+        
+        Monitor monitor = mock(Monitor.class);
+        when(monitoredVm.findByName(counter)).thenReturn(monitor);
+        
+        Monitor result = wrapper.getMonitor(counter);
+        assertEquals(monitor, result);
+    }
+    
+    @Test
+    public void testGetCounterNotFound() throws MonitorException, VmUpdateException {
+        final String counter = "myCounter";
+        
+        when(monitoredVm.findByName(counter)).thenReturn(null);
+        
+        Monitor result = wrapper.getMonitor(counter);
+        assertNull(result);
+    }
+    
+    @Test(expected=VmUpdateException.class)
+    public void testGetCounterError() throws MonitorException, VmUpdateException {
+        final String counter = "myCounter";
+        
+        when(monitoredVm.findByName(counter)).thenThrow(new MonitorException());
+        
+        wrapper.getMonitor(counter);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/test/java/com/redhat/thermostat/backend/internal/VmMonitorTest.java	Fri Mar 15 14:01:22 2013 -0400
@@ -0,0 +1,203 @@
+/*
+ * 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.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+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.backend.VmUpdateListener;
+
+public class VmMonitorTest {
+
+    private VmMonitor monitor;
+    private HostIdentifier hostIdentifier;
+    private MonitoredHost host;
+    private MonitoredVm monitoredVm;
+
+    @Before
+    public void setUp() throws Exception {
+        monitor = new VmMonitor();
+        
+        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);
+        monitor.setHost(host);
+    }
+
+    @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);
+
+        VmUpdateListener listener = mock(VmUpdateListener.class);
+        monitor.handleNewVm(listener, VM_PID);
+        
+        // Check listener registered
+        ArgumentCaptor<VmListenerWrapper> captor = ArgumentCaptor.forClass(VmListenerWrapper.class);
+        verify(monitoredVm).addVmListener(captor.capture());
+        VmListenerWrapper wrapper = captor.getValue();
+        assertEquals(listener, wrapper.getVmUpdateListener());
+        
+        // Check pid map
+        assertTrue(monitor.getPidToDataMap().containsKey(VM_PID));
+        assertEquals(wrapper, monitor.getPidToDataMap().get(VM_PID).getSecond());
+    }
+    
+    @Test
+    public void testStatVMGetMonitoredVmFails() throws MonitorException {
+        final int VM_PID = 1;
+        MonitorException monitorException = new MonitorException();
+        when(host.getMonitoredVm(isA(VmIdentifier.class))).thenThrow(monitorException);
+
+        VmUpdateListener listener = mock(VmUpdateListener.class);
+        monitor.handleNewVm(listener, VM_PID);
+
+        assertFalse(monitor.getPidToDataMap().containsKey(VM_PID));
+    }
+
+    @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);
+
+        VmUpdateListener listener = mock(VmUpdateListener.class);
+        
+        monitor.handleNewVm(listener, VM_PID);
+        monitor.handleStoppedVm(VM_PID);
+
+        // Check listener unregistered
+        ArgumentCaptor<VmListenerWrapper> captor = ArgumentCaptor.forClass(VmListenerWrapper.class);
+        verify(monitoredVm).removeVmListener(captor.capture());
+        VmListenerWrapper wrapper = captor.getValue();
+        assertEquals(listener, wrapper.getVmUpdateListener());
+        
+        assertFalse(monitor.getPidToDataMap().containsKey(VM_PID));
+    }
+
+    @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);
+
+        monitor.handleStoppedVm(VM_PID);
+
+        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(any(VmListener.class));
+
+        VmUpdateListener listener = mock(VmUpdateListener.class);
+        monitor.handleNewVm(listener, VM_PID);
+        monitor.handleStoppedVm(VM_PID);
+
+        verify(monitoredVm).detach();
+    }
+    
+    @Test
+    public void testRemoveAllListeners() throws URISyntaxException, MonitorException {
+        final int VM_PID1 = 1;
+        final int VM_PID2 = 2;
+        
+        VmIdentifier VM_ID1 = new VmIdentifier(String.valueOf(VM_PID1));
+        when(host.getMonitoredVm(VM_ID1)).thenReturn(monitoredVm);
+        
+        MonitoredVm monitoredVm2 = mock(MonitoredVm.class);
+        VmIdentifier VM_ID2 = new VmIdentifier(String.valueOf(VM_PID2));
+        when(host.getMonitoredVm(VM_ID2)).thenReturn(monitoredVm2);
+
+        VmUpdateListener listener1 = mock(VmUpdateListener.class);
+        VmUpdateListener listener2 = mock(VmUpdateListener.class);
+        monitor.handleNewVm(listener1, VM_PID1);
+        monitor.handleNewVm(listener2, VM_PID2);
+        
+        monitor.removeVmListeners();
+        
+        ArgumentCaptor<VmListenerWrapper> captor1 = ArgumentCaptor.forClass(VmListenerWrapper.class);
+        verify(monitoredVm).removeVmListener(captor1.capture());
+        VmListenerWrapper wrapper1 = captor1.getValue();
+        assertEquals(listener1, wrapper1.getVmUpdateListener());
+        
+        ArgumentCaptor<VmListenerWrapper> captor2 = ArgumentCaptor.forClass(VmListenerWrapper.class);
+        verify(monitoredVm2).removeVmListener(captor2.capture());
+        VmListenerWrapper wrapper2 = captor2.getValue();
+        assertEquals(listener2, wrapper2.getVmUpdateListener());
+        
+        assertEquals(0, monitor.getPidToDataMap().size());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/test/java/com/redhat/thermostat/backend/internal/VmUpdateImplTest.java	Fri Mar 15 14:01:22 2013 -0400
@@ -0,0 +1,124 @@
+/*
+ * 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.internal;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import sun.jvmstat.monitor.Monitor;
+
+import com.redhat.thermostat.backend.VmUpdateException;
+
+public class VmUpdateImplTest {
+
+    private VmUpdateImpl update;
+    private VmListenerWrapper wrapper;
+
+    @Before
+    public void setUp() throws Exception {
+        wrapper = mock(VmListenerWrapper.class);
+        update = new VmUpdateImpl(wrapper);
+    }
+
+    @Test
+    public void testGetPerformanceCounterLong() throws VmUpdateException {
+        final String counter = "myCounter";
+        final Long value = 9001L;
+        Monitor monitor = mock(Monitor.class);
+        when(monitor.getValue()).thenReturn(value);
+        when(wrapper.getMonitor(counter)).thenReturn(monitor);
+        
+        Long result = update.getPerformanceCounterLong(counter);
+        assertEquals(value, result);
+    }
+    
+    @Test(expected=ClassCastException.class)
+    public void testGetPerformanceCounterLongBadType() throws VmUpdateException {
+        final String counter = "myCounter";
+        final String value = "myValue";
+        Monitor monitor = mock(Monitor.class);
+        when(monitor.getValue()).thenReturn(value);
+        when(wrapper.getMonitor(counter)).thenReturn(monitor);
+        
+        update.getPerformanceCounterLong(counter);
+    }
+    
+    @Test
+    public void testGetPerformanceCounterLongNoCounter() throws VmUpdateException {
+        final String counter = "myCounter";
+        when(wrapper.getMonitor(counter)).thenReturn(null);
+        
+        Long result = update.getPerformanceCounterLong(counter);
+        assertNull(result);
+    }
+
+    @Test
+    public void testGetPerformanceCounterString() throws VmUpdateException {
+        final String counter = "myCounter";
+        final String value = "myValue";
+        Monitor monitor = mock(Monitor.class);
+        when(monitor.getValue()).thenReturn(value);
+        when(wrapper.getMonitor(counter)).thenReturn(monitor);
+        
+        String result = update.getPerformanceCounterString(counter);
+        assertEquals(value, result);
+    }
+    
+    @Test(expected=ClassCastException.class)
+    public void testGetPerformanceCounterStringBadType() throws VmUpdateException {
+        final String counter = "myCounter";
+        final Long value = 9001L;
+        Monitor monitor = mock(Monitor.class);
+        when(monitor.getValue()).thenReturn(value);
+        when(wrapper.getMonitor(counter)).thenReturn(monitor);
+        
+        update.getPerformanceCounterString(counter);
+    }
+    
+    @Test
+    public void testGetPerformanceCounterStringNoCounter() throws VmUpdateException {
+        final String counter = "myCounter";
+        when(wrapper.getMonitor(counter)).thenReturn(null);
+        
+        String result = update.getPerformanceCounterString(counter);
+        assertNull(result);
+    }
+
+}
--- a/vm-classstat/agent/src/main/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatBackend.java	Thu Mar 14 14:37:34 2013 +0100
+++ b/vm-classstat/agent/src/main/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatBackend.java	Fri Mar 15 14:01:22 2013 -0400
@@ -36,10 +36,9 @@
 
 package com.redhat.thermostat.vm.classstat.agent.internal;
 
-import sun.jvmstat.monitor.event.VmListener;
-
 import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
 import com.redhat.thermostat.backend.VmListenerBackend;
+import com.redhat.thermostat.backend.VmUpdateListener;
 import com.redhat.thermostat.common.Version;
 import com.redhat.thermostat.vm.classstat.common.VmClassStatDAO;
 
@@ -60,7 +59,7 @@
     }
 
     @Override
-    protected VmListener createVmListener(int pid) {
+    protected VmUpdateListener createVmListener(int pid) {
         return new VmClassStatVmListener(vmClassStats, pid);
     }
 
--- a/vm-classstat/agent/src/main/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatDataExtractor.java	Thu Mar 14 14:37:34 2013 +0100
+++ b/vm-classstat/agent/src/main/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatDataExtractor.java	Fri Mar 15 14:01:22 2013 -0400
@@ -36,8 +36,8 @@
 
 package com.redhat.thermostat.vm.classstat.agent.internal;
 
-import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredVm;
+import com.redhat.thermostat.backend.VmUpdate;
+import com.redhat.thermostat.backend.VmUpdateException;
 
 /**
  * A helper class to provide type-safe access to commonly used jvmstat monitors
@@ -59,14 +59,14 @@
      * http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#intern()
      */
 
-    private final MonitoredVm vm;
+    private final VmUpdate update;
 
-    public VmClassStatDataExtractor(MonitoredVm vm) {
-        this.vm = vm;
+    public VmClassStatDataExtractor(VmUpdate update) {
+        this.update = update;
     }
 
-    public long getLoadedClasses() throws MonitorException {
-        return (Long) vm.findByName("java.cls.loadedClasses").getValue();
+    public long getLoadedClasses() throws VmUpdateException {
+        return update.getPerformanceCounterLong("java.cls.loadedClasses");
     }
 
 }
--- a/vm-classstat/agent/src/main/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatVmListener.java	Thu Mar 14 14:37:34 2013 +0100
+++ b/vm-classstat/agent/src/main/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatVmListener.java	Fri Mar 15 14:01:22 2013 -0400
@@ -39,18 +39,15 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredVm;
-import sun.jvmstat.monitor.event.MonitorStatusChangeEvent;
-import sun.jvmstat.monitor.event.VmEvent;
-import sun.jvmstat.monitor.event.VmListener;
-
+import com.redhat.thermostat.backend.VmUpdate;
+import com.redhat.thermostat.backend.VmUpdateException;
+import com.redhat.thermostat.backend.VmUpdateListener;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.vm.classstat.common.VmClassStatDAO;
 import com.redhat.thermostat.vm.classstat.common.model.VmClassStat;
 
-class VmClassStatVmListener implements VmListener {
-
+class VmClassStatVmListener implements VmUpdateListener {
+    
     private static final Logger logger = LoggingUtils.getLogger(VmClassStatVmListener.class);
 
     private VmClassStatDAO dao;
@@ -62,29 +59,16 @@
     }
 
     @Override
-    public void disconnected(VmEvent vmEvent) {
-        /* nothing to do here */
-    }
-
-    @Override
-    public void monitorStatusChanged(MonitorStatusChangeEvent vmEvent) {
-        /* nothing to do here */
-    }
-
-    @Override
-    public void monitorsUpdated(VmEvent vmEvent) {
-        MonitoredVm vm = vmEvent.getMonitoredVm();
+    public void countersUpdated(VmUpdate update) {
+        VmClassStatDataExtractor extractor = new VmClassStatDataExtractor(update);
         try {
-            VmClassStatDataExtractor extractor = new VmClassStatDataExtractor(vm);
             long loadedClasses = extractor.getLoadedClasses();
             long timestamp = System.currentTimeMillis();
             VmClassStat stat = new VmClassStat(vmId, timestamp, loadedClasses);
             dao.putVmClassStat(stat);
-        } catch (MonitorException e) {
+        } catch (VmUpdateException e) {
             logger.log(Level.WARNING, "error gathering class info for vm " + vmId, e);
         }
-
-
     }
 
 }
--- a/vm-classstat/agent/src/test/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatBackendTest.java	Thu Mar 14 14:37:34 2013 +0100
+++ b/vm-classstat/agent/src/test/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatBackendTest.java	Fri Mar 15 14:01:22 2013 -0400
@@ -40,13 +40,9 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import java.net.URISyntaxException;
-
 import org.junit.Before;
 import org.junit.Test;
 
-import sun.jvmstat.monitor.MonitorException;
-
 import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
 import com.redhat.thermostat.common.Ordered;
 import com.redhat.thermostat.common.Version;
@@ -57,7 +53,7 @@
     private VmClassStatBackend backend;
 
     @Before
-    public void setup() throws MonitorException, URISyntaxException {
+    public void setup() {
         VmClassStatDAO vmClassStatDao = mock(VmClassStatDAO.class);
         
         Version version = mock(Version.class);
--- a/vm-classstat/agent/src/test/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatDataExtractorTest.java	Thu Mar 14 14:37:34 2013 +0100
+++ b/vm-classstat/agent/src/test/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatDataExtractorTest.java	Fri Mar 15 14:01:22 2013 -0400
@@ -39,36 +39,26 @@
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import org.junit.Test;
 
-import sun.jvmstat.monitor.LongMonitor;
-import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredVm;
+import com.redhat.thermostat.backend.VmUpdate;
+import com.redhat.thermostat.backend.VmUpdateException;
 
 public class VmClassStatDataExtractorTest {
 
-    private MonitoredVm buildLongMonitoredVm(String monitorName, Long monitorReturn) throws MonitorException {
-        final LongMonitor monitor = mock(LongMonitor.class);
-        when(monitor.longValue()).thenReturn(monitorReturn);
-        when(monitor.getValue()).thenReturn(monitorReturn);
-        MonitoredVm vm = mock(MonitoredVm.class);
-        when(vm.findByName(monitorName)).thenReturn(monitor);
-        return vm;
-    }
-
     @Test
-    public void testLoadedClasses() throws MonitorException {
+    public void testLoadedClasses() throws VmUpdateException {
         final String MONITOR_NAME = "java.cls.loadedClasses";
         final Long LOADED_CLASSES = 99l;
-        MonitoredVm vm = buildLongMonitoredVm(MONITOR_NAME, LOADED_CLASSES);
+        
+        VmUpdate update = mock(VmUpdate.class);
+        when(update.getPerformanceCounterLong(eq(MONITOR_NAME))).thenReturn(LOADED_CLASSES);
 
-        VmClassStatDataExtractor extractor = new VmClassStatDataExtractor(vm);
+        VmClassStatDataExtractor extractor = new VmClassStatDataExtractor(update);
         Long returned = extractor.getLoadedClasses();
-
-        verify(vm).findByName(eq(MONITOR_NAME));
+        
         assertEquals(LOADED_CLASSES, returned);
     }
 
--- a/vm-classstat/agent/src/test/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatVmListenerTest.java	Thu Mar 14 14:37:34 2013 +0100
+++ b/vm-classstat/agent/src/test/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatVmListenerTest.java	Fri Mar 15 14:01:22 2013 -0400
@@ -38,6 +38,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -47,13 +48,8 @@
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 
-import sun.jvmstat.monitor.Monitor;
-import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredVm;
-import sun.jvmstat.monitor.event.MonitorStatusChangeEvent;
-import sun.jvmstat.monitor.event.VmEvent;
-
-import com.redhat.thermostat.vm.classstat.agent.internal.VmClassStatVmListener;
+import com.redhat.thermostat.backend.VmUpdate;
+import com.redhat.thermostat.backend.VmUpdateException;
 import com.redhat.thermostat.vm.classstat.common.VmClassStatDAO;
 import com.redhat.thermostat.vm.classstat.common.model.VmClassStat;
 
@@ -72,33 +68,11 @@
     }
 
     @Test
-    public void testDisconnected() {
-        VmEvent vmEvent = mock(VmEvent.class);
-
-        listener.disconnected(vmEvent);
-
-        verifyNoMoreInteractions(vmEvent, dao);
-    }
-
-    @Test
-    public void testMonitorStatusChanged() {
-        MonitorStatusChangeEvent statusChangeEvent = mock(MonitorStatusChangeEvent.class);
-
-        listener.monitorStatusChanged(statusChangeEvent);
+    public void testMonitorUpdatedClassStat() throws Exception {
+        VmUpdate update = mock(VmUpdate.class);
+        when(update.getPerformanceCounterLong(eq("java.cls.loadedClasses"))).thenReturn(LOADED_CLASSES);
 
-        verifyNoMoreInteractions(statusChangeEvent, dao);
-    }
-
-    @Test
-    public void testMonitorUpdatedClassStat() throws Exception {
-        VmEvent vmEvent = mock(VmEvent.class);
-        MonitoredVm monitoredVm = mock(MonitoredVm.class);
-        Monitor m = mock(Monitor.class);
-        when(m.getValue()).thenReturn(LOADED_CLASSES);
-        when(monitoredVm.findByName("java.cls.loadedClasses")).thenReturn(m);
-        when(vmEvent.getMonitoredVm()).thenReturn(monitoredVm);
-
-        listener.monitorsUpdated(vmEvent);
+        listener.countersUpdated(update);
 
         ArgumentCaptor<VmClassStat> arg = ArgumentCaptor.forClass(VmClassStat.class);
         verify(dao).putVmClassStat(arg.capture());
@@ -109,30 +83,21 @@
 
     @Test
     public void testMonitorUpdatedClassStatTwice() throws Exception {
-        VmEvent vmEvent = mock(VmEvent.class);
-        MonitoredVm monitoredVm = mock(MonitoredVm.class);
-        Monitor m = mock(Monitor.class);
-        when(m.getValue()).thenReturn(LOADED_CLASSES);
-        when(monitoredVm.findByName("java.cls.loadedClasses")).thenReturn(m);
-        when(vmEvent.getMonitoredVm()).thenReturn(monitoredVm);
+        VmUpdate update = mock(VmUpdate.class);
+        when(update.getPerformanceCounterLong(eq("java.cls.loadedClasses"))).thenReturn(LOADED_CLASSES);
 
-        listener.monitorsUpdated(vmEvent);
-        listener.monitorsUpdated(vmEvent);
+        listener.countersUpdated(update);
+        listener.countersUpdated(update);
 
         // This checks a bug where the Category threw an IllegalStateException because the DAO
         // created a new one on each call, thus violating the unique guarantee of Category.
     }
 
     @Test
-    public void testMonitorUpdateFails() throws MonitorException {
-        VmEvent vmEvent = mock(VmEvent.class);
-        MonitoredVm monitoredVm = mock(MonitoredVm.class);
-        MonitorException monitorException = new MonitorException();
-
-        when(monitoredVm.findByName(anyString())).thenThrow(monitorException);
-        when(vmEvent.getMonitoredVm()).thenReturn(monitoredVm);
-
-        listener.monitorsUpdated(vmEvent);
+    public void testMonitorUpdateFails() throws VmUpdateException {
+        VmUpdate update = mock(VmUpdate.class);
+        when(update.getPerformanceCounterLong(anyString())).thenThrow(new VmUpdateException());
+        listener.countersUpdated(update);
 
         verifyNoMoreInteractions(dao);
     }
--- a/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackend.java	Thu Mar 14 14:37:34 2013 +0100
+++ b/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackend.java	Fri Mar 15 14:01:22 2013 -0400
@@ -36,10 +36,9 @@
 
 package com.redhat.thermostat.vm.gc.agent.internal;
 
-import sun.jvmstat.monitor.event.VmListener;
-
 import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
 import com.redhat.thermostat.backend.VmListenerBackend;
+import com.redhat.thermostat.backend.VmUpdateListener;
 import com.redhat.thermostat.common.Version;
 import com.redhat.thermostat.vm.gc.common.VmGcStatDAO;
 
@@ -60,7 +59,7 @@
     }
 
     @Override
-    protected VmListener createVmListener(int pid) {
+    protected VmUpdateListener createVmListener(int pid) {
         return new VmGcVmListener(vmGcStats, pid);
     }
 
--- a/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcDataExtractor.java	Thu Mar 14 14:37:34 2013 +0100
+++ b/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcDataExtractor.java	Fri Mar 15 14:01:22 2013 -0400
@@ -36,8 +36,8 @@
 
 package com.redhat.thermostat.vm.gc.agent.internal;
 
-import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredVm;
+import com.redhat.thermostat.backend.VmUpdate;
+import com.redhat.thermostat.backend.VmUpdateException;
 
 /**
  * A helper class to provide type-safe access to commonly used jvmstat monitors
@@ -59,26 +59,26 @@
      * http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#intern()
      */
 
-    private final MonitoredVm vm;
+    private final VmUpdate update;
 
-    public VmGcDataExtractor(MonitoredVm vm) {
-        this.vm = vm;
+    public VmGcDataExtractor(VmUpdate update) {
+        this.update = update;
     }
 
-    public long getTotalCollectors() throws MonitorException {
-        return (Long) vm.findByName("sun.gc.policy.collectors").getValue();
+    public long getTotalCollectors() throws VmUpdateException {
+        return update.getPerformanceCounterLong("sun.gc.policy.collectors");
     }
 
-    public String getCollectorName(long collector) throws MonitorException {
-        return (String) vm.findByName("sun.gc.collector." + collector + ".name").getValue();
+    public String getCollectorName(long collector) throws VmUpdateException {
+        return update.getPerformanceCounterString("sun.gc.collector." + collector + ".name");
     }
 
-    public long getCollectorTime(long collector) throws MonitorException {
-        return (Long) vm.findByName("sun.gc.collector." + collector + ".time").getValue();
+    public long getCollectorTime(long collector) throws VmUpdateException {
+        return update.getPerformanceCounterLong("sun.gc.collector." + collector + ".time");
     }
 
-    public long getCollectorInvocations(long collector) throws MonitorException {
-        return (Long) vm.findByName("sun.gc.collector." + collector + ".invocations").getValue();
+    public long getCollectorInvocations(long collector) throws VmUpdateException {
+        return update.getPerformanceCounterLong("sun.gc.collector." + collector + ".invocations");
     }
 
 }
--- a/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcVmListener.java	Thu Mar 14 14:37:34 2013 +0100
+++ b/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcVmListener.java	Fri Mar 15 14:01:22 2013 -0400
@@ -39,18 +39,15 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredVm;
-import sun.jvmstat.monitor.event.MonitorStatusChangeEvent;
-import sun.jvmstat.monitor.event.VmEvent;
-import sun.jvmstat.monitor.event.VmListener;
-
+import com.redhat.thermostat.backend.VmUpdate;
+import com.redhat.thermostat.backend.VmUpdateException;
+import com.redhat.thermostat.backend.VmUpdateListener;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.vm.gc.common.VmGcStatDAO;
 import com.redhat.thermostat.vm.gc.common.model.VmGcStat;
 
-public class VmGcVmListener implements VmListener {
-
+public class VmGcVmListener implements VmUpdateListener {
+    
     private static final Logger logger = LoggingUtils.getLogger(VmGcVmListener.class);
 
     private final int vmId;
@@ -62,27 +59,12 @@
     }
 
     @Override
-    public void disconnected(VmEvent event) {
-        /* nothing to do here */
-    }
-
-    @Override
-    public void monitorStatusChanged(MonitorStatusChangeEvent event) {
-        /* nothing to do here */
+    public void countersUpdated(VmUpdate update) {
+        VmGcDataExtractor extractor = new VmGcDataExtractor(update);
+        recordGcStat(extractor);
     }
 
-    @Override
-    public void monitorsUpdated(VmEvent event) {
-        MonitoredVm vm = event.getMonitoredVm();
-        if (vm == null) {
-            throw new NullPointerException();
-        }
-        
-        VmGcDataExtractor extractor = new VmGcDataExtractor(vm);
-        recordGcStat(vm, extractor);
-    }
-
-    void recordGcStat(MonitoredVm vm, VmGcDataExtractor extractor) {
+    void recordGcStat(VmGcDataExtractor extractor) {
         try {
             long collectors = extractor.getTotalCollectors();
             for (int i = 0; i < collectors; i++) {
@@ -93,10 +75,9 @@
                         extractor.getCollectorTime(i));
                 gcDAO.putVmGcStat(stat);
             }
-        } catch (MonitorException e) {
+        } catch (VmUpdateException e) {
             logger.log(Level.WARNING, "error gathering gc info for vm " + vmId, e);
         }
-
     }
 
 }
--- a/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackendTest.java	Thu Mar 14 14:37:34 2013 +0100
+++ b/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackendTest.java	Fri Mar 15 14:01:22 2013 -0400
@@ -40,13 +40,9 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import java.net.URISyntaxException;
-
 import org.junit.Before;
 import org.junit.Test;
 
-import sun.jvmstat.monitor.MonitorException;
-
 import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
 import com.redhat.thermostat.common.Ordered;
 import com.redhat.thermostat.common.Version;
@@ -57,7 +53,7 @@
     private VmGcBackend backend;
 
     @Before
-    public void setup() throws MonitorException, URISyntaxException {
+    public void setup() {
         VmGcStatDAO vmGcStatDao = mock(VmGcStatDAO.class);
 
         Version version = mock(Version.class);
--- a/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcDataExtractorTest.java	Thu Mar 14 14:37:34 2013 +0100
+++ b/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcDataExtractorTest.java	Fri Mar 15 14:01:22 2013 -0400
@@ -39,85 +39,66 @@
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import org.junit.Before;
 import org.junit.Test;
 
-import sun.jvmstat.monitor.LongMonitor;
-import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredVm;
-import sun.jvmstat.monitor.StringMonitor;
+import com.redhat.thermostat.backend.VmUpdate;
+import com.redhat.thermostat.backend.VmUpdateException;
 
 public class VmGcDataExtractorTest {
 
-    private MonitoredVm buildStringMonitoredVm(String monitorName, String monitorReturn) throws MonitorException {
-        final StringMonitor monitor = mock(StringMonitor.class);
-        when(monitor.stringValue()).thenReturn(monitorReturn);
-        when(monitor.getValue()).thenReturn(monitorReturn);
-        MonitoredVm vm = mock(MonitoredVm.class);
-        when(vm.findByName(monitorName)).thenReturn(monitor);
-        return vm;
-    }
+    private VmGcDataExtractor extractor;
+    private VmUpdate update;
 
-    private MonitoredVm buildLongMonitoredVm(String monitorName, Long monitorReturn) throws MonitorException {
-        final LongMonitor monitor = mock(LongMonitor.class);
-        when(monitor.longValue()).thenReturn(monitorReturn);
-        when(monitor.getValue()).thenReturn(monitorReturn);
-        MonitoredVm vm = mock(MonitoredVm.class);
-        when(vm.findByName(monitorName)).thenReturn(monitor);
-        return vm;
+    @Before
+    public void setup() {
+        update = mock(VmUpdate.class);
+        extractor = new VmGcDataExtractor(update);
     }
-
+    
     @Test
-    public void testTotalCollectors() throws MonitorException {
+    public void testTotalCollectors() throws VmUpdateException {
         final String MONITOR_NAME = "sun.gc.policy.collectors";
         final Long MONITOR_VALUE = 9l;
-        MonitoredVm vm = buildLongMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
 
-        VmGcDataExtractor extractor = new VmGcDataExtractor(vm);
+        when(update.getPerformanceCounterLong(eq(MONITOR_NAME))).thenReturn(MONITOR_VALUE);
+        
         Long returned = extractor.getTotalCollectors();
-
-        verify(vm).findByName(eq(MONITOR_NAME));
         assertEquals(MONITOR_VALUE, returned);
     }
 
     @Test
-    public void testCollectorName() throws MonitorException {
+    public void testCollectorName() throws VmUpdateException {
         final String MONITOR_NAME = "sun.gc.collector.0.name";
         final String COLLECTOR_NAME = "SomeMemoryCollector";
-        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, COLLECTOR_NAME);
 
-        VmGcDataExtractor extractor = new VmGcDataExtractor(vm);
+        when(update.getPerformanceCounterString(eq(MONITOR_NAME))).thenReturn(COLLECTOR_NAME);
+
         String returned = extractor.getCollectorName(0);
-
-        verify(vm).findByName(eq(MONITOR_NAME));
         assertEquals(COLLECTOR_NAME, returned);
     }
 
     @Test
-    public void testCollectorTime() throws MonitorException {
+    public void testCollectorTime() throws VmUpdateException {
         final String MONITOR_NAME = "sun.gc.collector.0.time";
         final Long COLLECTOR_TIME = 99l;
-        MonitoredVm vm = buildLongMonitoredVm(MONITOR_NAME, COLLECTOR_TIME);
 
-        VmGcDataExtractor extractor = new VmGcDataExtractor(vm);
+        when(update.getPerformanceCounterLong(eq(MONITOR_NAME))).thenReturn(COLLECTOR_TIME);
+
         Long returned = extractor.getCollectorTime(0);
-
-        verify(vm).findByName(eq(MONITOR_NAME));
         assertEquals(COLLECTOR_TIME, returned);
     }
 
     @Test
-    public void testCollectorInvocations() throws MonitorException {
+    public void testCollectorInvocations() throws VmUpdateException {
         final String MONITOR_NAME = "sun.gc.collector.0.invocations";
         final Long COLLECTOR_INVOCATIONS = 99l;
-        MonitoredVm vm = buildLongMonitoredVm(MONITOR_NAME, COLLECTOR_INVOCATIONS);
 
-        VmGcDataExtractor extractor = new VmGcDataExtractor(vm);
+        when(update.getPerformanceCounterLong(eq(MONITOR_NAME))).thenReturn(COLLECTOR_INVOCATIONS);
+
         Long returned = extractor.getCollectorInvocations(0);
-
-        verify(vm).findByName(eq(MONITOR_NAME));
         assertEquals(COLLECTOR_INVOCATIONS, returned);
     }
 
--- a/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcVmListenerTest.java	Thu Mar 14 14:37:34 2013 +0100
+++ b/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcVmListenerTest.java	Fri Mar 15 14:01:22 2013 -0400
@@ -48,9 +48,7 @@
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 
-import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredVm;
-
+import com.redhat.thermostat.backend.VmUpdateException;
 import com.redhat.thermostat.vm.gc.common.VmGcStatDAO;
 import com.redhat.thermostat.vm.gc.common.model.VmGcStat;
 
@@ -60,17 +58,15 @@
     private static final Long[] GC_TIMES = new Long[] { 5000L, 10000L };
     
     private VmGcVmListener vmListener;
-    private MonitoredVm monitoredVm;
     private VmGcDataExtractor extractor;
     private VmGcStatDAO vmGcStatDAO;
     
     @Before
-    public void setup() throws MonitorException {
+    public void setup() throws VmUpdateException {
         final int numGCs = 2;
         vmGcStatDAO = mock(VmGcStatDAO.class);
         vmListener = new VmGcVmListener(vmGcStatDAO, 0);
         
-        monitoredVm = mock(MonitoredVm.class);
         extractor = mock(VmGcDataExtractor.class);
         
         for (int i = 0; i < numGCs; i++) {
@@ -82,22 +78,22 @@
         when(extractor.getTotalCollectors()).thenReturn((long) GC_NAMES.length);
     }
 
-    private void mockCollectorName(int gc) throws MonitorException {
+    private void mockCollectorName(int gc) throws VmUpdateException {
         when(extractor.getCollectorName(gc)).thenReturn(GC_NAMES[gc]);
     }
     
-    private void mockCollectorInvocations(int gc) throws MonitorException {
+    private void mockCollectorInvocations(int gc) throws VmUpdateException {
         when(extractor.getCollectorInvocations(gc)).thenReturn(GC_INVOCS[gc]);
     }
 
-    private void mockCollectorTime(int gc) throws MonitorException {
+    private void mockCollectorTime(int gc) throws VmUpdateException {
         when(extractor.getCollectorTime(gc)).thenReturn(GC_TIMES[gc]);
     }
     
     @Test
     public void testRecordMemoryStat() {
         final int numCollectors = GC_NAMES.length;
-        vmListener.recordGcStat(monitoredVm, extractor);
+        vmListener.recordGcStat(extractor);
         ArgumentCaptor<VmGcStat> captor = ArgumentCaptor.forClass(VmGcStat.class);
         verify(vmGcStatDAO, times(numCollectors)).putVmGcStat(captor.capture());
         List<VmGcStat> gcStats = captor.getAllValues();
--- a/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackend.java	Thu Mar 14 14:37:34 2013 +0100
+++ b/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackend.java	Fri Mar 15 14:01:22 2013 -0400
@@ -38,6 +38,7 @@
 
 import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
 import com.redhat.thermostat.backend.VmListenerBackend;
+import com.redhat.thermostat.backend.VmUpdateListener;
 import com.redhat.thermostat.common.Version;
 import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO;
 
@@ -58,7 +59,7 @@
     }
 
     @Override
-    protected VmMemoryVmListener createVmListener(int pid) {
+    protected VmUpdateListener createVmListener(int pid) {
         return new VmMemoryVmListener(vmMemoryStats, pid);
     }
     
--- a/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryDataExtractor.java	Thu Mar 14 14:37:34 2013 +0100
+++ b/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryDataExtractor.java	Fri Mar 15 14:01:22 2013 -0400
@@ -36,10 +36,8 @@
 
 package com.redhat.thermostat.vm.memory.agent.internal;
 
-import sun.jvmstat.monitor.Monitor;
-import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredVm;
-
+import com.redhat.thermostat.backend.VmUpdate;
+import com.redhat.thermostat.backend.VmUpdateException;
 import com.redhat.thermostat.vm.memory.common.model.VmMemoryStat.Generation;
 
 /**
@@ -62,56 +60,56 @@
      * http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#intern()
      */
 
-    private final MonitoredVm vm;
+    private final VmUpdate update;
 
-    public VmMemoryDataExtractor(MonitoredVm vm) {
-        this.vm = vm;
+    public VmMemoryDataExtractor(VmUpdate update) {
+        this.update = update;
     }
     
-    public long getTotalGcGenerations() throws MonitorException {
-        return (Long) vm.findByName("sun.gc.policy.generations").getValue();
+    public long getTotalGcGenerations() throws VmUpdateException {
+        return update.getPerformanceCounterLong("sun.gc.policy.generations");
     }
 
-    public String getGenerationName(long generation) throws MonitorException {
-        return (String) vm.findByName("sun.gc.generation." + generation + ".name").getValue();
+    public String getGenerationName(long generation) throws VmUpdateException {
+        return update.getPerformanceCounterString("sun.gc.generation." + generation + ".name");
     }
 
-    public long getGenerationCapacity(long generation) throws MonitorException {
-        return (Long) vm.findByName("sun.gc.generation." + generation + ".capacity").getValue();
+    public long getGenerationCapacity(long generation) throws VmUpdateException {
+        return update.getPerformanceCounterLong("sun.gc.generation." + generation + ".capacity");
     }
 
-    public long getGenerationMaxCapacity(long generation) throws MonitorException {
-        return (Long) vm.findByName("sun.gc.generation." + generation + ".maxCapacity").getValue();
+    public long getGenerationMaxCapacity(long generation) throws VmUpdateException {
+        return update.getPerformanceCounterLong("sun.gc.generation." + generation + ".maxCapacity");
     }
 
-    public String getGenerationCollector(long generation) throws MonitorException {
+    public String getGenerationCollector(long generation) throws VmUpdateException {
         // this is just re-implementing getCollectorName()
         // TODO check generation number and collector number are always associated
-        Monitor m = vm.findByName("sun.gc.collector." + generation + ".name");
-        if (m == null) {
-            return Generation.COLLECTOR_NONE;
+        String collector = update.getPerformanceCounterString("sun.gc.collector." + generation + ".name");
+        if (collector == null) {
+            collector = Generation.COLLECTOR_NONE;
         }
-        return (String) m.getValue();
+        return collector;
     }
 
-    public long getTotalSpaces(long generation) throws MonitorException {
-        return (Long) vm.findByName("sun.gc.generation." + generation + ".spaces").getValue();
+    public long getTotalSpaces(long generation) throws VmUpdateException {
+        return update.getPerformanceCounterLong("sun.gc.generation." + generation + ".spaces");
     }
 
-    public String getSpaceName(long generation, long space) throws MonitorException {
-        return (String) vm.findByName("sun.gc.generation." + generation + ".space." + space + ".name").getValue();
+    public String getSpaceName(long generation, long space) throws VmUpdateException {
+        return update.getPerformanceCounterString("sun.gc.generation." + generation + ".space." + space + ".name");
     }
 
-    public long getSpaceCapacity(long generation, long space) throws MonitorException {
-        return (Long) vm.findByName("sun.gc.generation." + generation + ".space." + space + ".capacity").getValue();
+    public long getSpaceCapacity(long generation, long space) throws VmUpdateException {
+        return update.getPerformanceCounterLong("sun.gc.generation." + generation + ".space." + space + ".capacity");
     }
 
-    public long getSpaceMaxCapacity(long generation, long space) throws MonitorException {
-        return (Long) vm.findByName("sun.gc.generation." + generation + ".space." + space + ".maxCapacity").getValue();
+    public long getSpaceMaxCapacity(long generation, long space) throws VmUpdateException {
+        return update.getPerformanceCounterLong("sun.gc.generation." + generation + ".space." + space + ".maxCapacity");
     }
 
-    public long getSpaceUsed(long generation, long space) throws MonitorException {
-        return (Long) vm.findByName("sun.gc.generation." + generation + ".space." + space + ".used").getValue();
+    public long getSpaceUsed(long generation, long space) throws VmUpdateException {
+        return update.getPerformanceCounterLong("sun.gc.generation." + generation + ".space." + space + ".used");
     }
 
 }
--- a/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryVmListener.java	Thu Mar 14 14:37:34 2013 +0100
+++ b/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryVmListener.java	Fri Mar 15 14:01:22 2013 -0400
@@ -39,20 +39,17 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredVm;
-import sun.jvmstat.monitor.event.MonitorStatusChangeEvent;
-import sun.jvmstat.monitor.event.VmEvent;
-import sun.jvmstat.monitor.event.VmListener;
-
+import com.redhat.thermostat.backend.VmUpdate;
+import com.redhat.thermostat.backend.VmUpdateException;
+import com.redhat.thermostat.backend.VmUpdateListener;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO;
 import com.redhat.thermostat.vm.memory.common.model.VmMemoryStat;
 import com.redhat.thermostat.vm.memory.common.model.VmMemoryStat.Generation;
 import com.redhat.thermostat.vm.memory.common.model.VmMemoryStat.Space;
 
-public class VmMemoryVmListener implements VmListener {
-
+public class VmMemoryVmListener implements VmUpdateListener {
+    
     private static final Logger logger = LoggingUtils.getLogger(VmMemoryVmListener.class);
 
     private final int vmId;
@@ -64,20 +61,8 @@
     }
 
     @Override
-    public void disconnected(VmEvent event) {
-        /* nothing to do here */
-    }
-
-    @Override
-    public void monitorStatusChanged(MonitorStatusChangeEvent event) {
-        /* nothing to do here */
-    }
-
-    @Override
-    public void monitorsUpdated(VmEvent event) {
-        MonitoredVm vm = event.getMonitoredVm();
-
-        VmMemoryDataExtractor extractor = new VmMemoryDataExtractor(vm);
+    public void countersUpdated(VmUpdate update) {
+        VmMemoryDataExtractor extractor = new VmMemoryDataExtractor(update);
         recordMemoryStat(extractor);
     }
 
@@ -108,7 +93,7 @@
             }
             VmMemoryStat stat = new VmMemoryStat(timestamp, vmId, generations);
             memDAO.putVmMemoryStat(stat);
-        } catch (MonitorException e) {
+        } catch (VmUpdateException e) {
             logger.log(Level.WARNING, "error gathering memory info for vm " + vmId, e);
         }
     }
--- a/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackendTest.java	Thu Mar 14 14:37:34 2013 +0100
+++ b/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackendTest.java	Fri Mar 15 14:01:22 2013 -0400
@@ -40,13 +40,9 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import java.net.URISyntaxException;
-
 import org.junit.Before;
 import org.junit.Test;
 
-import sun.jvmstat.monitor.MonitorException;
-
 import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
 import com.redhat.thermostat.common.Ordered;
 import com.redhat.thermostat.common.Version;
@@ -57,7 +53,7 @@
     private VmMemoryBackend backend;
 
     @Before
-    public void setup() throws MonitorException, URISyntaxException {
+    public void setup() {
         VmMemoryStatDAO vmMemoryStatDao = mock(VmMemoryStatDAO.class);
         
         Version version = mock(Version.class);
--- a/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryDataExtractorTest.java	Thu Mar 14 14:37:34 2013 +0100
+++ b/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryDataExtractorTest.java	Fri Mar 15 14:01:22 2013 -0400
@@ -39,181 +39,144 @@
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import org.junit.Before;
 import org.junit.Test;
 
-import sun.jvmstat.monitor.LongMonitor;
-import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredVm;
-import sun.jvmstat.monitor.StringMonitor;
-
+import com.redhat.thermostat.backend.VmUpdate;
+import com.redhat.thermostat.backend.VmUpdateException;
 import com.redhat.thermostat.vm.memory.common.model.VmMemoryStat.Generation;
 
 public class VmMemoryDataExtractorTest {
 
-    private MonitoredVm buildStringMonitoredVm(String monitorName, String monitorReturn) throws MonitorException {
-        final StringMonitor monitor = mock(StringMonitor.class);
-        when(monitor.stringValue()).thenReturn(monitorReturn);
-        when(monitor.getValue()).thenReturn(monitorReturn);
-        MonitoredVm vm = mock(MonitoredVm.class);
-        when(vm.findByName(monitorName)).thenReturn(monitor);
-        return vm;
-    }
+    private VmUpdate update;
+    private VmMemoryDataExtractor extractor;
 
-    private MonitoredVm buildLongMonitoredVm(String monitorName, Long monitorReturn) throws MonitorException {
-        final LongMonitor monitor = mock(LongMonitor.class);
-        when(monitor.longValue()).thenReturn(monitorReturn);
-        when(monitor.getValue()).thenReturn(monitorReturn);
-        MonitoredVm vm = mock(MonitoredVm.class);
-        when(vm.findByName(monitorName)).thenReturn(monitor);
-        return vm;
+    @Before
+    public void setup() {
+        update = mock(VmUpdate.class);
+        extractor = new VmMemoryDataExtractor(update);
     }
-
+    
     @Test
-    public void testTotalGcGenerations() throws MonitorException {
+    public void testTotalGcGenerations() throws VmUpdateException {
         final String MONITOR_NAME = "sun.gc.policy.generations";
         final Long GC_GENERATIONS = 99l;
-        MonitoredVm vm = buildLongMonitoredVm(MONITOR_NAME, GC_GENERATIONS);
 
-        VmMemoryDataExtractor extractor = new VmMemoryDataExtractor(vm);
+        when(update.getPerformanceCounterLong(eq(MONITOR_NAME))).thenReturn(GC_GENERATIONS);
+        
         Long returned = extractor.getTotalGcGenerations();
-
-        verify(vm).findByName(eq(MONITOR_NAME));
         assertEquals(GC_GENERATIONS, returned);
     }
 
     @Test
-    public void testGenerationName() throws MonitorException {
+    public void testGenerationName() throws VmUpdateException {
         final String MONITOR_NAME = "sun.gc.generation.0.name";
         final String GENERATION_NAME = "Youth";
-        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, GENERATION_NAME);
 
-        VmMemoryDataExtractor extractor = new VmMemoryDataExtractor(vm);
+        when(update.getPerformanceCounterString(eq(MONITOR_NAME))).thenReturn(GENERATION_NAME);
+
         String returned = extractor.getGenerationName(0);
-
-        verify(vm).findByName(eq(MONITOR_NAME));
         assertEquals(GENERATION_NAME, returned);
     }
 
     @Test
-    public void testGenerationCapacity() throws MonitorException {
+    public void testGenerationCapacity() throws VmUpdateException {
         final String MONITOR_NAME = "sun.gc.generation.0.capacity";
         final Long GENERATION_CAPACITY = 99l;
-        MonitoredVm vm = buildLongMonitoredVm(MONITOR_NAME, GENERATION_CAPACITY);
 
-        VmMemoryDataExtractor extractor = new VmMemoryDataExtractor(vm);
+        when(update.getPerformanceCounterLong(eq(MONITOR_NAME))).thenReturn(GENERATION_CAPACITY);
+
         Long returned = extractor.getGenerationCapacity(0);
-
-        verify(vm).findByName(eq(MONITOR_NAME));
         assertEquals(GENERATION_CAPACITY, returned);
     }
 
     @Test
-    public void testGenerationMaxCapacity() throws MonitorException {
+    public void testGenerationMaxCapacity() throws VmUpdateException {
         final String MONITOR_NAME = "sun.gc.generation.0.maxCapacity";
         final Long GENERATION_MAX_CAPACITY = 99l;
-        MonitoredVm vm = buildLongMonitoredVm(MONITOR_NAME, GENERATION_MAX_CAPACITY);
-
 
-        VmMemoryDataExtractor extractor = new VmMemoryDataExtractor(vm);
+        when(update.getPerformanceCounterLong(eq(MONITOR_NAME))).thenReturn(GENERATION_MAX_CAPACITY);
+
         Long returned = extractor.getGenerationMaxCapacity(0);
-
-        verify(vm).findByName(eq(MONITOR_NAME));
         assertEquals(GENERATION_MAX_CAPACITY, returned);
     }
 
     @Test
-    public void testGenerationCollector() throws MonitorException {
+    public void testGenerationCollector() throws VmUpdateException {
         final String MONITOR_NAME = "sun.gc.collector.0.name";
         final String GENERATION_COLLECTOR = "generation collector";
-        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, GENERATION_COLLECTOR);
 
-        VmMemoryDataExtractor extractor = new VmMemoryDataExtractor(vm);
+        when(update.getPerformanceCounterString(eq(MONITOR_NAME))).thenReturn(GENERATION_COLLECTOR);
+
         String returned = extractor.getGenerationCollector(0);
-
-        verify(vm).findByName(eq(MONITOR_NAME));
         assertEquals(GENERATION_COLLECTOR, returned);
     }
 
     @Test
-    public void testGenerationCollectorNone() throws MonitorException {
+    public void testGenerationCollectorNone() throws VmUpdateException {
         final String MONITOR_NAME = "sun.gc.collector.0.name";
-        MonitoredVm vm = mock(MonitoredVm.class);
-        when(vm.findByName(MONITOR_NAME)).thenReturn(null);
 
-        VmMemoryDataExtractor extractor = new VmMemoryDataExtractor(vm);
+        when(update.getPerformanceCounterString(eq(MONITOR_NAME))).thenReturn(null);
+
         String returned = extractor.getGenerationCollector(0);
-
         assertEquals(Generation.COLLECTOR_NONE, returned);
     }
 
     @Test
-    public void testTotalSpaces() throws MonitorException {
+    public void testTotalSpaces() throws VmUpdateException {
+        final String MONITOR_NAME = "sun.gc.generation.0.spaces";
         final Long TOTAL_SPACES = 99l;
-        final LongMonitor monitor = mock(LongMonitor.class);
-        when(monitor.getValue()).thenReturn(TOTAL_SPACES);
-        MonitoredVm vm = mock(MonitoredVm.class);
-        when(vm.findByName("sun.gc.generation.0.spaces")).thenReturn(monitor);
 
-        VmMemoryDataExtractor extractor = new VmMemoryDataExtractor(vm);
+        when(update.getPerformanceCounterLong(eq(MONITOR_NAME))).thenReturn(TOTAL_SPACES);
+
         Long returned = extractor.getTotalSpaces(0);
-
-        verify(vm).findByName(eq("sun.gc.generation.0.spaces"));
         assertEquals(TOTAL_SPACES, returned);
     }
 
 
     @Test
-    public void testSpaceName() throws MonitorException {
+    public void testSpaceName() throws VmUpdateException {
         final String MONITOR_NAME = "sun.gc.generation.0.space.0.name";
         final String SPACE_NAME = "Hilbert";
-        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, SPACE_NAME);
 
-        VmMemoryDataExtractor extractor = new VmMemoryDataExtractor(vm);
+        when(update.getPerformanceCounterString(eq(MONITOR_NAME))).thenReturn(SPACE_NAME);
+
         String returned = extractor.getSpaceName(0,0);
-
-        verify(vm).findByName(eq(MONITOR_NAME));
         assertEquals(SPACE_NAME, returned);
     }
 
     @Test
-    public void testSpaceCapacity() throws MonitorException {
+    public void testSpaceCapacity() throws VmUpdateException {
         final String MONITOR_NAME = "sun.gc.generation.0.space.0.capacity";
         final Long SPACE_CAPACITY = 99l;
-        MonitoredVm vm = buildLongMonitoredVm(MONITOR_NAME, SPACE_CAPACITY);
 
-        VmMemoryDataExtractor extractor = new VmMemoryDataExtractor(vm);
+        when(update.getPerformanceCounterLong(eq(MONITOR_NAME))).thenReturn(SPACE_CAPACITY);
+
         Long returned = extractor.getSpaceCapacity(0,0);
-
-        verify(vm).findByName(eq(MONITOR_NAME));
         assertEquals(SPACE_CAPACITY, returned);
     }
 
     @Test
-    public void testSpaceMaxCapacity() throws MonitorException {
+    public void testSpaceMaxCapacity() throws VmUpdateException {
         final String MONITOR_NAME = "sun.gc.generation.0.space.0.maxCapacity";
         final Long SPACE_MAX_CAPACITY = 99l;
-        MonitoredVm vm = buildLongMonitoredVm(MONITOR_NAME, SPACE_MAX_CAPACITY);
 
-        VmMemoryDataExtractor extractor = new VmMemoryDataExtractor(vm);
+        when(update.getPerformanceCounterLong(eq(MONITOR_NAME))).thenReturn(SPACE_MAX_CAPACITY);
+
         Long returned = extractor.getSpaceMaxCapacity(0,0);
-
-        verify(vm).findByName(eq(MONITOR_NAME));
         assertEquals(SPACE_MAX_CAPACITY, returned);
     }
 
     @Test
-    public void testSpaceUsed() throws MonitorException {
+    public void testSpaceUsed() throws VmUpdateException {
         final String MONITOR_NAME = "sun.gc.generation.0.space.0.used";
         final Long SPACE_USED = 99l;
-        MonitoredVm vm = buildLongMonitoredVm(MONITOR_NAME, SPACE_USED);
 
-        VmMemoryDataExtractor extractor = new VmMemoryDataExtractor(vm);
+        when(update.getPerformanceCounterLong(eq(MONITOR_NAME))).thenReturn(SPACE_USED);
+
         Long returned = extractor.getSpaceUsed(0,0);
-
-        verify(vm).findByName(eq(MONITOR_NAME));
         assertEquals(SPACE_USED, returned);
     }
 
--- a/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryVmListenerTest.java	Thu Mar 14 14:37:34 2013 +0100
+++ b/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryVmListenerTest.java	Fri Mar 15 14:01:22 2013 -0400
@@ -37,7 +37,6 @@
 package com.redhat.thermostat.vm.memory.agent.internal;
 
 import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.isA;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -48,11 +47,8 @@
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 
-import sun.jvmstat.monitor.Monitor;
-import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredVm;
-import sun.jvmstat.monitor.event.VmEvent;
-
+import com.redhat.thermostat.backend.VmUpdate;
+import com.redhat.thermostat.backend.VmUpdateException;
 import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO;
 import com.redhat.thermostat.vm.memory.common.model.VmMemoryStat;
 import com.redhat.thermostat.vm.memory.common.model.VmMemoryStat.Generation;
@@ -84,14 +80,12 @@
     private VmMemoryVmListener vmListener;
     private VmMemoryDataExtractor extractor;
     private VmMemoryStatDAO vmMemoryStatDAO;
-    private MonitoredVm monitoredVm;
     
     @Before
-    public void setup() throws MonitorException {
+    public void setup() throws VmUpdateException {
         final int numGens = 2;
         vmMemoryStatDAO = mock(VmMemoryStatDAO.class);
         vmListener = new VmMemoryVmListener(vmMemoryStatDAO, 0);
-        monitoredVm = mock(MonitoredVm.class);
         extractor = mock(VmMemoryDataExtractor.class);
 
         mockTotalGenerations(numGens);
@@ -112,69 +106,50 @@
         }
     }
 
-    private void mockTotalGenerations(long gens) throws MonitorException {
+    private void mockTotalGenerations(long gens) throws VmUpdateException {
         when(extractor.getTotalGcGenerations()).thenReturn(gens);
     }
 
-    private void mockGenerationName(int gen) throws MonitorException {
+    private void mockGenerationName(int gen) throws VmUpdateException {
         when(extractor.getGenerationName(gen)).thenReturn(GEN_NAMES[gen]);
     }
     
-    private void mockGenerationCapacity(int gen) throws MonitorException {
+    private void mockGenerationCapacity(int gen) throws VmUpdateException {
         when(extractor.getGenerationCapacity(gen)).thenReturn(GEN_CAPS[gen]);
     }
 
-    private void mockGenerationMaxCapacity(int gen) throws MonitorException {
+    private void mockGenerationMaxCapacity(int gen) throws VmUpdateException {
         when(extractor.getGenerationMaxCapacity(gen)).thenReturn(GEN_MAX_CAPS[gen]);
     }
     
-    private void mockGenerationGC(int gen) throws MonitorException {
+    private void mockGenerationGC(int gen) throws VmUpdateException {
         when(extractor.getGenerationCollector(gen)).thenReturn(GEN_GCS[gen]);
     }
     
-    private void mockTotalSpaces(int gen) throws MonitorException {
+    private void mockTotalSpaces(int gen) throws VmUpdateException {
         when(extractor.getTotalSpaces(gen)).thenReturn(GEN_SPACES[gen]);
     }
     
-    private void mockSpaceName(int gen, int space) throws MonitorException {
+    private void mockSpaceName(int gen, int space) throws VmUpdateException {
         when(extractor.getSpaceName(gen, space)).thenReturn(SPACE_NAME[gen][space]);
     }
     
-    private void mockSpaceCapacity(int gen, int space) throws MonitorException {
+    private void mockSpaceCapacity(int gen, int space) throws VmUpdateException {
         when(extractor.getSpaceCapacity(gen, space)).thenReturn(SPACE_CAPS[gen][space]);
     }
     
-    private void mockSpaceMaxCapacity(int gen, int space) throws MonitorException {
+    private void mockSpaceMaxCapacity(int gen, int space) throws VmUpdateException {
         when(extractor.getSpaceMaxCapacity(gen, space)).thenReturn(SPACE_MAX_CAPS[gen][space]);
     }
     
-    private void mockSpaceUsed(int gen, int space) throws MonitorException {
+    private void mockSpaceUsed(int gen, int space) throws VmUpdateException {
         when(extractor.getSpaceUsed(gen, space)).thenReturn(SPACE_USED[gen][space]);
     }
 
     @Test
-    public void testDisconnectedIsNoOp() {
-        vmListener.disconnected(null);
-
-        verifyNoMoreInteractions(vmMemoryStatDAO, extractor);
-    }
-
-    @Test
-    public void testMonitorStatusChangeIsNoOp() {
-        vmListener.monitorStatusChanged(null);
-
-        verifyNoMoreInteractions(vmMemoryStatDAO, extractor);
-    }
-
-    @Test
-    public void testMonitorsUpdated() throws MonitorException {
-        Monitor monitor = mock(Monitor.class);
-        when(monitor.getValue()).thenReturn(Long.valueOf(0));
-        when(monitoredVm.findByName(anyString())).thenReturn(monitor);
-        VmEvent monitorUpdateEvent = mock(VmEvent.class);
-        when(monitorUpdateEvent.getMonitoredVm()).thenReturn(monitoredVm);
-
-        vmListener.monitorsUpdated(monitorUpdateEvent);
+    public void testMonitorsUpdated() throws VmUpdateException {
+        VmUpdate update = mock(VmUpdate.class);
+        vmListener.countersUpdated(update);
 
         verify(vmMemoryStatDAO).putVmMemoryStat(isA(VmMemoryStat.class));
     }
@@ -207,8 +182,8 @@
     }
 
     @Test
-    public void testRecordingMemoryInPresenseOfExtrationErrors() throws MonitorException {
-        when(extractor.getTotalGcGenerations()).thenThrow(new MonitorException());
+    public void testRecordingMemoryInPresenseOfExtrationErrors() throws VmUpdateException {
+        when(extractor.getTotalGcGenerations()).thenThrow(new VmUpdateException());
         vmListener.recordMemoryStat(extractor);
 
         verifyNoMoreInteractions(vmMemoryStatDAO);