changeset 2687:48e1cf54c238

Make JvmInfo into its own backend review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-May/023339.html reviewed-by: ebaron
author Mario Torre <neugens.limasoftware@gmail.com>
date Fri, 09 Jun 2017 16:38:44 +0200
parents 74a3254fdbdb
children 93da88c81d1d
files agent/core/src/main/java/com/redhat/thermostat/agent/VmBlacklist.java agent/core/src/main/java/com/redhat/thermostat/agent/VmStatusListener.java agent/core/src/main/java/com/redhat/thermostat/agent/VmStatusListenerRegistrar.java agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java agent/core/src/main/java/com/redhat/thermostat/agent/internal/VmBlacklistImpl.java agent/core/src/main/java/com/redhat/thermostat/backend/BackendException.java agent/core/src/main/java/com/redhat/thermostat/backend/BaseBackend.java agent/core/src/main/java/com/redhat/thermostat/backend/HostPollingBackend.java agent/core/src/main/java/com/redhat/thermostat/backend/PollingBackend.java agent/core/src/main/java/com/redhat/thermostat/backend/VmListenerBackend.java agent/core/src/main/java/com/redhat/thermostat/backend/VmPollingAction.java agent/core/src/main/java/com/redhat/thermostat/backend/VmPollingBackend.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/main/java/com/redhat/thermostat/utils/management/internal/AgentProxyFilter.java agent/core/src/test/java/com/redhat/thermostat/agent/VmStatusListenerRegistrarTest.java agent/core/src/test/java/com/redhat/thermostat/agent/internal/ActivatorTest.java agent/core/src/test/java/com/redhat/thermostat/backend/BaseBackendTest.java agent/core/src/test/java/com/redhat/thermostat/backend/PollingBackendTest.java agent/core/src/test/java/com/redhat/thermostat/backend/VmListenerBackendTest.java agent/core/src/test/java/com/redhat/thermostat/backend/VmPollingBackendTest.java agent/core/src/test/java/com/redhat/thermostat/backend/internal/TestLogHandler.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 distribution/assembly/plugin-assembly.xml distribution/pom.xml launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java plugins/jvm-overview/agent/pom.xml plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmBlacklist.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmListenerBackend.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmMonitor.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmPollingAction.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmPollingBackend.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmStatusListener.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmStatusListenerRegistrar.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmUpdate.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmUpdateException.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmUpdateListener.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/JvmStatDataExtractor.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/JvmStatHostListener.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/VMMonitorBackend.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/VmBlacklistImpl.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/VmListenerWrapper.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/VmStatusChangeNotifier.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/VmUpdateImpl.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/model/InfoBuilderFactory.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/model/InfoBuilderFactoryImpl.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/model/ProcessEnvironmentBuilder.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/model/ProcessEnvironmentBuilderImpl.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/model/VmInfoDAO.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/model/VmInfoDAOImpl.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/model/VmInfoTypeAdapter.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/model/HostsVMsLoader.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/model/VmId.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/model/VmInfo.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/model/VmLatestPojoListGetter.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/model/VmRef.java plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/model/VmTimeIntervalPojoListGetter.java plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/JvmStatDataExtractorTest.java plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/VmIdTest.java plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/VmListenerBackendTest.java plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/VmMonitorTest.java plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/VmPollingBackendTest.java plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/VmStatusListenerRegistrarTest.java plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/VmUpdateImplTest.java plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/JvmStatHostListenerTest.java plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/ProcessEnvironmentBuilderTest.java plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/TestLogHandler.java plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/VmListenerWrapperTest.java plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/VmStatusChangeNotifierTest.java plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/model/InfoBuilderFactoryTest.java plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/model/VmInfoDAOTest.java plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/model/VmInfoTypeAdapterTest.java plugins/jvm-overview/distribution/assemblies/plugin-assembly.xml plugins/jvm-overview/distribution/pom.xml plugins/jvm-overview/distribution/thermostat-plugin.xml plugins/jvm-overview/pom.xml plugins/pom.xml plugins/vm-gc/agent/pom.xml plugins/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackend.java plugins/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcDataExtractor.java plugins/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcVmListener.java plugins/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackendTest.java plugins/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcDataExtractorTest.java plugins/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcVmListenerTest.java plugins/vm-memory/agent/pom.xml plugins/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/Activator.java plugins/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackend.java plugins/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryDataExtractor.java plugins/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryVmListener.java plugins/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/ActivatorTest.java plugins/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackendTest.java plugins/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryDataExtractorTest.java plugins/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryVmListenerTest.java storage/core/src/main/java/com/redhat/thermostat/storage/core/HostsVMsLoader.java storage/core/src/main/java/com/redhat/thermostat/storage/core/VmBoundaryPojoGetter.java storage/core/src/main/java/com/redhat/thermostat/storage/core/VmId.java storage/core/src/main/java/com/redhat/thermostat/storage/core/VmLatestPojoListGetter.java storage/core/src/main/java/com/redhat/thermostat/storage/core/VmRef.java storage/core/src/main/java/com/redhat/thermostat/storage/core/VmTimeIntervalPojoListGetter.java storage/core/src/main/java/com/redhat/thermostat/storage/dao/VmInfoDAO.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/Activator.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/VmInfoTypeAdapter.java storage/core/src/main/java/com/redhat/thermostat/storage/model/VmInfo.java storage/core/src/test/java/com/redhat/thermostat/storage/core/VmIdTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/ActivatorTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/VmInfoTypeAdapterTest.java storage/core/src/test/java/com/redhat/thermostat/storage/model/PojoModelInstantiationTest.java system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/InfoBuilderFactoryImpl.java system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/JvmStatDataExtractor.java system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/JvmStatHostListener.java system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/ProcessEnvironmentBuilderImpl.java system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/SystemBackend.java system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/SystemBackendActivator.java system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/VmStatusChangeNotifier.java system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/models/InfoBuilderFactory.java system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/models/ProcessEnvironmentBuilder.java system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/InfoBuilderFactoryTest.java system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/JvmStatDataExtractorTest.java system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/JvmStatHostListenerTest.java system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/ProcessEnvironmentBuilderTest.java system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/SystemBackendTest.java system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/VmStatusChangeNotifierTest.java
diffstat 131 files changed, 6382 insertions(+), 5930 deletions(-) [+]
line wrap: on
line diff
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/VmBlacklist.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/*
- * Copyright 2012-2017 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.agent;
-
-import com.redhat.thermostat.common.Filter;
-
-/**
- * Maintains a list of JVM processes that Thermostat should not
- * monitor.
- */
-public interface VmBlacklist {
-    
-    /**
-     * Adds a {@link Filter} to the blacklist. Virtual machines whose
-     * main class match the filter will not be monitored.
-     * @param filter - a filter whose matching VMs should not be monitored
-     */
-    void addVmFilter(Filter<String> filter);
-    
-    /**
-     * Removes a {@link Filter} from the blacklist. New virtual machines
-     * will no longer be tested against this filter for blacklisting.
-     * @param filter - a filter previously in the blacklist
-     */
-    void removeVmFilter(Filter<String> filter);
-    
-    /**
-     * Returns whether the given virtual machine should be monitored
-     * by matching it against filters in the blacklist. If any filter
-     * matches, then this method will return true.
-     * @param mainClass - a class name to check against classes covered
-     *                    by this blacklist
-     * @return true if blacklisted, false otherwise
-     */
-    boolean isBlacklisted(String mainClass);
-
-}
-
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/VmStatusListener.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/*
- * Copyright 2012-2017 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.agent;
-
-import com.redhat.thermostat.annotations.ExtensionPoint;
-
-/**
- * A listener that is notified when a JVM starts or is stopped.
- * <p>
- * Register an instance of this class as an OSGi service, and it will be
- * notified of all VM {@link Status} events.
- */
-@ExtensionPoint
-public interface VmStatusListener {
-
-    enum Status {
-
-        /** A VM has just started now */
-        VM_STARTED,
-
-        /**
-         * A delayed version of {@link #VM_STARTED}. A VM was started at some
-         * point in the past. The listener was not informed about it then
-         * (probably because the listener was not registered at the time), but
-         * is being informed about it now.
-         */
-        VM_ACTIVE,
-
-        /** A VM was stopped just now */
-        VM_STOPPED,
-    }
-
-    // TODO what other information other than vmId and pid may be useful for plugins?
-
-    public void vmStatusChanged(Status newStatus, String vmId, int pid);
-
-}
-
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/VmStatusListenerRegistrar.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright 2012-2017 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.agent;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-
-/**
- * Registers a {@link VmStatusListener} as an OSGi Service.
- * <p>
- * This is just a convenience wrapper over
- * {@link BundleContext#registerService(String, Object, java.util.Dictionary)}.
- * It does absolutely nothing special.
- *
- * @see VmStatusListener
- */
-public class VmStatusListenerRegistrar {
-
-    private final BundleContext context;
-    private final Map<VmStatusListener, ServiceRegistration> registrations = new HashMap<>();
-
-    public VmStatusListenerRegistrar(BundleContext context) {
-        this.context = context;
-    }
-
-    public void register(VmStatusListener listener) {
-        registrations.put(listener, context.registerService(VmStatusListener.class.getName(), listener, null));
-    }
-
-    public void unregister(VmStatusListener listener) {
-        ServiceRegistration registration = registrations.remove(listener);
-        if (registration == null) {
-            throw new IllegalArgumentException("no listener found");
-        }
-
-        registration.unregister();
-    }
-}
-
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java	Fri Jun 09 16:38:44 2017 +0200
@@ -46,7 +46,6 @@
 import org.osgi.util.tracker.ServiceTracker;
 import org.osgi.util.tracker.ServiceTrackerCustomizer;
 
-import com.redhat.thermostat.agent.VmBlacklist;
 import com.redhat.thermostat.agent.config.AgentConfigsUtils;
 import com.redhat.thermostat.agent.ipc.server.AgentIPCService;
 import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool;
@@ -57,7 +56,7 @@
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.shared.config.InvalidConfigurationException;
-import com.redhat.thermostat.utils.management.internal.AgentProxyFilter;
+
 import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolControl;
 import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolImpl;
 
@@ -82,9 +81,9 @@
                 CommonPaths paths = context.getService(ref);
                 try {
                     AgentConfigsUtils.setConfigFiles(paths.getSystemAgentConfigurationFile(), paths.getUserAgentConfigurationFile());
-                    VmBlacklistImpl blacklist = new VmBlacklistImpl();
-                    blacklist.addVmFilter(new AgentProxyFilter());
-                    context.registerService(VmBlacklist.class, blacklist, null);
+//                    VmBlacklistImpl blacklist = new VmBlacklistImpl();
+//                    blacklist.addVmFilter(new AgentProxyFilter());
+//                    context.registerService(VmBlacklist.class, blacklist, null);
                 } catch (InvalidConfigurationException e) {
                     logger.log(Level.SEVERE, "Failed to start agent services", e);
                 }
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/internal/VmBlacklistImpl.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-/*
- * Copyright 2012-2017 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.agent.internal;
-
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-import com.redhat.thermostat.agent.VmBlacklist;
-import com.redhat.thermostat.common.Filter;
-
-public class VmBlacklistImpl implements VmBlacklist {
-    
-    private final List<Filter<String>> filters;
-    
-    public VmBlacklistImpl() {
-        this.filters = new CopyOnWriteArrayList<>();
-    }
-
-    @Override
-    public void addVmFilter(Filter<String> filter) {
-        filters.add(filter);
-    }
-
-    @Override
-    public void removeVmFilter(Filter<String> filter) {
-        filters.remove(filter);
-    }
-
-    @Override
-    public boolean isBlacklisted(String mainClass) {
-        boolean result = false;
-        for (Filter<String> filter : filters) {
-            if (filter.matches(mainClass)) {
-                result = true;
-            }
-        }
-        return result;
-    }
-
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/main/java/com/redhat/thermostat/backend/BackendException.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2012-2017 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;
+
+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);
+    }
+
+}
+
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/BaseBackend.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/agent/core/src/main/java/com/redhat/thermostat/backend/BaseBackend.java	Fri Jun 09 16:38:44 2017 +0200
@@ -45,13 +45,18 @@
     private String name, description, vendor, version;
 
     public BaseBackend(String name, String description, String vendor) {
-        this(name, description, vendor, false);
+        this(name, description, vendor, "0.1", false);
     }
 
-    public BaseBackend(String name, String description, String vendor, boolean observeNewJvm) {
+    public BaseBackend(String name, String description, String vendor, String version) {
+        this(name, description, vendor, version, false);
+    }
+
+    public BaseBackend(String name, String description, String vendor, String version, boolean observeNewJvm) {
         this.name = Objects.requireNonNull(name);
         this.description = Objects.requireNonNull(description);
         this.vendor = Objects.requireNonNull(vendor);
+        this.version = Objects.requireNonNull(version);
         this.observeNewJvm = observeNewJvm;
     }
 
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/HostPollingBackend.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/agent/core/src/main/java/com/redhat/thermostat/backend/HostPollingBackend.java	Fri Jun 09 16:38:44 2017 +0200
@@ -67,7 +67,7 @@
         badActions = new HashMap<>();
     }
 
-    final void doScheduledActions() {
+    final public void doScheduledActions() {
         for (HostPollingAction action : actions) {
             try {
                 action.run();
@@ -118,6 +118,6 @@
     }
 
     // Intentionally final do-nothing.
-    final void preActivate() {};
-    final void postDeactivate() {};
+    final public void preActivate() {};
+    final public void postDeactivate() {};
 }
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/PollingBackend.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/agent/core/src/main/java/com/redhat/thermostat/backend/PollingBackend.java	Fri Jun 09 16:38:44 2017 +0200
@@ -50,7 +50,7 @@
  * extend child classes {@link HostPollingBackend}
  * or {@link VmPollingBackend} as appropriate.
  */
-abstract class PollingBackend extends BaseBackend {
+public abstract class PollingBackend extends BaseBackend {
 
     private static final Logger logger = LoggingUtils.getLogger(PollingBackend.class);
     static final long DEFAULT_INTERVAL = 1000; // TODO make this configurable.
@@ -58,10 +58,10 @@
     private ScheduledExecutorService executor;
     private boolean isActive;
 
-    PollingBackend(String name, String description, String vendor,
+    public PollingBackend(String name, String description, String vendor,
             Version version,
             ScheduledExecutorService executor) {
-        super(name, description, vendor, true);
+        super(name, description, vendor, version.getVersionNumber(), true);
         this.executor = executor;
         setVersion(version.getVersionNumber());
     }
@@ -107,14 +107,14 @@
     }
 
     // Give child classes a chance to specify what should happen at each polling interval.
-    abstract void doScheduledActions();
+    protected abstract void doScheduledActions();
 
     // An opportunity for child classes to do some setup upon activation.
     // Will execute before any actions are scheduled.
-    void preActivate() {}
+    protected void preActivate() {}
 
     // An opportunity for child classes to do some cleanup upon deactivation.
     // Will execute after all actions are unscheduled.
-    void postDeactivate() {}
+    protected void postDeactivate() {}
 
 }
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/VmListenerBackend.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,187 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.backend;
-
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.redhat.thermostat.agent.VmStatusListener;
-import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
-import com.redhat.thermostat.backend.internal.BackendException;
-import com.redhat.thermostat.backend.internal.VmMonitor;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.core.WriterID;
-
-/**
- * This class is a convenient subclass of {@link Backend} (via {@link BaseBackend}) for those
- * that need to attach {@link VmUpdateListener} in response to starting and stopping of JVMs on a
- * host.
- * 
- * @see VmStatusListener
- * @see Backend
- * @see BaseBackend
- */
-public abstract class VmListenerBackend extends BaseBackend implements VmStatusListener {
-    
-    private static final Logger logger = LoggingUtils.getLogger(VmListenerBackend.class);
-    
-    private WriterID writerId;
-    private VmStatusListenerRegistrar registrar;
-    private VmMonitor monitor;
-    private boolean started;
-    private boolean initialized;
-
-    public VmListenerBackend(String backendName, String description, String vendor) {
-        this(backendName, description, vendor, false);
-    }
-    public VmListenerBackend(String backendName, String description,
-            String vendor, boolean observeNewJvm) {
-        super(backendName, description, vendor, observeNewJvm);
-        try {
-            this.monitor = new VmMonitor();
-        } catch (BackendException e) {
-            logger.log(Level.SEVERE, "Unable to create backend", e);
-        }
-    }
-    
-    /**
-     * {@inheritDoc}
-     * 
-     * <p>
-     * Registers a VmUpdateListener to begin receiving VM lifecycle events.
-     * Subclasses should call <code>super.activate()</code> when overriding this method.
-     * </p>
-     * <p>
-     * This {@link VmListenerBackend} should be initialized via 
-     * {@link #initialize(WriterID, VmStatusListenerRegistrar)} before calling this method.
-     * </p>
-     */
-    @Override
-    public boolean activate() {
-        if (!initialized) {
-            logger.warning("Backend not started, initialize must be called before activate");
-        } else if (!started && monitor != null) {
-            registrar.register(this);
-            started = true;
-        }
-        return started;
-    }
-    
-    /**
-     * {@inheritDoc}
-     * 
-     * <p>
-     * 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 && monitor != null) {
-            registrar.unregister(this);
-            monitor.removeVmListeners();
-            started = false;
-        }
-        return !started;
-    }
-    
-    @Override
-    public boolean isActive() {
-        return started;
-    }
-
-    public void vmStatusChanged(Status newStatus, String vmId, int pid) {
-        switch (newStatus) {
-        case VM_STARTED:
-            /* fall-through */
-        case VM_ACTIVE:
-            if (getObserveNewJvm()) {
-                String wId = writerId.getWriterID();
-                VmUpdateListener listener = null;
-                try {
-                    listener = createVmListener(wId, vmId, pid);
-                } catch (Throwable t) {
-                    logger.log(Level.INFO, "Creating the VM listener for a VmListenerBackend threw an exception. Going to ignore the backend!", t);
-                }
-                if (listener != null) {
-                    monitor.handleNewVm(listener, pid);
-                }
-            } else {
-                logger.log(Level.FINE, "skipping new vm " + pid);
-            }
-            break;
-        case VM_STOPPED:
-            monitor.handleStoppedVm(pid);
-            break;
-        default:
-            break;
-        }
-    }
-
-    /**
-     * Initializes this {@link VmListenerBackend} with necessary services. This method
-     * must be called before {@link #activate()}.
-     * @param writerId service uniquely identifying this agent
-     * @param registrar responsible for registering and unregistering instances of {@link VmStatusListener}
-     * @param version version number of this backend
-     */
-    protected void initialize(WriterID writerId, VmStatusListenerRegistrar registrar, String version) {
-        this.writerId = writerId;
-        this.registrar = registrar;
-        setVersion(version);
-        this.initialized = true;
-    }
-    
-    /**
-     * 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 vmId unique identifier of the JVM
-     * @param pid the process ID of the JVM
-     * @return a new listener for the VM specified by pid
-     */
-    protected abstract VmUpdateListener createVmListener(String writerId, String vmId, int pid);
-    
-    /*
-     * For testing purposes only.
-     */
-    void setMonitor(VmMonitor monitor) {
-        this.monitor = monitor;
-    }
-}
-
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/VmPollingAction.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * Copyright 2012-2017 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;
-
-/**
- * An action to be performed at a regular interval as part of a
- * {@link VmPollingBackend} implementation.
- */
-public interface VmPollingAction {
-
-    /**
-     * Run the action.
-     * 
-     * @param vmId a String representation of the VmID on which to take action.
-     * @param pid the process ID of the JVM instance on which to take action.
-     */
-    public void run(String vmId, int pid);
-
-}
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/VmPollingBackend.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,159 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.backend;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.redhat.thermostat.agent.VmStatusListener;
-import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
-import com.redhat.thermostat.common.Pair;
-import com.redhat.thermostat.common.Version;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-
-/**
- * Convenience {@link Backend} class for implementations that will take some
- * action for each monitored JVM process on a regular interval.  Simply
- * extend this class, implement any missing methods, and register one or
- * more {@link VmPollingAction} implementations during instantiation.
- */
-public abstract class VmPollingBackend extends PollingBackend implements VmStatusListener {
-
-    private final Set<VmPollingAction> actions;
-    private final Map<String, Pair<Integer, VmPollingAction>> badActions;
-    private final Map<Integer, String> pidsToMonitor = new ConcurrentHashMap<>();
-    private final VmStatusListenerRegistrar registrar;
-    private static final Logger logger = LoggingUtils.getLogger(VmPollingBackend.class);
-    private static final int EXCEPTIONS_THRESHOLD = 10;
-
-    public VmPollingBackend(String name, String description,
-            String vendor, Version version, ScheduledExecutorService executor,
-            VmStatusListenerRegistrar registrar) {
-        super(name, description, vendor, version, executor);
-        this.registrar = registrar;
-        this.actions = new CopyOnWriteArraySet<>();
-        this.badActions = new HashMap<>();
-    }
-
-    @Override
-    final void preActivate() {
-        registrar.register(this);
-    }
-
-    @Override
-    final void postDeactivate() {
-        registrar.unregister(this);
-    }
-
-    @Override
-    final void doScheduledActions() {
-        for (Entry<Integer, String> entry : pidsToMonitor.entrySet()) {
-            int pid = entry.getKey();
-            String vmId = entry.getValue();
-            for (VmPollingAction action : actions) {
-                try {
-                    action.run(vmId, pid);
-                } catch (Throwable t) {
-                    handleActionException(action, vmId);
-                }
-            }
-        }
-    }
-
-    private synchronized void handleActionException(VmPollingAction action, String vmId) {
-        final String actionName = action.getClass().getName();
-        final String actionKey = actionName + vmId;
-        Pair<Integer, VmPollingAction> actionPair = badActions.remove(actionKey);
-        if (actionPair == null) {
-            actionPair = new Pair<>(Integer.valueOf(1), action);
-        }
-        int exceptionsPerAction = actionPair.getFirst();
-        if (exceptionsPerAction < EXCEPTIONS_THRESHOLD) {
-            exceptionsPerAction++;
-            logger.info(VmPollingAction.class.getSimpleName() + " " +
-                    actionName + " threw an exception");
-            badActions.put(actionKey, new Pair<>(exceptionsPerAction, action));
-        } else {
-            logger.fine("Removing " + actionName + " due to too many repeated exceptions.");
-            unregisterAction(action);
-        }
-    }
-
-    /**
-     * Register an action to be performed at each polling interval.  It is
-     * recommended that implementations register all such actions during
-     * instantiation.
-     */
-    protected final void registerAction(VmPollingAction action) {
-        actions.add(action);
-    }
-
-    /**
-     * Unregister an action so that it will no longer be performed at each
-     * polling interval.  If no such action has been registered, this
-     * method has no effect.  Depending on thread timing issues, the action
-     * may be performed once even after this method has been called.
-     */
-    protected final void unregisterAction(VmPollingAction action) {
-        actions.remove(action);
-    }
-
-    @Override
-    public void vmStatusChanged(Status newStatus, String vmId, int pid) {
-        switch (newStatus) {
-        case VM_STARTED:
-            /* fall-through */
-        case VM_ACTIVE:
-            if (getObserveNewJvm()) {
-                pidsToMonitor.put(pid, vmId);
-            } else {
-                logger.log(Level.FINE, "skipping new vm " + pid);
-            }
-            break;
-        case VM_STOPPED:
-            pidsToMonitor.remove(pid);
-            break;
-        }
-    }
-}
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/VmUpdate.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * Copyright 2012-2017 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;
-    
-}
-
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/VmUpdateException.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright 2012-2017 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);
-    }
-
-}
-
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/VmUpdateListener.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * Copyright 2012-2017 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);
-
-}
-
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/internal/BackendException.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * Copyright 2012-2017 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);
-    }
-
-}
-
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/internal/VmListenerWrapper.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,126 +0,0 @@
-/*
- * Copyright 2012-2017 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.util.logging.Level;
-import java.util.logging.Logger;
-
-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 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;
-
-public class VmListenerWrapper implements VmListener {
-    
-    private static final Logger logger = LoggingUtils.getLogger(VmListenerWrapper.class);
-    // Threshold until this listener gets removed from the JVM in case of it throwing
-    // exceptions on countersUpdated()
-    private static final int EXCEPTION_THRESHOLD = 10;
-    private final VmUpdateListener listener;
-    private final MonitoredVm vm;
-    private final VmUpdate update;
-    private int exceptionCount;
-
-    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");
-        }
-        try {
-            listener.countersUpdated(update);
-        } catch (Throwable t) {
-            handleListenerException(t);
-        }
-    }
-    
-    private void handleListenerException(Throwable t) {
-        final String listenerName = listener.getClass().getName();
-        if (exceptionCount < EXCEPTION_THRESHOLD) {
-            logger.log(Level.INFO, "VM listener " + listenerName + " threw an exception", t);
-            exceptionCount++;
-        } else {
-            logger.fine("Removing bad listener " + listenerName + " due to too many repeated exceptions.");
-            try {
-                vm.removeVmListener(this);
-            } catch (MonitorException e) {
-                // ignore remove failures for bad listeners
-            }
-        }
-    }
-
-    @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;
-    }
-    
-}
-
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/internal/VmMonitor.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,149 +0,0 @@
-/*
- * Copyright 2012-2017 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.common.portability.ProcessChecker;
-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 final ProcessChecker processChecker;
-    private MonitoredHost host;
-    private Map<Integer, Pair<MonitoredVm, VmListenerWrapper>> pidToData = new HashMap<>();
-    
-    public VmMonitor() throws BackendException {
-        this(new ProcessChecker());
-    }
-
-    public VmMonitor(ProcessChecker processChecker) throws BackendException {
-        this.processChecker = processChecker;
-        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 e) {
-            logMsg(pid, e);
-        } catch (URISyntaxException e) {
-            logger.log(Level.WARNING, "unable to attach to vm " + pid, e);
-        }
-    }
-
-    private void logMsg(int pid, MonitorException e) {
-        Throwable cause = e.getCause();
-        if (cause != null && cause instanceof IllegalArgumentException && !processChecker.exists(pid)) {
-            logger.log(Level.FINEST, "Tried to attach to a process which no longer exists. Pid was " + pid, e);
-        } else {
-            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;
-    }
-
-}
-
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/internal/VmUpdateImpl.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-/*
- * Copyright 2012-2017 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/main/java/com/redhat/thermostat/utils/management/internal/AgentProxyFilter.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/AgentProxyFilter.java	Fri Jun 09 16:38:44 2017 +0200
@@ -37,11 +37,15 @@
 package com.redhat.thermostat.utils.management.internal;
 
 import com.redhat.thermostat.common.Filter;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
 
 /**
  * Prevents Agent Proxies from being monitored, which would create
  * an infinite chain of agent proxies being created.
  */
+@Component
+@Service(value = AgentProxyFilter.class)
 public class AgentProxyFilter extends Filter<String> {
     
     private static final String AGENT_PROXY_CLASS = "com.redhat.thermostat.agent.proxy.server.AgentProxy";
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/VmStatusListenerRegistrarTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-/*
- * Copyright 2012-2017 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.agent;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.agent.VmStatusListener;
-import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
-import com.redhat.thermostat.testutils.StubBundleContext;
-
-public class VmStatusListenerRegistrarTest {
-
-    @Test
-    public void testRegister() {
-        StubBundleContext context = new StubBundleContext();
-        VmStatusListener listener = mock(VmStatusListener.class);
-
-        VmStatusListenerRegistrar registerer = new VmStatusListenerRegistrar(context);
-        registerer.register(listener);
-
-        assertTrue(context.isServiceRegistered(VmStatusListener.class.getName(), listener.getClass()));
-        assertEquals(1, context.getAllServices().size());
-    }
-
-    @Test
-    public void testUnregister() {
-        StubBundleContext context = new StubBundleContext();
-        VmStatusListener listener = mock(VmStatusListener.class);
-
-        VmStatusListenerRegistrar registerer = new VmStatusListenerRegistrar(context);
-        registerer.register(listener);
-        registerer.unregister(listener);
-
-        assertFalse(context.isServiceRegistered(VmStatusListener.class.getName(), listener.getClass()));
-        assertEquals(0, context.getAllServices().size());
-    }
-}
-
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/internal/ActivatorTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/agent/core/src/test/java/com/redhat/thermostat/agent/internal/ActivatorTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -49,7 +49,6 @@
 import org.junit.Test;
 import org.osgi.framework.ServiceRegistration;
 
-import com.redhat.thermostat.agent.VmBlacklist;
 import com.redhat.thermostat.agent.ipc.server.AgentIPCService;
 import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool;
 import com.redhat.thermostat.shared.config.CommonPaths;
@@ -88,7 +87,6 @@
 
         assertTrue(context.isServiceRegistered(MXBeanConnectionPool.class.getName(), MXBeanConnectionPoolImpl.class));
         assertTrue(context.isServiceRegistered(MXBeanConnectionPoolControl.class.getName(), MXBeanConnectionPoolImpl.class));
-        assertTrue(context.isServiceRegistered(VmBlacklist.class.getName(), VmBlacklistImpl.class));
     }
 
     @Test
--- a/agent/core/src/test/java/com/redhat/thermostat/backend/BaseBackendTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/agent/core/src/test/java/com/redhat/thermostat/backend/BaseBackendTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -134,13 +134,13 @@
 
         public TestBaseBackend(String name, String description, String vendor,
                 String version) {
-            super(name, description, vendor);
+            super(name, description, vendor, "1.0");
             setVersion(version);
         }
 
         public TestBaseBackend(String name, String description, String vendor,
                 String version, boolean observeNewJvm) {
-            super(name, description, vendor, observeNewJvm);
+            super(name, description, vendor, "1.0", observeNewJvm);
             setVersion(version);
         }
 
--- a/agent/core/src/test/java/com/redhat/thermostat/backend/PollingBackendTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/agent/core/src/test/java/com/redhat/thermostat/backend/PollingBackendTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -74,17 +74,17 @@
             }
 
             @Override
-            void doScheduledActions() {
+            protected void doScheduledActions() {
                 // Won't be called because mock executor.
             }
 
             @Override
-            void preActivate() {
+            protected void preActivate() {
                 mockActivate.activate();
             }
 
             @Override
-            void postDeactivate() {
+            protected void postDeactivate() {
                 mockActivate.deactivate();
             }};
     }
@@ -140,7 +140,7 @@
             }
 
             @Override
-            void doScheduledActions() {
+            protected void doScheduledActions() {
                 mockAction.doAction();
             }};
         backend.activate();
@@ -156,11 +156,11 @@
     }
 
     private interface CustomActivateTester {
-        public void activate();
-        public void deactivate();
+        void activate();
+        void deactivate();
     }
 
     private interface ScheduledActionTester {
-        public void doAction();
+        void doAction();
     }
 }
--- a/agent/core/src/test/java/com/redhat/thermostat/backend/VmListenerBackendTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,231 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.backend;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.same;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import java.net.URISyntaxException;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import sun.jvmstat.monitor.MonitorException;
-
-import com.redhat.thermostat.agent.VmStatusListener.Status;
-import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
-import com.redhat.thermostat.backend.internal.VmMonitor;
-import com.redhat.thermostat.common.internal.test.Bug;
-import com.redhat.thermostat.storage.core.WriterID;
-
-public class VmListenerBackendTest {
-    private static final String VERSION = "0.0.0";
-    private static final String VM_ID = "vmId";
-    private static final int VM_PID = 1;
-    
-    private VmListenerBackend backend;
-    private VmStatusListenerRegistrar registrar;
-    private VmMonitor monitor;
-    private VmUpdateListener listener;
-    private WriterID writerId;
-
-    @Before
-    public void setup() {
-        registrar = mock(VmStatusListenerRegistrar.class);
-        writerId = mock(WriterID.class);
-        backend = new TestBackend("Test Backend", "Backend for test", "Test Co.");
-        monitor = mock(VmMonitor.class);
-        listener = mock(VmUpdateListener.class);
-        backend.setMonitor(monitor);
-    }
-    
-    @Test
-    public void testActivate() {
-        backend.initialize(writerId, registrar, VERSION);
-        backend.activate();
-        assertTrue(backend.isActive());
-        verify(registrar).register(backend);
-    }
-    
-    @Test
-    public void testActivateNoInit() {
-        backend.activate();
-        assertFalse(backend.isActive());
-        verify(registrar, never()).register(backend);
-    }
-
-    @Test
-    public void testActivateTwice() {
-        backend.initialize(writerId, registrar, VERSION);
-        assertTrue(backend.activate());
-        assertTrue(backend.isActive());
-
-        assertTrue(backend.activate());
-        assertTrue(backend.isActive());
-    }
-
-    @Test
-    public void testCanNotActivateWithoutMonitor() {
-        backend.initialize(writerId, registrar, VERSION);
-        backend.setMonitor(null);
-
-        assertFalse(backend.activate());
-        assertFalse(backend.isActive());
-    }
-    
-    @Test
-    public void testDeactivate() {
-        backend.initialize(writerId, registrar, VERSION);
-        backend.activate();
-        backend.deactivate();
-        verify(registrar).unregister(backend);
-        assertFalse(backend.isActive());
-    }
-
-    @Test
-    public void testDeactivateTwice() {
-        backend.initialize(writerId, registrar, VERSION);
-        backend.activate();
-
-        assertTrue(backend.deactivate());
-        assertFalse(backend.isActive());
-        assertTrue(backend.deactivate());
-    }
-    
-    @Test
-    public void testNewVM() {
-        backend.initialize(writerId, registrar, VERSION);
-        // Should be no response if not observing new jvm.
-        backend.setObserveNewJvm(false);
-        backend.vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID);
-        verify(monitor, times(0)).handleNewVm(same(listener), same(VM_PID));
-
-        backend.setObserveNewJvm(true);
-        backend.vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID);
-        verify(monitor).handleNewVm(listener, VM_PID);
-    }
-    
-    /**
-     * createVmListener() might be plugin-supplied code. When creating the
-     * listener fails due to exceptions, other listeners should still continue
-     * to work. That is, the exception of creating one listener must not be
-     * propagated.
-     */
-    @Bug(id = "3242",
-         summary = "Adverse Backend breaks other Backends badly ",
-         url = "http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=3242")
-    @Test
-    public void testNewVMCreateListenerWithExceptions() {
-        VmListenerBackend testBackend = new ExceptionThrowingCreateVmListenerBackend(
-                "Test Backend", "Backend for test", "Test Co.", VERSION);
-        testBackend.initialize(writerId, registrar, VERSION);
-        testBackend.setObserveNewJvm(true);
-        VmMonitor testMonitor = mock(VmMonitor.class);
-        testBackend.setMonitor(testMonitor);
-        testBackend.vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID);
-        verify(testMonitor, times(0)).handleNewVm(any(VmUpdateListener.class), any(int.class));
-    }
-
-    @Test
-    public void testAlreadyRunningVM() {
-        backend.initialize(writerId, registrar, VERSION);
-        backend.setObserveNewJvm(true);
-        backend.vmStatusChanged(Status.VM_ACTIVE, VM_ID, VM_PID);
-
-        verify(monitor).handleNewVm(listener, VM_PID);
-    }
-
-    @Test
-    public void testStoppedVM() throws MonitorException, URISyntaxException {
-        backend.initialize(writerId, registrar, VERSION);
-        backend.setObserveNewJvm(true);
-        backend.vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID);
-        backend.vmStatusChanged(Status.VM_STOPPED, VM_ID, VM_PID);
-
-        verify(monitor).handleStoppedVm(VM_PID);
-    }
-
-    @Test
-    public void testDeactivateUnregistersListener() throws URISyntaxException, MonitorException {
-        backend.initialize(writerId, registrar, VERSION);
-        backend.activate();
-        
-        backend.setObserveNewJvm(true);
-        backend.vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID);
-        backend.deactivate();
-        verify(monitor).removeVmListeners();
-    }
-    
-    private class TestBackend extends VmListenerBackend {
-
-        public TestBackend(String name, String description, String vendor) {
-            super(name, description, vendor);
-        }
-
-        @Override
-        public int getOrderValue() {
-            return 0;
-        }
-
-        @Override
-        protected VmUpdateListener createVmListener(String writerId, String vmId, int pid) {
-            return listener;
-        }
-        
-    }
-    
-    private class ExceptionThrowingCreateVmListenerBackend extends TestBackend {
-        
-        public ExceptionThrowingCreateVmListenerBackend(String name, String description, String vendor,
-                String version) {
-            super(name, description, vendor);
-        }
-        
-        @Override
-        protected VmUpdateListener createVmListener(String writerId, String vmId, int pid) {
-            throw new RuntimeException("createVmListener() testing!");
-        }
-    }
-
-}
-
--- a/agent/core/src/test/java/com/redhat/thermostat/backend/VmPollingBackendTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,275 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.backend;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ScheduledExecutorService;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.agent.VmStatusListener.Status;
-import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
-import com.redhat.thermostat.common.Version;
-import com.redhat.thermostat.common.internal.test.Bug;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class VmPollingBackendTest {
-
-    private VmPollingBackend backend;
-    private ScheduledExecutorService mockExecutor;
-    private VmStatusListenerRegistrar mockRegistrar;
-
-    @Before
-    public void setUp() {
-        mockExecutor = mock(ScheduledExecutorService.class);
-        Version mockVersion = mock(Version.class);
-        when(mockVersion.getVersionNumber()).thenReturn("backend-version");
-        mockRegistrar = mock(VmStatusListenerRegistrar.class);
-        backend = new VmPollingBackend("backend-name", "backend-description",
-                  "backend-vendor", mockVersion, mockExecutor, mockRegistrar) {
-                    @Override
-                    public int getOrderValue() {
-                        return 0; // Doesn't matter, not being tested.
-                    }
-        };
-        if (!backend.getObserveNewJvm()) {
-            /* At time of writing, default is true.  This is
-             * inherited from parent PollingBackend.  In case
-             * default changes:
-             */
-            backend.setObserveNewJvm(true);
-        }
-    }
-
-    /**
-     * If an action throws exceptions repeatedly, that action shall get
-     * disabled/unregistered.
-     */
-    @Bug(id = "3242",
-         summary = "Adverse Backend breaks other Backends badly ",
-         url = "http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=3242")
-    @Test
-    public void testDoScheduledActionsWithExceptions() {
-        final int beyondExceptionThreshold = 13; // anything beyond 10 will do
-        String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2";
-        int pid1 = 123, pid2 = 456;
-        backend.vmStatusChanged(Status.VM_ACTIVE, vmId1, pid1);
-        backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2);
-        BadVmPollingAction badAction = new BadVmPollingAction();
-        backend.registerAction(badAction);
-        for (int i = 0; i < beyondExceptionThreshold; i++) {
-            backend.doScheduledActions();
-        }
-    
-        // The exceptions thrown for one vmID might disable the action
-        // for *all* other vmIDs too. So the call count for one of the
-        // vmIDs is actually 9, whereas the other one must have reached
-        // the threshold count of 10.
-        int callCountVm1 = badAction.getCallCount(vmId1);
-        int callCountVm2 = badAction.getCallCount(vmId2);
-        int minCallCount = Math.min(callCountVm2, callCountVm1);
-        int maxCallCount = Math.max(callCountVm1, callCountVm2);
-        assertEquals("Must not be called beyond exception threshold",
-                10, maxCallCount);
-        assertEquals("Other action's exception cancels globally",
-                9, minCallCount);
-    }
-
-    @Test
-    public void verifyCustomActivateRegistersListener() {
-        backend.preActivate();
-        verify(mockRegistrar).register(backend);
-    }
-
-    @Test
-    public void verifyCustomDeactivateUnregistersListener() {
-        backend.postDeactivate();
-        verify(mockRegistrar).unregister(backend);
-    }
-    
-    @Test
-    public void verifyRegisteredActionPerformed() {
-        String vmId = "test-vm-id";
-        int pid = 123;
-        backend.vmStatusChanged(Status.VM_ACTIVE, vmId, pid);
-        VmPollingAction action = mock(VmPollingAction.class);
-        backend.registerAction(action);
-        backend.doScheduledActions();
-
-        verify(action).run(eq(vmId), eq(pid));
-    }
-
-    @Test
-    public void verifyMultipleRegisteredActionsPerformed() {
-        String vmId = "test-vm-id";
-        int pid = 123;
-        backend.vmStatusChanged(Status.VM_ACTIVE, vmId, pid);
-        VmPollingAction action1 = mock(VmPollingAction.class);
-        VmPollingAction action2 = mock(VmPollingAction.class);
-        backend.registerAction(action1);
-        backend.registerAction(action2);
-        backend.doScheduledActions();
-
-        verify(action1).run(eq(vmId), eq(pid));
-        verify(action2).run(eq(vmId), eq(pid));
-    }
-
-    @Test
-    public void verifyActionsPerformedOnMultipleVms() {
-        String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2";
-        int pid1 = 123, pid2 = 456;
-        backend.vmStatusChanged(Status.VM_ACTIVE, vmId1, pid1);
-        backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2);
-        VmPollingAction action = mock(VmPollingAction.class);
-        backend.registerAction(action);
-        backend.doScheduledActions();
-
-        verify(action).run(eq(vmId1), eq(pid1));
-        verify(action).run(eq(vmId2), eq(pid2));
-    }
-
-    @Test
-    public void verifyMultipleRegisteredActionsPerformedOnMultipleVms() {
-        String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2";
-        int pid1 = 123, pid2 = 456;
-        backend.vmStatusChanged(Status.VM_ACTIVE, vmId1, pid1);
-        backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2);
-        VmPollingAction action1 = mock(VmPollingAction.class);
-        VmPollingAction action2 = mock(VmPollingAction.class);
-        backend.registerAction(action1);
-        backend.registerAction(action2);
-        backend.doScheduledActions();
-
-        verify(action1).run(eq(vmId1), eq(pid1));
-        verify(action1).run(eq(vmId2), eq(pid2));
-        verify(action2).run(eq(vmId1), eq(pid1));
-        verify(action2).run(eq(vmId2), eq(pid2));
-    }
-
-    @Test
-    public void verifyUnregisteredActionNotPerformed() {
-        String vmId = "test-vm-id";
-        int pid = 123;
-        backend.vmStatusChanged(Status.VM_ACTIVE, vmId, pid);
-        VmPollingAction action1 = mock(VmPollingAction.class);
-        VmPollingAction action2 = mock(VmPollingAction.class);
-        backend.registerAction(action1);
-        backend.registerAction(action2);
-        backend.doScheduledActions(); // Triggers both
-        backend.unregisterAction(action1);
-        backend.doScheduledActions(); // Triggers only action2
-
-        verify(action1, times(1)).run(eq(vmId), eq(pid));
-        verify(action2, times(2)).run(eq(vmId), eq(pid));
-    }
-
-    @Test
-    public void verifyVmStatusChangedStartedAndActiveResultInPolling() {
-        String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2";
-        int pid1 = 123, pid2 = 456;
-        backend.vmStatusChanged(Status.VM_STARTED, vmId1, pid1);
-        backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2);
-        VmPollingAction action = mock(VmPollingAction.class);
-        backend.registerAction(action);
-        backend.doScheduledActions();
-
-        verify(action).run(eq(vmId1), eq(pid1));
-        verify(action).run(eq(vmId2), eq(pid2));
-    }
-
-    @Test
-    public void verifyVmStatusChangedStopsResultsInNoMorePolling() {
-        String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2";
-        int pid1 = 123, pid2 = 456;
-        backend.vmStatusChanged(Status.VM_ACTIVE, vmId1, pid1);
-        backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2);
-        VmPollingAction action = mock(VmPollingAction.class);
-        backend.registerAction(action);
-        backend.doScheduledActions(); // Triggers for both vms
-        backend.vmStatusChanged(Status.VM_STOPPED, vmId1, pid1);
-        backend.doScheduledActions(); // Triggers only for vm2
-
-        verify(action, times(1)).run(eq(vmId1), eq(pid1));
-        verify(action, times(2)).run(eq(vmId2), eq(pid2));
-    }
-
-    @Test
-    public void verifyGetSetObserveNewJvmWorksAsExpected() {
-        String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2";
-        int pid1 = 123, pid2 = 456;
-        backend.vmStatusChanged(Status.VM_ACTIVE, vmId1, pid1);
-        backend.setObserveNewJvm(false);
-        backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2); // Should be ignored.
-        VmPollingAction action = mock(VmPollingAction.class);
-        backend.registerAction(action);
-        backend.doScheduledActions();
-
-        verify(action).run(eq(vmId1), eq(pid1));
-        verify(action, never()).run(eq(vmId2), eq(pid2));
-    }
-    
-    private static class BadVmPollingAction implements VmPollingAction {
-        
-        private final Map<String, Integer> callCounts = new HashMap<>();
-        
-        @Override
-        public void run(String vmId, int pid) {
-            Integer currCount = callCounts.remove(vmId);
-            if (currCount == null) {
-                currCount = Integer.valueOf(1);
-            } else {
-                currCount++;
-            }
-            callCounts.put(vmId, Integer.valueOf(currCount));
-            throw new RuntimeException("doScheduledActions() testing!");
-        }
-        
-        private Integer getCallCount(String vmId) {
-            return callCounts.get(vmId);
-        }
-        
-    }
-}
--- a/agent/core/src/test/java/com/redhat/thermostat/backend/internal/TestLogHandler.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-/*
- * Copyright 2012-2017 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.util.logging.Handler;
-import java.util.logging.Level;
-import java.util.logging.LogRecord;
-
-/*
- * Test log handler used for VmMonitor log testing.
- */
-public class TestLogHandler extends Handler {
-    
-    private static final String PROCESS_NOT_FOUND = "Process not found";
-    private static final String EXPECTED_UNABLE_TO_ATTACH_PROC_NOT_FOUND_FMT =
-            "Tried to attach to a process which no longer exists. Pid was %d";
-    private static final String EXPECTED_UNABLE_TO_ATTACH_MSG_FMT =
-            "unable to attach to vm %d";
-    private boolean unableToAttachLoggedWarning;
-    private boolean unableToAttachLoggedFinest;
-    private final String unableToAttachMsg;
-    private final String procNotFoundMsg;
-    
-    TestLogHandler(int pid) {
-        unableToAttachMsg = String.format(EXPECTED_UNABLE_TO_ATTACH_MSG_FMT, pid);
-        procNotFoundMsg = String.format(EXPECTED_UNABLE_TO_ATTACH_PROC_NOT_FOUND_FMT, pid);
-    }
-    
-    @Override
-    public void publish(LogRecord record) {
-        String logMessage = record.getMessage();
-        if (record.getLevel().intValue() >= Level.WARNING.intValue() && 
-                logMessage.equals(unableToAttachMsg)) {
-            unableToAttachLoggedWarning = diagnoseRecord(record);
-        }
-        if (record.getLevel().intValue() == Level.FINEST.intValue() &&
-                logMessage.equals(procNotFoundMsg)) {
-            unableToAttachLoggedFinest = diagnoseRecord(record);
-        }
-    }
-
-    private boolean diagnoseRecord(LogRecord record) {
-        Throwable thrown = record.getThrown();
-        if (thrown != null && thrown.getCause() instanceof IllegalArgumentException) {
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public void flush() {
-        // nothing
-    }
-
-    @Override
-    public void close() throws SecurityException {
-        // nothing
-    }
-    
-    boolean isUnableToAttachLoggedAsWarning() {
-        return unableToAttachLoggedWarning;
-    }
-    
-    boolean isUnableToAttachLoggedAsWarningUnrelated() {
-        return !unableToAttachLoggedWarning && !unableToAttachLoggedFinest;
-    }
-    
-    boolean isUnableToAttachLoggedAsFinest() {
-        return unableToAttachLoggedFinest;
-    }
-    
-}
-
--- a/agent/core/src/test/java/com/redhat/thermostat/backend/internal/VmListenerWrapperTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,154 +0,0 @@
-/*
- * Copyright 2012-2017 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.times;
-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 com.redhat.thermostat.backend.VmUpdate;
-import com.redhat.thermostat.backend.VmUpdateException;
-import com.redhat.thermostat.backend.VmUpdateListener;
-import com.redhat.thermostat.common.internal.test.Bug;
-
-import sun.jvmstat.monitor.Monitor;
-import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredVm;
-import sun.jvmstat.monitor.event.VmEvent;
-
-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);
-    }
-    
-    /**
-     * Verify that a bad listener which throws exceptions gets removed
-     * from the JVM beyond a threshold.
-     * @throws MonitorException 
-     */
-    @Bug(id = "3242",
-         summary = "Adverse Backend breaks other Backends badly ",
-         url = "http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=3242")
-    @Test
-    public void testMonitorsUpdatedListenerExceptions() throws MonitorException {
-        final int beyondThresholdLimit = 11;
-        VmUpdateListener badListener = new VmUpdateListener() {
-            @Override
-            public void countersUpdated(VmUpdate update) {
-                throw new RuntimeException("countersUpdated() testing!");
-            }
-        };
-        VmListenerWrapper vmListenerWrapper = new VmListenerWrapper(badListener, monitoredVm);
-        VmEvent event = mock(VmEvent.class);
-        for (int i = 0; i < beyondThresholdLimit; i++) {
-            when(event.getMonitoredVm()).thenReturn(monitoredVm);
-            
-            vmListenerWrapper.monitorsUpdated(event);
-            
-        }
-        verify(monitoredVm, times(1)).removeVmListener(vmListenerWrapper);
-    }
-
-    @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);
-    }
-
-}
-
--- a/agent/core/src/test/java/com/redhat/thermostat/backend/internal/VmMonitorTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,285 +0,0 @@
-/*
- * Copyright 2012-2017 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 java.util.logging.Level;
-import java.util.logging.Logger;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import com.redhat.thermostat.common.portability.ProcessChecker;
-import com.redhat.thermostat.backend.VmUpdateListener;
-
-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;
-
-public class VmMonitorTest {
-
-    private static final String PROCESS_NOT_FOUND = "Process not found";
-    private static final int MONITOR_EXCEPTION_THROWING_PID = 999;
-    private VmMonitor monitor;
-    private HostIdentifier hostIdentifier;
-    private MonitoredHost host;
-    private MonitoredVm monitoredVm;
-    private ProcessChecker checker;
-    private TestLogHandler handler;
-    private Logger logger;
-    private Level savedLoggingLevel;
-
-    @After
-    public void tearDown() {
-        if (handler != null) {
-            logger.removeHandler(handler);
-            handler = null;
-        }
-        logger.setLevel(savedLoggingLevel);
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        savedLoggingLevel = setupTestLoggerAndReturnOriginalLevel();
-
-        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);
-        
-        checker = mock(ProcessChecker.class);
-        when(checker.exists(isA(Integer.class))).thenReturn(false);
-
-        monitoredVm = mock(MonitoredVm.class);
-
-        monitor = new VmMonitor(checker);
-        monitor.setHost(host);
-    }
-    
-    private Level setupTestLoggerAndReturnOriginalLevel() {
-        logger = Logger.getLogger("com.redhat.thermostat");
-        Level originalLevel = logger.getLevel();
-        logger.setLevel(Level.FINEST);
-        handler = new TestLogHandler(MONITOR_EXCEPTION_THROWING_PID);
-        logger.addHandler(handler);
-        return originalLevel;
-    }
-
-    @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());
-    }
-    
-    /*
-     * English locale "Process not found". It must not matter really for this
-     * test. See the next test which verifies this.
-     */
-    @Test
-    public void testNewVMWithProcessNotFoundDoesNotLogWarning() throws Exception {
-        String exceptionMsg = PROCESS_NOT_FOUND;
-        basicProcNotFoundTest(exceptionMsg);
-    }
-    
-    /*
-     * Random exception message as the exact message will be locale dependent.
-     */
-    @Test
-    public void testNewVMWithProcessNotFoundDoesNotLogWarning2() throws Exception {
-        String exceptionMsg = "foo but not bar";
-        basicProcNotFoundTest(exceptionMsg);
-    }
-
-    private void basicProcNotFoundTest(String exceptionMsg) throws Exception {
-        IllegalArgumentException iae = new IllegalArgumentException(exceptionMsg);
-        MonitorException procNotFound = new MonitorException(iae);
-        assertEquals(iae, procNotFound.getCause());
-        
-        VmIdentifier vmID = new VmIdentifier(String.valueOf(MONITOR_EXCEPTION_THROWING_PID));
-        when(host.getMonitoredVm(vmID)).thenThrow(procNotFound);
-        VmUpdateListener listener = mock(VmUpdateListener.class);
-
-        monitor.handleNewVm(listener, MONITOR_EXCEPTION_THROWING_PID);
-        assertFalse(handler.isUnableToAttachLoggedAsWarning());
-        assertTrue(handler.isUnableToAttachLoggedAsFinest());
-        assertFalse(handler.isUnableToAttachLoggedAsWarningUnrelated());
-    }
-
-    @Test
-    public void testNewVMUnrelatedCausedMonitorExceptionLogWarning() throws Exception {
-        MonitorException procNotFound = new MonitorException("unknown");
-        
-        VmIdentifier vmID = new VmIdentifier(String.valueOf(MONITOR_EXCEPTION_THROWING_PID));
-        when(host.getMonitoredVm(vmID)).thenThrow(procNotFound);
-        VmUpdateListener listener = mock(VmUpdateListener.class);
-        
-        monitor.handleNewVm(listener, MONITOR_EXCEPTION_THROWING_PID);
-        assertFalse(handler.isUnableToAttachLoggedAsWarning());
-        assertFalse(handler.isUnableToAttachLoggedAsFinest());
-        assertTrue(handler.isUnableToAttachLoggedAsWarningUnrelated());
-    }
-    
-    @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());
-    }
-
-}
-
--- a/agent/core/src/test/java/com/redhat/thermostat/backend/internal/VmUpdateImplTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,125 +0,0 @@
-/*
- * Copyright 2012-2017 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/distribution/assembly/plugin-assembly.xml	Thu Jun 08 20:16:03 2017 +0200
+++ b/distribution/assembly/plugin-assembly.xml	Fri Jun 09 16:38:44 2017 +0200
@@ -50,6 +50,9 @@
       <unpack>true</unpack>
       <includes>
         <include>com.redhat.thermostat:thermostat-host-overview-distribution</include>
+        <include>com.redhat.thermostat:thermostat-jvm-overview-distribution</include>
+        <include>com.redhat.thermostat:thermostat-vm-gc-distribution</include>
+        <include>com.redhat.thermostat:thermostat-vm-memory-distribution</include>
 <!--        <include>com.redhat.thermostat:thermostat-host-cpu-distribution</include>-->
 <!--        <include>com.redhat.thermostat:thermostat-host-memory-distribution</include>-->
 <!--        <include>com.redhat.thermostat:thermostat-numa-distribution</include>-->
@@ -58,11 +61,9 @@
 <!--        <include>com.redhat.thermostat:thermostat-vm-classstat-distribution</include>-->
 <!--        <include>com.redhat.thermostat:thermostat-vm-compiler-distribution</include>-->
 <!--        <include>com.redhat.thermostat:thermostat-vm-cpu-distribution</include>-->
-        <include>com.redhat.thermostat:thermostat-vm-gc-distribution</include>
 <!--        <include>com.redhat.thermostat:thermostat-vm-heap-analysis-distribution</include>-->
 <!--        <include>com.redhat.thermostat:thermostat-vm-io-distribution</include>-->
 <!--        <include>com.redhat.thermostat:thermostat-vm-jmx-distribution</include>-->
-        <include>com.redhat.thermostat:thermostat-vm-memory-distribution</include>
 <!--        <include>com.redhat.thermostat:thermostat-vm-profiler-distribution</include>-->
 <!--        <include>com.redhat.thermostat:thermostat-killvm-distribution</include>-->
 <!--        <include>com.redhat.thermostat:thermostat-vm-numa-distribution</include>-->
--- a/distribution/pom.xml	Thu Jun 08 20:16:03 2017 +0200
+++ b/distribution/pom.xml	Fri Jun 09 16:38:44 2017 +0200
@@ -131,11 +131,6 @@
       <dependencies>
         <dependency>
           <groupId>com.redhat.thermostat</groupId>
-          <artifactId>thermostat-keyring</artifactId>
-          <version>${project.version}</version>
-        </dependency>
-        <dependency>
-          <groupId>com.redhat.thermostat</groupId>
           <artifactId>thermostat-agent-ipc-unixsocket-server</artifactId>
           <version>${project.version}</version>
         </dependency>
@@ -497,6 +492,30 @@
       <version>${project.version}</version>
       <type>zip</type>
     </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-jvm-overview-distribution</artifactId>
+      <version>${project.version}</version>
+      <type>zip</type>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-vm-gc-distribution</artifactId>
+      <version>${project.version}</version>
+      <type>zip</type>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-vm-memory-distribution</artifactId>
+      <version>${project.version}</version>
+      <type>zip</type>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-killvm-distribution</artifactId>
+      <version>${project.version}</version>
+      <type>zip</type>
+    </dependency>
     <!--<dependency>-->
       <!--<groupId>com.redhat.thermostat</groupId>-->
       <!--<artifactId>thermostat-host-cpu-distribution</artifactId>-->
@@ -560,12 +579,6 @@
       <!--<version>${project.version}</version>-->
       <!--<type>zip</type>-->
     <!--</dependency>-->
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-vm-gc-distribution</artifactId>
-      <version>${project.version}</version>
-      <type>zip</type>
-    </dependency>
     <!--<dependency>-->
       <!--<groupId>com.redhat.thermostat</groupId>-->
       <!--<artifactId>thermostat-vm-heap-analysis-distribution</artifactId>-->
@@ -584,24 +597,12 @@
       <!--<version>${project.version}</version>-->
       <!--<type>zip</type>-->
     <!--</dependency>-->
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-vm-memory-distribution</artifactId>
-      <version>${project.version}</version>
-      <type>zip</type>
-    </dependency>
     <!--<dependency>-->
       <!--<groupId>com.redhat.thermostat</groupId>-->
       <!--<artifactId>thermostat-vm-profiler-distribution</artifactId>-->
       <!--<version>${project.version}</version>-->
       <!--<type>zip</type>-->
     <!--</dependency>-->
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-killvm-distribution</artifactId>
-      <version>${project.version}</version>
-      <type>zip</type>
-    </dependency>
   </dependencies>
 
 </project>
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -46,7 +46,6 @@
 import com.redhat.thermostat.launcher.Launcher;
 import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.storage.dao.AgentInfoDAO;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.testutils.StubBundleContext;
 import org.junit.Before;
 import org.junit.Test;
@@ -174,7 +173,6 @@
 
         MultipleServiceTracker unusedTracker = mock(MultipleServiceTracker.class);
         Class<?>[] vmIdCompleterDeps = new Class[] {
-                VmInfoDAO.class,
                 AgentInfoDAO.class
         };
         whenNew(MultipleServiceTracker.class).withParameterTypes(BundleContext.class, Class[].class, Action.class).withArguments(eq(context),
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/pom.xml	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Copyright 2012-2017 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <artifactId>thermostat-jvm-overview</artifactId>
+    <groupId>com.redhat.thermostat</groupId>
+    <version>1.99.12-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>thermostat-jvm-overview-agent</artifactId>
+  <packaging>bundle</packaging>
+  <name>Thermostat JVM Overview Agent plugin</name>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Bundle-SymbolicName>com.redhat.thermostat.jvm.overview</Bundle-SymbolicName>
+            <Export-Package>
+              com.redhat.thermostat.jvm.overview.agent,
+              com.redhat.thermostat.jvm.overview.agent.model,
+            </Export-Package>
+            <Private-Package>
+              com.redhat.thermostat.jvm.overview.agent.internal,
+              com.redhat.thermostat.jvm.overview.agent.internal.model,
+            </Private-Package>
+            <!-- Do not autogenerate uses clauses in Manifests -->
+            <_nouses>true</_nouses>
+          </instructions>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-scr-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>generate-scr-scrdescriptor</id>
+            <goals>
+              <goal>scr</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>copy</id>
+            <phase>generate-resources</phase>
+            <goals>
+              <goal>copy-resources</goal>
+            </goals>
+            <configuration>
+              <overwrite>true</overwrite>
+              <outputDirectory>${project.build.directory}</outputDirectory>
+              <resources>
+                <resource>
+                  <directory>../../../common/portability/target</directory>
+                  <includes>
+                    <include>${sharedlib.prefix}thermostat-common-portability${sharedlib.suffix}</include>
+                  </includes>
+                </resource>
+              </resources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <!-- the test needs to link to common-portability native libraries -->
+          <systemPropertyVariables>
+            <com.redhat.thermostat.shared.loader.testNativesHome>${project.build.directory}</com.redhat.thermostat.shared.loader.testNativesHome>
+          </systemPropertyVariables>
+        </configuration>
+      </plugin>
+
+    </plugins>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-portability</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-agent-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-storage-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-test</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <!-- declarative services -->
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.scr.annotations</artifactId>
+    </dependency>
+  </dependencies>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmBlacklist.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent;
+
+import com.redhat.thermostat.common.Filter;
+
+/**
+ * Maintains a list of JVM processes that Thermostat should not
+ * monitor.
+ */
+public interface VmBlacklist {
+    
+    /**
+     * Adds a {@link Filter} to the blacklist. Virtual machines whose
+     * main class match the filter will not be monitored.
+     * @param filter - a filter whose matching VMs should not be monitored
+     */
+    void addVmFilter(Filter<String> filter);
+    
+    /**
+     * Removes a {@link Filter} from the blacklist. New virtual machines
+     * will no longer be tested against this filter for blacklisting.
+     * @param filter - a filter previously in the blacklist
+     */
+    void removeVmFilter(Filter<String> filter);
+    
+    /**
+     * Returns whether the given virtual machine should be monitored
+     * by matching it against filters in the blacklist. If any filter
+     * matches, then this method will return true.
+     * @param mainClass - a class name to check against classes covered
+     *                    by this blacklist
+     * @return true if blacklisted, false otherwise
+     */
+    boolean isBlacklisted(String mainClass);
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmListenerBackend.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.backend.BaseBackend;
+import com.redhat.thermostat.backend.BackendException;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.storage.core.WriterID;
+
+/**
+ * This class is a convenient subclass of {@link com.redhat.thermostat.backend.Backend} (via {@link BaseBackend}) for those
+ * that need to attach {@link VmUpdateListener} in response to starting and stopping of JVMs on a
+ * host.
+ * 
+ * @see package com.redhat.thermostat.jvm.overview.agent.VmStatusListener
+ * @see com.redhat.thermostat.backend.Backend
+ * @see BaseBackend
+ */
+public abstract class VmListenerBackend extends BaseBackend implements VmStatusListener {
+    
+    private static final Logger logger = LoggingUtils.getLogger(VmListenerBackend.class);
+    
+    private WriterID writerId;
+    private VmStatusListenerRegistrar registrar;
+    private VmMonitor monitor;
+    private boolean started;
+    private boolean initialized;
+
+    public VmListenerBackend(String backendName, String description, String vendor, boolean observeNewJvm) {
+        this(backendName, description, vendor, "1.0", observeNewJvm);
+    }
+
+    public VmListenerBackend(String backendName, String description, String vendor) {
+        this(backendName, description, vendor, "1.0", false);
+    }
+
+    public VmListenerBackend(String backendName, String description,
+            String vendor, String version, boolean observeNewJvm) {
+        super(backendName, description, vendor, version, observeNewJvm);
+        try {
+            this.monitor = new VmMonitor();
+        } catch (BackendException e) {
+            logger.log(Level.SEVERE, "Unable to create backend", e);
+        }
+    }
+    
+    /**
+     * {@inheritDoc}
+     * 
+     * <p>
+     * Registers a VmUpdateListener to begin receiving VM lifecycle events.
+     * Subclasses should call <code>super.activate()</code> when overriding this method.
+     * </p>
+     * <p>
+     * This {@link VmListenerBackend} should be initialized via 
+     * {@link #initialize(WriterID, VmStatusListenerRegistrar)} before calling this method.
+     * </p>
+     */
+    @Override
+    public boolean activate() {
+        if (!initialized) {
+            logger.warning("Backend not started, initialize must be called before activate");
+        } else if (!started && monitor != null) {
+            registrar.register(this);
+            started = true;
+        }
+        return started;
+    }
+    
+    /**
+     * {@inheritDoc}
+     * 
+     * <p>
+     * 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 && monitor != null) {
+            registrar.unregister(this);
+            monitor.removeVmListeners();
+            started = false;
+        }
+        return !started;
+    }
+    
+    @Override
+    public boolean isActive() {
+        return started;
+    }
+
+    public void vmStatusChanged(Status newStatus, String vmId, int pid) {
+        switch (newStatus) {
+        case VM_STARTED:
+            /* fall-through */
+        case VM_ACTIVE:
+            if (getObserveNewJvm()) {
+                String wId = writerId.getWriterID();
+                VmUpdateListener listener = null;
+                try {
+                    listener = createVmListener(wId, vmId, pid);
+                } catch (Throwable t) {
+                    logger.log(Level.INFO, "Creating the VM listener for a VmListenerBackend threw an exception. Going to ignore the backend!", t);
+                }
+                if (listener != null) {
+                    monitor.handleNewVm(listener, pid);
+                }
+            } else {
+                logger.log(Level.FINE, "skipping new vm " + pid);
+            }
+            break;
+        case VM_STOPPED:
+            monitor.handleStoppedVm(pid);
+            break;
+        default:
+            break;
+        }
+    }
+
+    /**
+     * Initializes this {@link VmListenerBackend} with necessary services. This method
+     * must be called before {@link #activate()}.
+     * @param writerId service uniquely identifying this agent
+     * @param registrar responsible for registering and unregistering instances of {@link VmStatusListener}
+     * @param version version number of this backend
+     */
+    protected void initialize(WriterID writerId, VmStatusListenerRegistrar registrar, String version) {
+        this.writerId = writerId;
+        this.registrar = registrar;
+        setVersion(version);
+        this.initialized = true;
+    }
+    
+    /**
+     * 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 vmId unique identifier of the JVM
+     * @param pid the process ID of the JVM
+     * @return a new listener for the VM specified by pid
+     */
+    protected abstract VmUpdateListener createVmListener(String writerId, String vmId, int pid);
+    
+    /*
+     * For testing purposes only.
+     */
+    void setMonitor(VmMonitor monitor) {
+        this.monitor = monitor;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmMonitor.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent;
+
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.backend.BackendException;
+import com.redhat.thermostat.jvm.overview.agent.internal.VmListenerWrapper;
+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.common.portability.ProcessChecker;
+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 final ProcessChecker processChecker;
+    private MonitoredHost host;
+    private Map<Integer, Pair<MonitoredVm, VmListenerWrapper>> pidToData = new HashMap<>();
+    
+    public VmMonitor() throws BackendException {
+        this(new ProcessChecker());
+    }
+
+    public VmMonitor(ProcessChecker processChecker) throws BackendException {
+        this.processChecker = processChecker;
+        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 e) {
+            logMsg(pid, e);
+        } catch (URISyntaxException e) {
+            logger.log(Level.WARNING, "unable to attach to vm " + pid, e);
+        }
+    }
+
+    private void logMsg(int pid, MonitorException e) {
+        Throwable cause = e.getCause();
+        if (cause != null && cause instanceof IllegalArgumentException && !processChecker.exists(pid)) {
+            logger.log(Level.FINEST, "Tried to attach to a process which no longer exists. Pid was " + pid, e);
+        } else {
+            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/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmPollingAction.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent;
+
+/**
+ * An action to be performed at a regular interval as part of a
+ * {@link VmPollingBackend} implementation.
+ */
+public interface VmPollingAction {
+
+    /**
+     * Run the action.
+     * 
+     * @param vmId a String representation of the VmID on which to take action.
+     * @param pid the process ID of the JVM instance on which to take action.
+     */
+    public void run(String vmId, int pid);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmPollingBackend.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.backend.PollingBackend;
+import com.redhat.thermostat.common.Pair;
+import com.redhat.thermostat.common.Version;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+
+/**
+ * Convenience {@link com.redhat.thermostat.backend.Backend} class for implementations that will take some
+ * action for each monitored JVM process on a regular interval.  Simply
+ * extend this class, implement any missing methods, and register one or
+ * more {@link VmPollingAction} implementations during instantiation.
+ */
+public abstract class VmPollingBackend extends PollingBackend implements VmStatusListener {
+
+    private final Set<VmPollingAction> actions;
+    private final Map<String, Pair<Integer, VmPollingAction>> badActions;
+    private final Map<Integer, String> pidsToMonitor = new ConcurrentHashMap<>();
+    private final VmStatusListenerRegistrar registrar;
+    private static final Logger logger = LoggingUtils.getLogger(VmPollingBackend.class);
+    private static final int EXCEPTIONS_THRESHOLD = 10;
+
+    public VmPollingBackend(String name, String description,
+            String vendor, Version version, ScheduledExecutorService executor,
+            VmStatusListenerRegistrar registrar) {
+        super(name, description, vendor, version, executor);
+        this.registrar = registrar;
+        this.actions = new CopyOnWriteArraySet<>();
+        this.badActions = new HashMap<>();
+    }
+
+    @Override
+    final public void preActivate() {
+        registrar.register(this);
+    }
+
+    @Override
+    final public void postDeactivate() {
+        registrar.unregister(this);
+    }
+
+    @Override
+    final public void doScheduledActions() {
+        for (Entry<Integer, String> entry : pidsToMonitor.entrySet()) {
+            int pid = entry.getKey();
+            String vmId = entry.getValue();
+            for (VmPollingAction action : actions) {
+                try {
+                    action.run(vmId, pid);
+                } catch (Throwable t) {
+                    handleActionException(action, vmId);
+                }
+            }
+        }
+    }
+
+    private synchronized void handleActionException(VmPollingAction action, String vmId) {
+        final String actionName = action.getClass().getName();
+        final String actionKey = actionName + vmId;
+        Pair<Integer, VmPollingAction> actionPair = badActions.remove(actionKey);
+        if (actionPair == null) {
+            actionPair = new Pair<>(Integer.valueOf(1), action);
+        }
+        int exceptionsPerAction = actionPair.getFirst();
+        if (exceptionsPerAction < EXCEPTIONS_THRESHOLD) {
+            exceptionsPerAction++;
+            logger.info(VmPollingAction.class.getSimpleName() + " " +
+                    actionName + " threw an exception");
+            badActions.put(actionKey, new Pair<>(exceptionsPerAction, action));
+        } else {
+            logger.fine("Removing " + actionName + " due to too many repeated exceptions.");
+            unregisterAction(action);
+        }
+    }
+
+    /**
+     * Register an action to be performed at each polling interval.  It is
+     * recommended that implementations register all such actions during
+     * instantiation.
+     */
+    protected final void registerAction(VmPollingAction action) {
+        actions.add(action);
+    }
+
+    /**
+     * Unregister an action so that it will no longer be performed at each
+     * polling interval.  If no such action has been registered, this
+     * method has no effect.  Depending on thread timing issues, the action
+     * may be performed once even after this method has been called.
+     */
+    protected final void unregisterAction(VmPollingAction action) {
+        actions.remove(action);
+    }
+
+    @Override
+    public void vmStatusChanged(Status newStatus, String vmId, int pid) {
+        switch (newStatus) {
+        case VM_STARTED:
+            /* fall-through */
+        case VM_ACTIVE:
+            if (getObserveNewJvm()) {
+                pidsToMonitor.put(pid, vmId);
+            } else {
+                logger.log(Level.FINE, "skipping new vm " + pid);
+            }
+            break;
+        case VM_STOPPED:
+            pidsToMonitor.remove(pid);
+            break;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmStatusListener.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent;
+
+import com.redhat.thermostat.annotations.ExtensionPoint;
+
+/**
+ * A listener that is notified when a JVM starts or is stopped.
+ * <p>
+ * Register an instance of this class as an OSGi service, and it will be
+ * notified of all VM {@link Status} events.
+ */
+@ExtensionPoint
+public interface VmStatusListener {
+
+    enum Status {
+
+        /** A VM has just started now */
+        VM_STARTED,
+
+        /**
+         * A delayed version of {@link #VM_STARTED}. A VM was started at some
+         * point in the past. The listener was not informed about it then
+         * (probably because the listener was not registered at the time), but
+         * is being informed about it now.
+         */
+        VM_ACTIVE,
+
+        /** A VM was stopped just now */
+        VM_STOPPED,
+    }
+
+    // TODO what other information other than vmId and pid may be useful for plugins?
+
+    void vmStatusChanged(Status newStatus, String vmId, int pid);
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmStatusListenerRegistrar.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Registers a {@link VmStatusListener} as an OSGi Service.
+ * <p>
+ * This is just a convenience wrapper over
+ * {@link BundleContext#registerService(String, Object, java.util.Dictionary)}.
+ * It does absolutely nothing special.
+ *
+ * @see VmStatusListener
+ */
+public class VmStatusListenerRegistrar {
+
+    private final BundleContext context;
+    private final Map<VmStatusListener, ServiceRegistration> registrations = new HashMap<>();
+
+    public VmStatusListenerRegistrar(BundleContext context) {
+        this.context = context;
+    }
+
+    public void register(VmStatusListener listener) {
+        registrations.put(listener, context.registerService(VmStatusListener.class.getName(), listener, null));
+    }
+
+    public void unregister(VmStatusListener listener) {
+        ServiceRegistration registration = registrations.remove(listener);
+        if (registration == null) {
+            throw new IllegalArgumentException("no listener found");
+        }
+
+        registration.unregister();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmUpdate.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent;
+
+/**
+ * This interface can be used to query the performance counters
+ * of a monitored JVM when they are updated.
+ * @see package com.redhat.thermostat.jvm.overview.agent.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 com.redhat.thermostat.jvm.overview.agent.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/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmUpdateException.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent;
+
+/**
+ * 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/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmUpdateListener.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent;
+
+/**
+ * A listener that can be registered to receive updates for a
+ * JVM's performance counters.
+ * @see com.redhat.thermostat.jvm.overview.agent.VmListenerBackend#createVmListener(String, String, 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
+     */
+    void countersUpdated(VmUpdate update);
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/JvmStatDataExtractor.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal;
+
+import sun.jvmstat.monitor.MonitorException;
+import sun.jvmstat.monitor.MonitoredVm;
+import sun.jvmstat.monitor.MonitoredVmUtil;
+
+/**
+ * A helper class to provide type-safe access to commonly used jvmstat monitors
+ * <p>
+ * Implementation details: For local vms, jvmstat uses a ByteBuffer
+ * corresponding to mmap()ed hsperfdata file. The hsperfdata file is updated
+ * asynchronously by the vm that created the file. The polling that jvmstat api
+ * provides is merely an abstraction over this (possibly always up-to-date)
+ * ByteBuffer. So the data this class extracts is as current as possible, and
+ * does not correspond to when the jvmstat update events fired.
+ */
+public class JvmStatDataExtractor {
+
+    /*
+     * Note, there may be a performance issue to consider here. We have a lot of
+     * string constants. When we start adding some of the more heavyweight
+     * features, and running into CPU issues this may need to be reconsidered in
+     * order to avoid the String pool overhead. See also:
+     * http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#intern()
+     */
+
+    private final MonitoredVm vm;
+
+    public JvmStatDataExtractor(MonitoredVm vm) {
+        this.vm = vm;
+    }
+
+    public String getCommandLine() throws MonitorException {
+        return MonitoredVmUtil.commandLine(vm);
+    }
+
+    public String getMainClass() throws MonitorException {
+        return MonitoredVmUtil.mainClass(vm, true);
+    }
+
+    public String getJavaVersion() throws MonitorException {
+        return (String) vm.findByName("java.property.java.version").getValue();
+    }
+
+    public String getJavaHome() throws MonitorException {
+        return (String) vm.findByName("java.property.java.home").getValue();
+    }
+
+    public String getVmName() throws MonitorException {
+        return (String) vm.findByName("java.property.java.vm.name").getValue();
+    }
+
+    public String getVmInfo() throws MonitorException {
+        return (String) vm.findByName("java.property.java.vm.info").getValue();
+    }
+
+    public String getVmVersion() throws MonitorException {
+        return (String) vm.findByName("java.property.java.vm.version").getValue();
+    }
+
+    public String getVmArguments() throws MonitorException {
+        return MonitoredVmUtil.jvmArgs(vm);
+    }
+
+    public long getVmStartTime() throws MonitorException {
+        return (long) vm.findByName("sun.rt.vmInitDoneTime").getValue();
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/JvmStatHostListener.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal;
+
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.common.Pair;
+import com.redhat.thermostat.common.portability.ProcessUserInfo;
+import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.jvm.overview.agent.VmBlacklist;
+import com.redhat.thermostat.jvm.overview.agent.VmStatusListener.Status;
+import com.redhat.thermostat.jvm.overview.agent.internal.model.InfoBuilderFactory;
+import com.redhat.thermostat.jvm.overview.agent.internal.model.VmInfoDAO;
+import com.redhat.thermostat.jvm.overview.agent.model.VmInfo;
+import com.redhat.thermostat.storage.core.WriterID;
+
+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.HostEvent;
+import sun.jvmstat.monitor.event.HostListener;
+import sun.jvmstat.monitor.event.VmStatusChangeEvent;
+
+class JvmStatHostListener implements HostListener {
+
+    private static final Logger logger = LoggingUtils.getLogger(JvmStatHostListener.class);
+
+    private final VmInfoDAO vmInfoDAO;
+    private final VmStatusChangeNotifier notifier;
+    private final ProcessUserInfoBuilder userInfoBuilder;
+    private final WriterID writerId;
+    private Map<Integer, Pair<String, MonitoredVm>> monitoredVms  = new HashMap<>();
+    private final VmBlacklist blacklist;
+
+    JvmStatHostListener(VmInfoDAO vmInfoDAO, VmStatusChangeNotifier notifier,
+                        ProcessUserInfoBuilder userInfoBuilder, WriterID writerId,
+                        VmBlacklist blacklist) {
+        this.vmInfoDAO = vmInfoDAO;
+        this.notifier = notifier;
+        this.userInfoBuilder = userInfoBuilder;
+        this.writerId = writerId;
+        this.blacklist = blacklist;
+    }
+
+    @Override
+    public void disconnected(HostEvent event) {
+        logger.warning("Disconnected from host");
+    }
+
+    @SuppressWarnings("unchecked") // Unchecked casts to (Set<Integer>).
+    @Override
+    public void vmStatusChanged(VmStatusChangeEvent event) {
+        MonitoredHost host = event.getMonitoredHost();
+
+        for (Integer newVm : (Set<Integer>) event.getStarted()) {
+            try {
+                logger.fine("New vm: " + newVm);
+                sendNewVM(newVm, host);
+            } catch (MonitorException e) {
+                logger.log(Level.WARNING, "error getting info for new vm " + newVm, e);
+            } catch (URISyntaxException e) {
+                logger.log(Level.WARNING, "error getting info for new vm " + newVm, e);
+            }
+        }
+
+        for (Integer stoppedVm : (Set<Integer>) event.getTerminated()) {
+            try {
+                logger.fine("stopped vm: " + stoppedVm);
+                sendStoppedVM(stoppedVm, host);
+            } catch (URISyntaxException e) {
+                logger.log(Level.WARNING, "error getting info for stopped vm " + stoppedVm, e);
+            } catch (MonitorException e) {
+                logger.log(Level.WARNING, "error getting info for stopped vm " + stoppedVm, e);
+            }
+        }
+    }
+
+    private void sendNewVM(Integer vmPid, MonitoredHost host)
+            throws MonitorException, URISyntaxException {
+        // Propagate any MonitorException, and do not notify Backends or remember
+        // VMs when we fail to extract the necessary information.
+        // http://icedtea.classpath.org/pipermail/thermostat/2013-November/008702.html
+        MonitoredVm vm = host.getMonitoredVm(host.getHostIdentifier().resolve(
+                new VmIdentifier(vmPid.toString())));
+        if (vm != null) {
+            JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+            String vmId = UUID.randomUUID().toString();
+            long stopTime = Long.MIN_VALUE;
+            VmInfo info = createVmInfo(vmId, vmPid, stopTime, extractor);
+
+            // Check blacklist
+            if (!blacklist.isBlacklisted(info.getMainClass())) {
+                vmInfoDAO.putVmInfo(info);
+
+                notifier.notifyVmStatusChange(Status.VM_STARTED, vmId, vmPid);
+                logger.finer("Sent VM_STARTED messsage");
+
+                monitoredVms.put(vmPid, new Pair<>(vmId, vm));
+            }
+            else {
+                logger.info("Skipping VM: " + vmPid);
+            }
+        }
+    }
+
+    VmInfo createVmInfo(String vmId, Integer vmPid, long stopTime,
+            JvmStatDataExtractor extractor) throws MonitorException {
+        Map<String, String> properties = new HashMap<String, String>();
+        Map<String, String> environment = InfoBuilderFactory.INSTANCE.createProcessEnvironmentBuilder().build(vmPid);
+        // TODO actually figure out the loaded libraries.
+        String[] loadedNativeLibraries = new String[0];
+        ProcessUserInfo userInfo = userInfoBuilder.build(vmPid);
+        VmInfo info = new VmInfo(writerId.getWriterID(), vmId, vmPid, extractor.getVmStartTime(), stopTime,
+                                 extractor.getJavaVersion(), extractor.getJavaHome(),
+                                 extractor.getMainClass(), extractor.getCommandLine(),
+                                 extractor.getVmName(), extractor.getVmInfo(), extractor.getVmVersion(), extractor.getVmArguments(),
+                                 properties, environment, loadedNativeLibraries, userInfo.getUid(), userInfo.getUsername());
+        return info;
+    }
+
+    private void sendStoppedVM(Integer vmPid, MonitoredHost host) throws URISyntaxException, MonitorException {
+        
+        VmIdentifier resolvedVmID = host.getHostIdentifier().resolve(new VmIdentifier(vmPid.toString()));
+        if (resolvedVmID != null && monitoredVms.containsKey(vmPid)) {
+            Pair<String, MonitoredVm> vmData = monitoredVms.remove(vmPid);
+            
+            String vmId = vmData.getFirst();
+            notifier.notifyVmStatusChange(Status.VM_STOPPED, vmId, vmPid);
+
+            long stopTime = System.currentTimeMillis();
+            vmInfoDAO.putVmStoppedTime(writerId.getWriterID(), vmId, stopTime);
+
+            MonitoredVm vm = vmData.getSecond();
+            vm.detach();
+        }
+    }
+
+    /*
+     * For testing purposes only.
+     */
+    Map<Integer, Pair<String, MonitoredVm>> getMonitoredVms() {
+        return monitoredVms;
+    }
+    
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/VMMonitorBackend.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal;
+
+import com.redhat.thermostat.backend.Backend;
+import com.redhat.thermostat.backend.BaseBackend;
+import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder;
+import com.redhat.thermostat.common.portability.ProcessUserInfoBuilderFactory;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.jvm.overview.agent.VmBlacklist;
+import com.redhat.thermostat.jvm.overview.agent.internal.model.VmInfoDAO;
+import com.redhat.thermostat.storage.core.WriterID;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import sun.jvmstat.monitor.HostIdentifier;
+import sun.jvmstat.monitor.MonitorException;
+import sun.jvmstat.monitor.MonitoredHost;
+
+import java.net.URISyntaxException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ */
+@Component
+@Service(value = Backend.class)
+public class VMMonitorBackend extends BaseBackend {
+    private static final Logger logger = LoggingUtils.getLogger(VMMonitorBackend.class);
+
+    @Reference
+    private VmInfoDAO vmInfoDAO;
+
+    private VmStatusChangeNotifier notifier;
+
+    @Reference
+    private WriterID writerId;
+
+    @Reference
+    private VmBlacklist blacklist;
+
+    private volatile boolean active;
+
+    private MonitoredHost host;
+    private JvmStatHostListener hostListener;
+
+    public VMMonitorBackend() {
+        super("VM Basic Monitor Backend",
+              "Monitor the system for JVM processes",
+              "Red Hat, Inc.",
+              "0.1");
+    }
+
+    @Activate
+    private void _activate_(BundleContext context) {
+        notifier = new VmStatusChangeNotifier(context);
+        notifier.start();
+    }
+
+    @Deactivate
+    private void _deactivate_() {
+        notifier.stop();
+    }
+
+    @Override
+    public synchronized boolean activate() {
+        try {
+            ProcessUserInfoBuilder userInfoBuilder = ProcessUserInfoBuilderFactory.createBuilder();
+            hostListener = new JvmStatHostListener(vmInfoDAO, notifier,
+                                                   userInfoBuilder, writerId, blacklist);
+            HostIdentifier hostId = new HostIdentifier((String) null);
+            host = MonitoredHost.getMonitoredHost(hostId);
+            host.addHostListener(hostListener);
+            active = true;
+
+        } catch (MonitorException | URISyntaxException me) {
+            logger.log(Level.WARNING, "problems with connecting jvmstat to local machine", me);
+        }
+
+        return active;
+    }
+
+    @Override
+    public synchronized boolean deactivate() {
+        try {
+            host.removeHostListener(hostListener);
+            active = false;
+        } catch (MonitorException me) {
+            logger.log(Level.INFO, "something went wrong in jvmstat's listening to this host");
+        }
+
+        return !active;
+    }
+
+    @Override
+    public synchronized boolean isActive() {
+        return active;
+    }
+
+    @Override
+    public int getOrderValue() {
+        return ORDER_DEFAULT_GROUP;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/VmBlacklistImpl.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import com.redhat.thermostat.common.Filter;
+import com.redhat.thermostat.jvm.overview.agent.VmBlacklist;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+
+@Component
+@Service(value = VmBlacklist.class)
+public class VmBlacklistImpl implements VmBlacklist {
+    
+    private final List<Filter<String>> filters;
+    
+    public VmBlacklistImpl() {
+        this.filters = new CopyOnWriteArrayList<>();
+    }
+
+    @Override
+    public void addVmFilter(Filter<String> filter) {
+        filters.add(filter);
+    }
+
+    @Override
+    public void removeVmFilter(Filter<String> filter) {
+        filters.remove(filter);
+    }
+
+    @Override
+    public boolean isBlacklisted(String mainClass) {
+        boolean result = false;
+        for (Filter<String> filter : filters) {
+            if (filter.matches(mainClass)) {
+                result = true;
+            }
+        }
+        return result;
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/VmListenerWrapper.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.common.utils.LoggingUtils;
+
+import com.redhat.thermostat.jvm.overview.agent.VmUpdate;
+import com.redhat.thermostat.jvm.overview.agent.VmUpdateException;
+import com.redhat.thermostat.jvm.overview.agent.VmUpdateListener;
+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;
+
+public class VmListenerWrapper implements VmListener {
+    
+    private static final Logger logger = LoggingUtils.getLogger(VmListenerWrapper.class);
+    // Threshold until this listener gets removed from the JVM in case of it throwing
+    // exceptions on countersUpdated()
+    private static final int EXCEPTION_THRESHOLD = 10;
+    private final VmUpdateListener listener;
+    private final MonitoredVm vm;
+    private final VmUpdate update;
+    private int exceptionCount;
+
+    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");
+        }
+        try {
+            listener.countersUpdated(update);
+        } catch (Throwable t) {
+            handleListenerException(t);
+        }
+    }
+    
+    private void handleListenerException(Throwable t) {
+        final String listenerName = listener.getClass().getName();
+        if (exceptionCount < EXCEPTION_THRESHOLD) {
+            logger.log(Level.INFO, "VM listener " + listenerName + " threw an exception", t);
+            exceptionCount++;
+        } else {
+            logger.fine("Removing bad listener " + listenerName + " due to too many repeated exceptions.");
+            try {
+                vm.removeVmListener(this);
+            } catch (MonitorException e) {
+                // ignore remove failures for bad listeners
+            }
+        }
+    }
+
+    @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.
+     */
+    public VmUpdateListener getVmUpdateListener() {
+        return listener;
+    }
+    
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/VmStatusChangeNotifier.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+
+import com.redhat.thermostat.jvm.overview.agent.VmStatusListener;
+import com.redhat.thermostat.jvm.overview.agent.VmStatusListener.Status;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * Notifies any and all {@link com.redhat.thermostat.jvm.overview.agent.VmStatusListener} registered as OSGi Services
+ * about VM status changes: {@link com.redhat.thermostat.jvm.overview.agent.VmStatusListener.Status#VM_STARTED} and
+ * {@link com.redhat.thermostat.jvm.overview.agent.VmStatusListener.Status#VM_STOPPED}.
+ * <p>
+ * Any listeners registered after a {@link com.redhat.thermostat.jvm.overview.agent.VmStatusListener.Status#VM_STARTED}
+ * was delivered receive a {@link com.redhat.thermostat.jvm.overview.agent.VmStatusListener.Status#VM_ACTIVE} event
+ * instead as an indication that a VM was started at some unknown point
+ * previously.
+ */
+public class VmStatusChangeNotifier {
+
+    private final Object listenerLock = new Object();
+    private final Map<Integer, String> activePids;
+    private final Map<VmStatusListener, Set<Integer>> listeners = new ConcurrentHashMap<>();
+
+    private final ServiceTracker tracker;
+
+    public VmStatusChangeNotifier(BundleContext bundleContext) {
+        this.activePids = new HashMap<>();
+
+        tracker = new ServiceTracker(bundleContext, VmStatusListener.class, null) {
+            @Override
+            public VmStatusListener addingService(ServiceReference reference) {
+                VmStatusListener listener = (VmStatusListener) super.addingService(reference);
+
+                synchronized (listenerLock) {
+                    Set<Integer> notifiedAbout = new TreeSet<>();
+                    for (Entry<Integer, String> entry : activePids.entrySet()) {
+                        Integer pid = entry.getKey();
+                        listener.vmStatusChanged(Status.VM_ACTIVE, entry.getValue(), pid);
+                        notifiedAbout.add(pid);
+                    }
+
+                    listeners.put(listener, notifiedAbout);
+                }
+
+                return listener;
+            }
+
+            @Override
+            public void removedService(ServiceReference reference,
+                    Object service) {
+                VmStatusListener listener = (VmStatusListener) service;
+                listeners.remove(listener);
+                super.removedService(reference, service);
+            }
+        };
+    }
+
+    public void start() {
+        tracker.open();
+    }
+
+    public void stop() {
+        tracker.close();
+    }
+
+    /**
+     * Notify all registered listeners about a Vm status change.
+     *
+     * @param newStatus either {@link VmStatusListener.Status#VM_STARTED} or
+     * {@link VmStatusListener.Status#VM_STOPPED}
+     * @param vmId unique identifier for the VM
+     * @param pid process ID for the VM
+     */
+    public void notifyVmStatusChange(VmStatusListener.Status newStatus, String vmId, int pid) {
+        if (newStatus == Status.VM_ACTIVE) {
+            throw new IllegalArgumentException("Dont pass in " + Status.VM_ACTIVE + ", that will be handled automatically");
+        }
+
+        synchronized (listenerLock) {
+            for (Entry<VmStatusListener, Set<Integer>> entry : listeners.entrySet()) {
+                entry.getKey().vmStatusChanged(newStatus, vmId, pid);
+                entry.getValue().add(pid);
+            }
+
+            if (newStatus == Status.VM_STARTED) {
+                activePids.put(pid, vmId);
+            } else {
+                activePids.remove(pid);
+            }
+        }
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/VmUpdateImpl.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal;
+
+import com.redhat.thermostat.jvm.overview.agent.VmUpdate;
+import com.redhat.thermostat.jvm.overview.agent.VmUpdateException;
+import sun.jvmstat.monitor.Monitor;
+
+public class VmUpdateImpl implements VmUpdate {
+    
+    private VmListenerWrapper wrapper;
+
+    public 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;
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/model/InfoBuilderFactory.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal.model;
+
+import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder;
+import com.redhat.thermostat.common.portability.UserNameUtil;
+
+/**
+ * Allows callers to access OS-specific builders portably
+ */
+public interface InfoBuilderFactory {
+
+    InfoBuilderFactory INSTANCE = new InfoBuilderFactoryImpl();
+    ProcessEnvironmentBuilder createProcessEnvironmentBuilder();
+    ProcessUserInfoBuilder createProcessUserInfoBuilder(final UserNameUtil userNameUtil);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/model/InfoBuilderFactoryImpl.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal.model;
+
+import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder;
+import com.redhat.thermostat.common.portability.ProcessUserInfoBuilderFactory;
+import com.redhat.thermostat.common.portability.UserNameUtil;
+import com.redhat.thermostat.common.portability.linux.ProcDataSource;
+
+/**
+ * Allows callers to access Windows-specific builders portably
+ */
+public class InfoBuilderFactoryImpl implements InfoBuilderFactory {
+
+    public InfoBuilderFactoryImpl() {
+    }
+
+    public ProcessEnvironmentBuilder createProcessEnvironmentBuilder() {
+        return new ProcessEnvironmentBuilderImpl();
+    }
+
+    public ProcessUserInfoBuilder createProcessUserInfoBuilder(final UserNameUtil userNameUtil) {
+        return ProcessUserInfoBuilderFactory.createBuilder(new ProcDataSource(), userNameUtil);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/model/ProcessEnvironmentBuilder.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal.model;
+
+import java.util.Map;
+
+/**
+ * Interface for fetching a process environment
+ * An environment is represented as a map of name-value pairs
+ */
+public interface ProcessEnvironmentBuilder {
+    Map<String,String> build(int pid);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/model/ProcessEnvironmentBuilderImpl.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal.model;
+
+import com.redhat.thermostat.common.portability.PortableProcess;
+import com.redhat.thermostat.common.portability.PortableProcessFactory;
+
+import java.util.Map;
+
+/**
+ * Build process environment information via portable helper classes
+ */
+public class ProcessEnvironmentBuilderImpl implements ProcessEnvironmentBuilder {
+
+    private final PortableProcess helper;
+
+    public ProcessEnvironmentBuilderImpl() {
+        this(PortableProcessFactory.getInstance());
+    }
+
+    public ProcessEnvironmentBuilderImpl(PortableProcess wh) {
+        helper = wh;
+    }
+
+    @Override
+    public Map<String, String> build(int pid) {
+        return helper.getEnvironment(pid);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/model/VmInfoDAO.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal.model;
+
+import java.util.Set;
+
+import com.redhat.thermostat.annotations.Service;
+import com.redhat.thermostat.jvm.overview.agent.model.VmId;
+import com.redhat.thermostat.jvm.overview.agent.model.VmInfo;
+import com.redhat.thermostat.storage.core.AgentId;
+
+@Service
+public interface VmInfoDAO {
+
+    /** @return {@code null} if no information can be found */
+    VmInfo getVmInfo(VmId id);
+
+    /**
+     *
+     * @param agentId The id of host to get the VM(s) for.
+     * @return A set of the VmId(s).
+     */
+    Set<VmId> getVmIds(AgentId agentId);
+
+    void putVmInfo(VmInfo info);
+
+    void putVmStoppedTime(String agentId, String vmId, long since);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/model/VmInfoDAOImpl.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal.model;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Collections;
+
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.jvm.overview.agent.internal.model.VmInfoTypeAdapter.VmInfoUpdateTypeAdapter;
+import com.redhat.thermostat.jvm.overview.agent.model.VmId;
+import com.redhat.thermostat.jvm.overview.agent.model.VmInfo;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.HttpContentResponse;
+import org.eclipse.jetty.client.HttpRequest;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.client.util.StringContentProvider;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpStatus;
+
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.storage.core.AgentId;
+
+@Component
+@Service(VmInfoDAO.class)
+public class VmInfoDAOImpl implements VmInfoDAO {
+    
+    private final Logger logger = LoggingUtils.getLogger(VmInfoDAOImpl.class);
+    
+    private static final String GATEWAY_URL = "http://localhost:26000/api/v100"; // TODO configurable
+    private static final String GATEWAY_PATH = "/vm-info/systems/*/agents/";
+    private static final String GATEWAY_PATH_JVM_SUFFIX = "/jvms/";
+    private static final String CONTENT_TYPE = "application/json";
+    
+    private final HttpHelper httpHelper;
+    private final JsonHelper jsonHelper;
+
+    public VmInfoDAOImpl() throws Exception {
+        this(new HttpHelper(new HttpClient()), new JsonHelper(new VmInfoTypeAdapter(), new VmInfoUpdateTypeAdapter()));
+    }
+
+    VmInfoDAOImpl(HttpHelper httpHelper, JsonHelper jsonHelper) throws Exception {
+        this.jsonHelper = jsonHelper;
+        this.httpHelper = httpHelper;
+        
+        this.httpHelper.startClient();
+    }
+
+    @Override
+    public VmInfo getVmInfo(final VmId id) {
+        return null; // TODO Remove once VM Id completer is removed
+    }
+
+    @Override
+    public Set<VmId> getVmIds(AgentId agentId) {
+        return Collections.emptySet(); // TODO Remove once VM Id completer is removed
+    }
+
+    @Override
+    public void putVmInfo(final VmInfo info) {
+        try {
+            // Encode as JSON and send as POST request
+            String json = jsonHelper.toJson(Arrays.asList(info));
+            StringContentProvider provider = httpHelper.createContentProvider(json);
+            
+            String url = getAddURL(info.getAgentId());
+            Request httpRequest = httpHelper.newRequest(url);
+            httpRequest.method(HttpMethod.POST);
+            httpRequest.content(provider, CONTENT_TYPE);
+            sendRequest(httpRequest);
+        } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) {
+           logger.log(Level.WARNING, "Failed to send JVM information to web gateway", e);
+        }
+    }
+
+    @Override
+    public void putVmStoppedTime(final String agentId, final String vmId, final long timestamp) {
+        try {
+            // Encode as JSON and send as PUT request
+            VmInfoUpdate update = new VmInfoUpdate(timestamp);
+            String json = jsonHelper.toJson(update);
+            StringContentProvider provider = httpHelper.createContentProvider(json);
+            
+            String url = getUpdateURL(agentId, vmId);
+            Request httpRequest = httpHelper.newRequest(url);
+            httpRequest.method(HttpMethod.PUT);
+            httpRequest.content(provider, CONTENT_TYPE);
+            sendRequest(httpRequest);
+        } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) {
+           logger.log(Level.WARNING, "Failed to send JVM information update to web gateway", e);
+        }
+    }
+
+    private void sendRequest(Request httpRequest)
+            throws InterruptedException, TimeoutException, ExecutionException, IOException {
+        ContentResponse resp = httpRequest.send();
+        int status = resp.getStatus();
+        if (status != HttpStatus.OK_200) {
+            throw new IOException("Gateway returned HTTP status " + String.valueOf(status) + " - " + resp.getReason());
+        }
+    }
+    
+    private String getAddURL(String agentId) {
+        StringBuilder builder = buildURL(agentId);
+        return builder.toString();
+    }
+
+    private StringBuilder buildURL(String agentId) {
+        StringBuilder builder = new StringBuilder();
+        builder.append(GATEWAY_URL);
+        builder.append(GATEWAY_PATH);
+        builder.append(agentId);
+        return builder;
+    }
+    
+    private String getUpdateURL(String agentId, String vmId) {
+        StringBuilder builder = buildURL(agentId);
+        builder.append(GATEWAY_PATH_JVM_SUFFIX);
+        builder.append(vmId);
+        return builder.toString();
+    }
+    
+    static class VmInfoUpdate {
+        
+        private final long stoppedTime;
+        
+        VmInfoUpdate(long stoppedTime) {
+           this.stoppedTime = stoppedTime;
+        }
+        
+        long getStoppedTime() {
+            return stoppedTime;
+        }
+    }
+    
+    
+    // For testing purposes
+    static class JsonHelper {
+        
+        private final VmInfoTypeAdapter typeAdapter;
+        private final VmInfoUpdateTypeAdapter updateTypeAdapter;
+        
+        public JsonHelper(VmInfoTypeAdapter typeAdapter, VmInfoUpdateTypeAdapter updateTypeAdapter) {
+            this.typeAdapter = typeAdapter;
+            this.updateTypeAdapter = updateTypeAdapter;
+        }
+        
+        String toJson(List<VmInfo> infos) throws IOException {
+            return typeAdapter.toJson(infos);
+        }
+        
+        String toJson(VmInfoUpdate update) throws IOException {
+            return updateTypeAdapter.toJson(update);
+        }
+        
+    }
+    
+    // For testing purposes
+    static class HttpHelper {
+        
+        private final HttpClient httpClient;
+
+        HttpHelper(HttpClient httpClient) {
+            this.httpClient = httpClient;
+        }
+        
+        void startClient() throws Exception {
+            httpClient.start();
+        }
+        
+        StringContentProvider createContentProvider(String content) {
+            return new StringContentProvider(content);
+        }
+        
+        Request newRequest(String url) {
+            return new MockRequest(httpClient, URI.create(url));
+        }
+        
+    }
+    
+    // FIXME This class should be removed when the web gateway has a microservice for this DAO
+    private static class MockRequest extends HttpRequest {
+
+        MockRequest(HttpClient client, URI uri) {
+            super(client, uri);
+        }
+        
+        @Override
+        public ContentResponse send() throws InterruptedException, TimeoutException, ExecutionException {
+            return new MockResponse();
+        }
+        
+    }
+    
+    // FIXME This class should be removed when the web gateway has a microservice for this DAO
+    private static class MockResponse extends HttpContentResponse {
+
+        MockResponse() {
+            super(null, null, null);
+        }
+        
+        @Override
+        public int getStatus() {
+            return HttpStatus.OK_200;
+        }
+        
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/model/VmInfoTypeAdapter.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal.model;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+import com.redhat.thermostat.jvm.overview.agent.internal.model.VmInfoDAOImpl.VmInfoUpdate;
+import com.redhat.thermostat.jvm.overview.agent.model.VmInfo;
+
+public class VmInfoTypeAdapter extends TypeAdapter<List<VmInfo>> {
+    
+    private static final String AGENT_ID = "agentId";
+    private static final String VM_ID = "vmId";
+    private static final String VM_PID = "vmPid";
+    private static final String JAVA_VERSION = "javaVersion";
+    private static final String JAVA_HOME = "javaHome";
+    private static final String MAIN_CLASS = "mainClass";
+    private static final String JAVA_COMMAND_LINE = "javaCommandLine";
+    private static final String VM_ARGUMENTS = "vmArguments";
+    private static final String VM_NAME = "vmName";
+    private static final String VM_INFO = "vmInfo";
+    private static final String VM_VERSION = "vmVersion";
+    private static final String PROPERTIES_AS_ARRAY = "propertiesAsArray";
+    private static final String ENVIRONMENT_AS_ARRAY = "environmentAsArray";
+    private static final String LOADED_NATIVE_LIBRARIES = "loadedNativeLibraries";
+    private static final String START_TIME_STAMP = "startTimeStamp";
+    private static final String STOP_TIME_STAMP = "stopTimeStamp";
+    private static final String UID = "uid";
+    private static final String USERNAME = "username";
+    private static final String TYPE_LONG = "$numberLong";
+    private static final String KEY = "key";
+    private static final String VALUE = "value";
+    
+    @Override
+    public void write(JsonWriter out, List<VmInfo> value) throws IOException {
+        // Request is an array of VmInfo objects
+        out.beginArray();
+        
+        for (VmInfo info : value) {
+            writeVmInfo(out, info);
+        }
+        
+        out.endArray();
+    }
+
+    private void writeVmInfo(JsonWriter out, VmInfo info) throws IOException {
+        out.beginObject();
+        
+        // Write each field of VmInfo as part of a JSON object
+        out.name(AGENT_ID);
+        out.value(info.getAgentId());
+        out.name(VM_ID);
+        out.value(info.getVmId());
+        out.name(VM_PID);
+        out.value(info.getVmPid());
+        out.name(START_TIME_STAMP);
+        writeLong(out, info.getStartTimeStamp());
+        out.name(STOP_TIME_STAMP);
+        writeLong(out, info.getStopTimeStamp());
+        out.name(JAVA_VERSION);
+        out.value(info.getJavaVersion());
+        out.name(JAVA_HOME);
+        out.value(info.getJavaHome());
+        out.name(MAIN_CLASS);
+        out.value(info.getMainClass());
+        out.name(JAVA_COMMAND_LINE);
+        out.value(info.getJavaCommandLine());
+        out.name(VM_NAME);
+        out.value(info.getVmName());
+        out.name(VM_ARGUMENTS);
+        out.value(info.getVmArguments());
+        out.name(VM_INFO);
+        out.value(info.getVmInfo());
+        out.name(VM_VERSION);
+        out.value(info.getVmVersion());
+        out.name(PROPERTIES_AS_ARRAY);
+        writeStringMap(out, info.getProperties());
+        out.name(ENVIRONMENT_AS_ARRAY);
+        writeStringMap(out, info.getEnvironment());
+        out.name(LOADED_NATIVE_LIBRARIES);
+        writeStringArray(out, info.getLoadedNativeLibraries());
+        out.name(UID);
+        writeLong(out, info.getUid());
+        out.name(USERNAME);
+        out.value(info.getUsername());
+        
+        out.endObject();
+    }
+    
+    private void writeStringMap(JsonWriter out, Map<String, String> map) throws IOException {
+        // Write contents of Map as an array of JSON objects
+        out.beginArray();
+        
+        Set<Entry<String, String>> entries = map.entrySet();
+        for (Map.Entry<String, String> entry : entries) {
+            // Create JSON object with key and value labeled as JSON names
+            out.beginObject();
+            out.name(KEY);
+            out.value(entry.getKey());
+            out.name(VALUE);
+            out.value(entry.getValue());
+            out.endObject();
+        }
+        
+        out.endArray();
+    }
+    
+    private void writeStringArray(JsonWriter out, String[] array) throws IOException {
+        // Write String[] as JSON array
+        out.beginArray();
+        
+        for (String item : array) {
+            out.value(item);
+        }
+        
+        out.endArray();
+    }
+    
+    private static void writeLong(JsonWriter out, long value) throws IOException {
+        // Write MongoDB representation of a Long
+        out.beginObject();
+        out.name(TYPE_LONG);
+        out.value(String.valueOf(value));
+        out.endObject();
+    }
+
+    @Override
+    public List<VmInfo> read(JsonReader in) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+    
+    static class VmInfoUpdateTypeAdapter extends TypeAdapter<VmInfoUpdate> {
+
+        private static final String SET = "set";
+        
+        @Override
+        public void write(JsonWriter out, VmInfoUpdate value) throws IOException {
+            // List fields to update as part of a JSON object with name "set"
+            out.beginObject();
+            out.name(SET);
+            
+            out.beginObject();
+            out.name(STOP_TIME_STAMP);
+            writeLong(out, value.getStoppedTime());
+            out.endObject();
+            
+            out.endObject();
+        }
+
+        @Override
+        public VmInfoUpdate read(JsonReader in) throws IOException {
+            throw new UnsupportedOperationException();
+        }
+        
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/model/HostsVMsLoader.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.model;
+
+import com.redhat.thermostat.storage.core.HostRef;
+
+import java.util.Collection;
+
+
+/**
+ * Provides a way to load the current hosts and VMs.
+ */
+public interface HostsVMsLoader {
+
+    Collection<HostRef> getHosts();
+    Collection<VmRef> getVMs(HostRef host);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/model/VmId.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.model;
+
+import com.redhat.thermostat.storage.core.Id;
+
+/**
+ * This class uniquely identifies a Java Virtual Machine
+ *
+ */
+public class VmId extends Id {
+
+    public VmId(String id) {
+        super(id);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/model/VmInfo.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,390 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.model;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import com.redhat.thermostat.storage.core.Entity;
+import com.redhat.thermostat.storage.core.Persist;
+import com.redhat.thermostat.storage.model.AgentInformation;
+import com.redhat.thermostat.storage.model.BasePojo;
+import com.redhat.thermostat.storage.model.Pojo;
+
+@Entity
+public class VmInfo extends BasePojo {
+
+    public enum AliveStatus {
+        RUNNING,
+        EXITED,
+        /**
+         * We don't know what the status of this VM is. Possible cause: agent
+         * was shut down before the VM was.
+         */
+        UNKNOWN,
+    }
+
+    @Entity
+    public static class KeyValuePair implements Pojo {
+    
+        private String key;
+        private String value;
+
+        public KeyValuePair() {
+            this(null, null);
+        }
+
+        public KeyValuePair(String key, String value) {
+            this.key = key;
+            this.value = value;
+        }
+
+        @Persist
+        public String getKey() {
+            return key;
+        }
+
+        @Persist
+        public void setKey(String key) {
+            this.key = key;
+        }
+
+        @Persist
+        public String getValue() {
+            return value;
+        }
+
+        @Persist
+        public void setValue(String value) {
+            this.value = value;
+        }
+
+        
+    }
+
+    private String vmId;
+    private int vmPid = 0;
+    private long startTime = System.currentTimeMillis();
+    private long stopTime = Long.MIN_VALUE;
+    private String javaVersion = "unknown";
+    private String javaHome = "unknown";
+    private String javaCommandLine = "unknown";
+    private String mainClass = "unknown";
+    private String vmName = "unknown";
+    private String vmInfo = "unknown";
+    private String vmVersion = "unknown";
+    private String vmArguments = "unknown";
+    private Map<String, String> properties = new HashMap<String, String>();
+    private Map<String, String> environment = new HashMap<String, String>();
+    private String[] loadedNativeLibraries;
+    private long uid;
+    private String username;
+
+    public VmInfo() {
+        /* use defaults */
+        super(null);
+    }
+
+    public VmInfo(String writerId, String vmId, int vmPid, long startTime, long stopTime,
+            String javaVersion, String javaHome,
+            String mainClass, String commandLine,
+            String vmName, String vmInfo, String vmVersion, String vmArguments,
+            Map<String, String> properties, Map<String, String> environment, String[] loadedNativeLibraries,
+            long uid, String username) {
+        super(writerId);
+        this.vmId = vmId;
+        this.vmPid = vmPid;
+        this.startTime = startTime;
+        this.stopTime = stopTime;
+        this.javaVersion = javaVersion;
+        this.javaHome = javaHome;
+        this.mainClass = mainClass;
+        this.javaCommandLine = commandLine;
+        this.vmName = vmName;
+        this.vmInfo = vmInfo;
+        this.vmVersion = vmVersion;
+        this.vmArguments = vmArguments;
+        this.properties = properties;
+        this.environment = environment;
+        this.loadedNativeLibraries = loadedNativeLibraries;
+        this.uid = uid;
+        this.username = username;
+    }
+
+    @Persist
+    public String getVmId() {
+        return vmId;
+    }
+
+    @Persist
+    public void setVmId(String vmId) {
+        this.vmId = vmId;
+    }
+
+    @Persist
+    public int getVmPid() {
+        return vmPid;
+    }
+
+    @Persist
+    public void setVmPid(int vmPid) {
+        this.vmPid = vmPid;
+    }
+
+    @Persist
+    public long getStartTimeStamp() {
+        return startTime;
+    }
+
+    @Persist
+    public void setStartTimeStamp(long startTime) {
+        this.startTime = startTime;
+    }
+
+    @Persist
+    public long getStopTimeStamp() {
+        return stopTime;
+    }
+
+    @Persist
+    public void setStopTimeStamp(long stopTime) {
+        this.stopTime = stopTime;
+    }
+
+    @Persist
+    public String getJavaVersion() {
+        return javaVersion;
+    }
+
+    @Persist
+    public void setJavaVersion(String javaVersion) {
+        this.javaVersion = javaVersion;
+    }
+
+    @Persist
+    public String getJavaHome() {
+        return javaHome;
+    }
+
+    @Persist
+    public void setJavaHome(String javaHome) {
+        this.javaHome = javaHome;
+    }
+
+    /**
+     * If java is invoked as {@code java -jar foo.jar}, then the main class name
+     * is {@code foo.jar}.
+     */
+    @Persist
+    public String getMainClass() {
+        return mainClass;
+    }
+
+    @Persist
+    public void setMainClass(String mainClass) {
+        this.mainClass = mainClass;
+    }
+
+    @Persist
+    public String getJavaCommandLine() {
+        return javaCommandLine;
+    }
+
+    @Persist
+    public void setJavaCommandLine(String javaCommandLine) {
+        this.javaCommandLine = javaCommandLine;
+    }
+
+    @Persist
+    public String getVmName() {
+        return vmName;
+    }
+
+    @Persist
+    public void setVmName(String vmName) {
+        this.vmName = vmName;
+    }
+
+    @Persist
+    public String getVmArguments() {
+        return vmArguments;
+    }
+
+    @Persist
+    public void setVmArguments(String vmArguments) {
+        this.vmArguments = vmArguments;
+    }
+
+    @Persist
+    public String getVmInfo() {
+        return vmInfo;
+    }
+
+    @Persist
+    public void setVmInfo(String vmInfo) {
+        this.vmInfo = vmInfo;
+    }
+
+    @Persist
+    public String getVmVersion() {
+        return vmVersion;
+    }
+
+    @Persist
+    public void setVmVersion(String vmVersion) {
+        this.vmVersion = vmVersion;
+    }
+
+    /**
+     * @deprecated This can incorrectly show a VM as running when the actual
+     *             status is unknown. Use {@link #isAlive(AgentInformation)}
+     *             instead.
+     */
+    @Deprecated
+    public boolean isAlive() {
+        return getStartTimeStamp() > getStopTimeStamp();
+    }
+
+    public AliveStatus isAlive(AgentInformation agentInfo) {
+        if (agentInfo.isAlive()) {
+            return (isAlive() ? AliveStatus.RUNNING : AliveStatus.EXITED);
+        } else {
+            return (isAlive() ? AliveStatus.UNKNOWN: AliveStatus.EXITED);
+        }
+    }
+
+    public Map<String, String> getProperties() {
+        return properties;
+    }
+
+    public void setProperties(Map<String, String> properties) {
+        this.properties = properties;
+    }
+
+    @Persist
+    public KeyValuePair[] getPropertiesAsArray() {
+        return getMapAsArray(properties);
+    }
+
+    @Persist
+    public void setPropertiesAsArray(KeyValuePair[] properties) {
+        this.properties = getArrayAsMap(properties);
+    }
+
+    public Map<String, String> getEnvironment() {
+        return environment;
+    }
+
+    public void setEnvironment(Map<String, String> environment) {
+        this.environment = environment;
+    }
+
+    @Persist
+    public KeyValuePair[] getEnvironmentAsArray() {
+        return getMapAsArray(environment);
+    }
+
+    @Persist
+    public void setEnvironmentAsArray(KeyValuePair[] environment) {
+        this.environment = getArrayAsMap(environment);
+    }
+
+    private KeyValuePair[] getMapAsArray(Map<String, String> map) {
+        if (map == null) {
+            return null;
+        }
+        Set<String> keys = map.keySet();
+        KeyValuePair[] tuples = new KeyValuePair[keys.size()];
+        int i = 0;
+        for (String key: keys) {
+            tuples[i] = new KeyValuePair(key, map.get(key));
+            i++;
+        }
+        return tuples;
+    }
+
+    private Map<String,String> getArrayAsMap(KeyValuePair[] tuples) {
+        if (tuples == null) {
+            return null;
+        }
+        Map<String,String> map = new HashMap<>();
+        for (KeyValuePair tuple : tuples) {
+            map.put(tuple.getKey(), tuple.getValue());
+        }
+        return map;
+    }
+
+    @Persist
+    public String[] getLoadedNativeLibraries() {
+        return loadedNativeLibraries;
+    }
+
+    @Persist
+    public void setLoadedNativeLibraries(String[] loadedNativeLibraries) {
+        this.loadedNativeLibraries = loadedNativeLibraries;
+    }
+    
+    /**
+     * Returns the system user id for the owner of this JVM process,
+     * or -1 if an owner could not be found.
+     */
+    @Persist
+    public long getUid() {
+        return uid;
+    }
+    
+    @Persist
+    public void setUid(long uid) {
+        this.uid = uid;
+    }
+    
+    /**
+     * Returns the system user name for the owner of this JVM process,
+     * or null if an owner could not be found.
+     */
+    @Persist
+    public String getUsername() {
+        return username;
+    }
+    
+    @Persist
+    public void setUsername(String username) {
+        this.username = username;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/model/VmLatestPojoListGetter.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.model;
+
+import java.util.List;
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.storage.core.AgentId;
+import com.redhat.thermostat.storage.core.Category;
+import com.redhat.thermostat.storage.core.Key;
+import com.redhat.thermostat.storage.model.TimeStampedPojo;
+
+/**
+ * Get a {@link List} of {@link TimeStampedPojo}s newer than a given time stamp.
+ *
+ * @see VmTimeIntervalPojoListGetter
+ */
+public class VmLatestPojoListGetter<T extends TimeStampedPojo> {
+
+    public static final String VM_LATEST_QUERY_FORMAT = "QUERY %s WHERE '"
+            + Key.AGENT_ID.getName() + "' = ?s AND '"
+            + Key.VM_ID.getName() + "' = ?s AND '"
+            + Key.TIMESTAMP.getName() + "' > ?l SORT '"
+            + Key.TIMESTAMP.getName() + "' DSC";
+    private static final Logger logger = LoggingUtils.getLogger(VmLatestPojoListGetter.class);
+
+    private final Category<T> cat;
+    private final String queryLatest;
+
+    public VmLatestPojoListGetter(Category<T> cat) {
+        this.cat = cat;
+        this.queryLatest = String.format(VM_LATEST_QUERY_FORMAT, cat.getName());
+    }
+
+    /**
+     * @deprecated use {@link #getLatest(AgentId, VmId, long)}
+     */
+    @Deprecated
+    public List<T> getLatest(VmRef vmRef, long since) {
+        return getLatest(new AgentId(vmRef.getHostRef().getAgentId()), new VmId(vmRef.getVmId()), since);
+    }
+
+    public List<T> getLatest(final AgentId agentId, final VmId vmId, final long since) {
+        return null;
+    }
+
+    // package private for tests
+    String getQueryLatestDesc() {
+        return queryLatest;
+    }
+
+    public Logger getLogger() {
+        return logger;
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/model/VmRef.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.model;
+
+import com.redhat.thermostat.storage.core.HostRef;
+import com.redhat.thermostat.storage.core.Ref;
+
+public class VmRef implements Ref {
+
+    private final HostRef hostRef;
+    private final String id;
+    private final Integer pid;
+    private final String name;
+
+    public VmRef(HostRef hostRef, String id, Integer pid, String name) {
+        this.hostRef = hostRef;
+        this.id = id;
+        this.pid = pid;
+        this.name = name;
+    }
+
+    public VmRef(HostRef hostRef, VmInfo vmInfo) {
+        this.hostRef = hostRef;
+        this.id = vmInfo.getVmId();
+        this.pid = vmInfo.getVmPid();
+        this.name = vmInfo.getMainClass();
+    }
+
+    @Override
+    public String toString() {
+        return name;
+    }
+
+    public HostRef getHostRef() {
+        return hostRef;
+    }
+    
+    public String getVmId() {
+        return id;
+    }
+    
+    public Integer getPid() {
+        return pid;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (obj == this) {
+            return true;
+        }
+        if (obj.getClass() != this.getClass()) {
+            return false;
+        }
+        VmRef other = (VmRef) obj;
+        if (equals(this.hostRef, other.hostRef)
+                && equals(this.id, other.id)
+                && equals(this.pid, other.pid) && equals(this.name, other.name)) {
+            return true;
+        }
+        return false;
+    }
+
+    private static boolean equals(Object obj1, Object obj2) {
+        return (obj1 == null && obj2 == null) || (obj1 != null && obj1.equals(obj2));
+    }
+
+    @Override
+    public int hashCode() {
+        return id.hashCode();
+    }
+
+    @Override
+    public String getStringID() {
+        return id;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/model/VmTimeIntervalPojoListGetter.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.model;
+
+import java.util.List;
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.storage.core.AgentId;
+import com.redhat.thermostat.storage.core.Category;
+import com.redhat.thermostat.storage.core.Key;
+import com.redhat.thermostat.storage.model.TimeStampedPojo;
+
+/**
+ * Get a {@link List} of {@link TimeStampedPojo}s in a given time interval
+ * range.
+ *
+ * @see VmLatestPojoListGetter
+ */
+public class VmTimeIntervalPojoListGetter<T extends TimeStampedPojo>  {
+
+    // The query for VmTimeIntervalPojoListGetter should query for since <= timestamp < to
+    // in order not to miss data for multiple consecutive queries of the form [a, b), [b, c), ...
+    // If the query were since < timestamp < to then queries of (a, b), (b, c), ... would
+    // result in missed data at the endpoints (b, ...)
+    public static final String VM_INTERVAL_QUERY_FORMAT = "QUERY %s WHERE '"
+            + Key.AGENT_ID.getName() + "' = ?s AND '"
+            + Key.VM_ID.getName() + "' = ?s AND '"
+            + Key.TIMESTAMP.getName() + "' >= ?l AND '"
+            + Key.TIMESTAMP.getName() + "' < ?l SORT '"
+            + Key.TIMESTAMP.getName() + "' DSC";
+
+    private static final Logger logger = LoggingUtils.getLogger(VmTimeIntervalPojoListGetter.class);
+
+    private final Category<T> cat;
+    private final String query;
+
+    public VmTimeIntervalPojoListGetter(Category<T> cat) {
+        this.cat = cat;
+        this.query = String.format(VM_INTERVAL_QUERY_FORMAT, cat.getName());
+    }
+
+    /**
+     * @deprecated use {@link #getLatest(AgentId, VmId, long, long)}
+     */
+    @Deprecated
+    public List<T> getLatest(final VmRef vmRef, final long since, final long to) {
+        return getLatest(new AgentId(vmRef.getHostRef().getAgentId()), new VmId(vmRef.getVmId()), since, to);
+    }
+
+    public List<T> getLatest(final AgentId agentId, final VmId vmId, final long since, final long to) {
+        return null;
+    }
+
+    // package private for tests
+    String getQueryLatestDesc() {
+        return query;
+    }
+
+    protected Logger getLogger() {
+        return logger;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/JvmStatDataExtractorTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent;
+
+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 com.redhat.thermostat.jvm.overview.agent.internal.JvmStatDataExtractor;
+import org.junit.Test;
+
+import sun.jvmstat.monitor.MonitorException;
+import sun.jvmstat.monitor.MonitoredVm;
+import sun.jvmstat.monitor.StringMonitor;
+
+public class JvmStatDataExtractorTest {
+
+    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;
+    }
+
+    @Test
+    public void testCommandLine() throws MonitorException {
+        final String MONITOR_NAME = "sun.rt.javaCommand";
+        final String MONITOR_VALUE = "command line java";
+        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        String returned = extractor.getCommandLine();
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(MONITOR_VALUE, returned);
+    }
+
+    @Test
+    public void testMainClass() throws MonitorException {
+        final String MONITOR_NAME = "sun.rt.javaCommand";
+        final String MONITOR_VALUE = "some.package.Main";
+        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        String returned = extractor.getMainClass();
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(MONITOR_VALUE, returned);
+    }
+
+    @Test
+    public void testJavaVersion() throws MonitorException {
+        final String MONITOR_NAME = "java.property.java.version";
+        final String MONITOR_VALUE = "some java version";
+        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        String returned = extractor.getJavaVersion();
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(MONITOR_VALUE, returned);
+    }
+
+    @Test
+    public void testJavaHome() throws MonitorException {
+        final String MONITOR_NAME = "java.property.java.home";
+        final String MONITOR_VALUE = "${java.home}";
+        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        String returned = extractor.getJavaHome();
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(MONITOR_VALUE, returned);
+    }
+
+    @Test
+    public void testVmName() throws MonitorException {
+        final String MONITOR_NAME = "java.property.java.vm.name";
+        final String MONITOR_VALUE = "${vm.name}";
+        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        String returned = extractor.getVmName();
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(MONITOR_VALUE, returned);
+    }
+
+    @Test
+    public void testVmInfo() throws MonitorException {
+        final String MONITOR_NAME = "java.property.java.vm.info";
+        final String MONITOR_VALUE = "${vm.info}";
+        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        String returned = extractor.getVmInfo();
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(MONITOR_VALUE, returned);
+    }
+
+    @Test
+    public void testVmVersion() throws MonitorException {
+        final String MONITOR_NAME = "java.property.java.vm.version";
+        final String MONITOR_VALUE = "${vm.version}";
+        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        String returned = extractor.getVmVersion();
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(MONITOR_VALUE, returned);
+    }
+
+    @Test
+    public void testVmArguments() throws MonitorException {
+        final String MONITOR_NAME = "java.rt.vmArgs";
+        final String MONITOR_VALUE = "${vm.arguments}";
+        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
+
+        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+        String returned = extractor.getVmArguments();
+
+        verify(vm).findByName(eq(MONITOR_NAME));
+        assertEquals(MONITOR_VALUE, returned);
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/VmIdTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent;
+
+import com.redhat.thermostat.jvm.overview.agent.model.VmId;
+import com.redhat.thermostat.storage.core.Id;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class VmIdTest {
+
+    protected Id fooId1;
+    protected Id fooId2;
+    protected Id barId;
+
+    @Before
+    public void setup() {
+        fooId1 = createId("foo");
+        fooId2 = createId("foo");
+        barId = createId("bar");
+    }
+
+    @Test
+    public void testEquals() {
+        assertTrue(fooId1.equals(fooId1));
+        assertTrue(fooId1.equals(fooId2));
+    }
+
+    @Test
+    public void testNotEquals() {
+        assertFalse(fooId1.equals(null));
+        assertFalse(fooId1.equals(barId));
+    }
+
+    @Test
+    public void testEqualsHaveIdenticalHashcode() {
+        assertEquals(fooId1, fooId2);
+
+        assertEquals(fooId1.hashCode(), fooId1.hashCode());
+        assertEquals(fooId1.hashCode(), fooId2.hashCode());
+    }
+
+    protected Id createId(String id) { return new VmId(id); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/VmListenerBackendTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import java.net.URISyntaxException;
+
+import com.redhat.thermostat.jvm.overview.agent.VmStatusListener.Status;
+import org.junit.Before;
+import org.junit.Test;
+
+import sun.jvmstat.monitor.MonitorException;
+
+import com.redhat.thermostat.common.internal.test.Bug;
+import com.redhat.thermostat.storage.core.WriterID;
+
+public class VmListenerBackendTest {
+    private static final String VERSION = "0.0.0";
+    private static final String VM_ID = "vmId";
+    private static final int VM_PID = 1;
+    
+    private com.redhat.thermostat.jvm.overview.agent.VmListenerBackend backend;
+    private VmStatusListenerRegistrar registrar;
+    private VmMonitor monitor;
+    private VmUpdateListener listener;
+    private WriterID writerId;
+
+    @Before
+    public void setup() {
+        registrar = mock(VmStatusListenerRegistrar.class);
+        writerId = mock(WriterID.class);
+        backend = new TestBackend("Test Backend", "Backend for test", "Test Co.");
+        monitor = mock(VmMonitor.class);
+        listener = mock(VmUpdateListener.class);
+        backend.setMonitor(monitor);
+    }
+    
+    @Test
+    public void testActivate() {
+        backend.initialize(writerId, registrar, VERSION);
+        backend.activate();
+        assertTrue(backend.isActive());
+        verify(registrar).register(backend);
+    }
+    
+    @Test
+    public void testActivateNoInit() {
+        backend.activate();
+        assertFalse(backend.isActive());
+        verify(registrar, never()).register(backend);
+    }
+
+    @Test
+    public void testActivateTwice() {
+        backend.initialize(writerId, registrar, VERSION);
+        assertTrue(backend.activate());
+        assertTrue(backend.isActive());
+
+        assertTrue(backend.activate());
+        assertTrue(backend.isActive());
+    }
+
+    @Test
+    public void testCanNotActivateWithoutMonitor() {
+        backend.initialize(writerId, registrar, VERSION);
+        backend.setMonitor(null);
+
+        assertFalse(backend.activate());
+        assertFalse(backend.isActive());
+    }
+    
+    @Test
+    public void testDeactivate() {
+        backend.initialize(writerId, registrar, VERSION);
+        backend.activate();
+        backend.deactivate();
+        verify(registrar).unregister(backend);
+        assertFalse(backend.isActive());
+    }
+
+    @Test
+    public void testDeactivateTwice() {
+        backend.initialize(writerId, registrar, VERSION);
+        backend.activate();
+
+        assertTrue(backend.deactivate());
+        assertFalse(backend.isActive());
+        assertTrue(backend.deactivate());
+    }
+    
+    @Test
+    public void testNewVM() {
+        backend.initialize(writerId, registrar, VERSION);
+        // Should be no response if not observing new jvm.
+        backend.setObserveNewJvm(false);
+        backend.vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID);
+        verify(monitor, times(0)).handleNewVm(same(listener), same(VM_PID));
+
+        backend.setObserveNewJvm(true);
+        backend.vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID);
+        verify(monitor).handleNewVm(listener, VM_PID);
+    }
+    
+    /**
+     * createVmListener() might be plugin-supplied code. When creating the
+     * listener fails due to exceptions, other listeners should still continue
+     * to work. That is, the exception of creating one listener must not be
+     * propagated.
+     */
+    @Bug(id = "3242",
+         summary = "Adverse Backend breaks other Backends badly ",
+         url = "http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=3242")
+    @Test
+    public void testNewVMCreateListenerWithExceptions() {
+        VmListenerBackend testBackend = new ExceptionThrowingCreateVmListenerBackend(
+                "Test Backend", "Backend for test", "Test Co.", VERSION);
+        testBackend.initialize(writerId, registrar, VERSION);
+        testBackend.setObserveNewJvm(true);
+        VmMonitor testMonitor = mock(VmMonitor.class);
+        testBackend.setMonitor(testMonitor);
+        testBackend.vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID);
+        verify(testMonitor, times(0)).handleNewVm(any(VmUpdateListener.class), any(int.class));
+    }
+
+    @Test
+    public void testAlreadyRunningVM() {
+        backend.initialize(writerId, registrar, VERSION);
+        backend.setObserveNewJvm(true);
+        backend.vmStatusChanged(Status.VM_ACTIVE, VM_ID, VM_PID);
+
+        verify(monitor).handleNewVm(listener, VM_PID);
+    }
+
+    @Test
+    public void testStoppedVM() throws MonitorException, URISyntaxException {
+        backend.initialize(writerId, registrar, VERSION);
+        backend.setObserveNewJvm(true);
+        backend.vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID);
+        backend.vmStatusChanged(Status.VM_STOPPED, VM_ID, VM_PID);
+
+        verify(monitor).handleStoppedVm(VM_PID);
+    }
+
+    @Test
+    public void testDeactivateUnregistersListener() throws URISyntaxException, MonitorException {
+        backend.initialize(writerId, registrar, VERSION);
+        backend.activate();
+        
+        backend.setObserveNewJvm(true);
+        backend.vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID);
+        backend.deactivate();
+        verify(monitor).removeVmListeners();
+    }
+    
+    private class TestBackend extends VmListenerBackend {
+
+        public TestBackend(String name, String description, String vendor) {
+            super(name, description, vendor);
+        }
+
+        @Override
+        public int getOrderValue() {
+            return 0;
+        }
+
+        @Override
+        protected VmUpdateListener createVmListener(String writerId, String vmId, int pid) {
+            return listener;
+        }
+        
+    }
+    
+    private class ExceptionThrowingCreateVmListenerBackend extends TestBackend {
+        
+        public ExceptionThrowingCreateVmListenerBackend(String name, String description, String vendor,
+                String version) {
+            super(name, description, vendor);
+        }
+        
+        @Override
+        protected VmUpdateListener createVmListener(String writerId, String vmId, int pid) {
+            throw new RuntimeException("createVmListener() testing!");
+        }
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/VmMonitorTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,286 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent;
+
+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 java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.jvm.overview.agent.internal.TestLogHandler;
+import com.redhat.thermostat.jvm.overview.agent.internal.VmListenerWrapper;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import com.redhat.thermostat.common.portability.ProcessChecker;
+
+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;
+
+public class VmMonitorTest {
+
+    private static final String PROCESS_NOT_FOUND = "Process not found";
+    private static final int MONITOR_EXCEPTION_THROWING_PID = 999;
+    private VmMonitor monitor;
+    private HostIdentifier hostIdentifier;
+    private MonitoredHost host;
+    private MonitoredVm monitoredVm;
+    private ProcessChecker checker;
+    private TestLogHandler handler;
+    private Logger logger;
+    private Level savedLoggingLevel;
+
+    @After
+    public void tearDown() {
+        if (handler != null) {
+            logger.removeHandler(handler);
+            handler = null;
+        }
+        logger.setLevel(savedLoggingLevel);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        savedLoggingLevel = setupTestLoggerAndReturnOriginalLevel();
+
+        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);
+        
+        checker = mock(ProcessChecker.class);
+        when(checker.exists(isA(Integer.class))).thenReturn(false);
+
+        monitoredVm = mock(MonitoredVm.class);
+
+        monitor = new VmMonitor(checker);
+        monitor.setHost(host);
+    }
+    
+    private Level setupTestLoggerAndReturnOriginalLevel() {
+        logger = Logger.getLogger("com.redhat.thermostat");
+        Level originalLevel = logger.getLevel();
+        logger.setLevel(Level.FINEST);
+        handler = new TestLogHandler(MONITOR_EXCEPTION_THROWING_PID);
+        logger.addHandler(handler);
+        return originalLevel;
+    }
+
+    @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());
+    }
+    
+    /*
+     * English locale "Process not found". It must not matter really for this
+     * test. See the next test which verifies this.
+     */
+    @Test
+    public void testNewVMWithProcessNotFoundDoesNotLogWarning() throws Exception {
+        String exceptionMsg = PROCESS_NOT_FOUND;
+        basicProcNotFoundTest(exceptionMsg);
+    }
+    
+    /*
+     * Random exception message as the exact message will be locale dependent.
+     */
+    @Test
+    public void testNewVMWithProcessNotFoundDoesNotLogWarning2() throws Exception {
+        String exceptionMsg = "foo but not bar";
+        basicProcNotFoundTest(exceptionMsg);
+    }
+
+    private void basicProcNotFoundTest(String exceptionMsg) throws Exception {
+        IllegalArgumentException iae = new IllegalArgumentException(exceptionMsg);
+        MonitorException procNotFound = new MonitorException(iae);
+        assertEquals(iae, procNotFound.getCause());
+        
+        VmIdentifier vmID = new VmIdentifier(String.valueOf(MONITOR_EXCEPTION_THROWING_PID));
+        when(host.getMonitoredVm(vmID)).thenThrow(procNotFound);
+        VmUpdateListener listener = mock(VmUpdateListener.class);
+
+        monitor.handleNewVm(listener, MONITOR_EXCEPTION_THROWING_PID);
+        assertFalse(handler.isUnableToAttachLoggedAsWarning());
+        assertTrue(handler.isUnableToAttachLoggedAsFinest());
+        assertFalse(handler.isUnableToAttachLoggedAsWarningUnrelated());
+    }
+
+    @Test
+    public void testNewVMUnrelatedCausedMonitorExceptionLogWarning() throws Exception {
+        MonitorException procNotFound = new MonitorException("unknown");
+        
+        VmIdentifier vmID = new VmIdentifier(String.valueOf(MONITOR_EXCEPTION_THROWING_PID));
+        when(host.getMonitoredVm(vmID)).thenThrow(procNotFound);
+        VmUpdateListener listener = mock(VmUpdateListener.class);
+        
+        monitor.handleNewVm(listener, MONITOR_EXCEPTION_THROWING_PID);
+        assertFalse(handler.isUnableToAttachLoggedAsWarning());
+        assertFalse(handler.isUnableToAttachLoggedAsFinest());
+        assertTrue(handler.isUnableToAttachLoggedAsWarningUnrelated());
+    }
+    
+    @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/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/VmPollingBackendTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ScheduledExecutorService;
+
+import com.redhat.thermostat.jvm.overview.agent.VmStatusListener.Status;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.Version;
+import com.redhat.thermostat.common.internal.test.Bug;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class VmPollingBackendTest {
+
+    private VmPollingBackend backend;
+    private ScheduledExecutorService mockExecutor;
+    private VmStatusListenerRegistrar mockRegistrar;
+
+    @Before
+    public void setUp() {
+        mockExecutor = mock(ScheduledExecutorService.class);
+        Version mockVersion = mock(Version.class);
+        when(mockVersion.getVersionNumber()).thenReturn("backend-version");
+        mockRegistrar = mock(VmStatusListenerRegistrar.class);
+        backend = new VmPollingBackend("backend-name", "backend-description",
+                  "backend-vendor", mockVersion, mockExecutor, mockRegistrar) {
+                    @Override
+                    public int getOrderValue() {
+                        return 0; // Doesn't matter, not being tested.
+                    }
+        };
+        if (!backend.getObserveNewJvm()) {
+            /* At time of writing, default is true.  This is
+             * inherited from parent PollingBackend.  In case
+             * default changes:
+             */
+            backend.setObserveNewJvm(true);
+        }
+    }
+
+    /**
+     * If an action throws exceptions repeatedly, that action shall get
+     * disabled/unregistered.
+     */
+    @Bug(id = "3242",
+         summary = "Adverse Backend breaks other Backends badly ",
+         url = "http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=3242")
+    @Test
+    public void testDoScheduledActionsWithExceptions() {
+        final int beyondExceptionThreshold = 13; // anything beyond 10 will do
+        String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2";
+        int pid1 = 123, pid2 = 456;
+        backend.vmStatusChanged(Status.VM_ACTIVE, vmId1, pid1);
+        backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2);
+        BadVmPollingAction badAction = new BadVmPollingAction();
+        backend.registerAction(badAction);
+        for (int i = 0; i < beyondExceptionThreshold; i++) {
+            backend.doScheduledActions();
+        }
+    
+        // The exceptions thrown for one vmID might disable the action
+        // for *all* other vmIDs too. So the call count for one of the
+        // vmIDs is actually 9, whereas the other one must have reached
+        // the threshold count of 10.
+        int callCountVm1 = badAction.getCallCount(vmId1);
+        int callCountVm2 = badAction.getCallCount(vmId2);
+        int minCallCount = Math.min(callCountVm2, callCountVm1);
+        int maxCallCount = Math.max(callCountVm1, callCountVm2);
+        assertEquals("Must not be called beyond exception threshold",
+                10, maxCallCount);
+        assertEquals("Other action's exception cancels globally",
+                9, minCallCount);
+    }
+
+    @Test
+    public void verifyCustomActivateRegistersListener() {
+        backend.preActivate();
+        verify(mockRegistrar).register(backend);
+    }
+
+    @Test
+    public void verifyCustomDeactivateUnregistersListener() {
+        backend.postDeactivate();
+        verify(mockRegistrar).unregister(backend);
+    }
+    
+    @Test
+    public void verifyRegisteredActionPerformed() {
+        String vmId = "test-vm-id";
+        int pid = 123;
+        backend.vmStatusChanged(Status.VM_ACTIVE, vmId, pid);
+        VmPollingAction action = mock(VmPollingAction.class);
+        backend.registerAction(action);
+        backend.doScheduledActions();
+
+        verify(action).run(eq(vmId), eq(pid));
+    }
+
+    @Test
+    public void verifyMultipleRegisteredActionsPerformed() {
+        String vmId = "test-vm-id";
+        int pid = 123;
+        backend.vmStatusChanged(Status.VM_ACTIVE, vmId, pid);
+        VmPollingAction action1 = mock(VmPollingAction.class);
+        VmPollingAction action2 = mock(VmPollingAction.class);
+        backend.registerAction(action1);
+        backend.registerAction(action2);
+        backend.doScheduledActions();
+
+        verify(action1).run(eq(vmId), eq(pid));
+        verify(action2).run(eq(vmId), eq(pid));
+    }
+
+    @Test
+    public void verifyActionsPerformedOnMultipleVms() {
+        String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2";
+        int pid1 = 123, pid2 = 456;
+        backend.vmStatusChanged(Status.VM_ACTIVE, vmId1, pid1);
+        backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2);
+        VmPollingAction action = mock(VmPollingAction.class);
+        backend.registerAction(action);
+        backend.doScheduledActions();
+
+        verify(action).run(eq(vmId1), eq(pid1));
+        verify(action).run(eq(vmId2), eq(pid2));
+    }
+
+    @Test
+    public void verifyMultipleRegisteredActionsPerformedOnMultipleVms() {
+        String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2";
+        int pid1 = 123, pid2 = 456;
+        backend.vmStatusChanged(Status.VM_ACTIVE, vmId1, pid1);
+        backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2);
+        VmPollingAction action1 = mock(VmPollingAction.class);
+        VmPollingAction action2 = mock(VmPollingAction.class);
+        backend.registerAction(action1);
+        backend.registerAction(action2);
+        backend.doScheduledActions();
+
+        verify(action1).run(eq(vmId1), eq(pid1));
+        verify(action1).run(eq(vmId2), eq(pid2));
+        verify(action2).run(eq(vmId1), eq(pid1));
+        verify(action2).run(eq(vmId2), eq(pid2));
+    }
+
+    @Test
+    public void verifyUnregisteredActionNotPerformed() {
+        String vmId = "test-vm-id";
+        int pid = 123;
+        backend.vmStatusChanged(Status.VM_ACTIVE, vmId, pid);
+        VmPollingAction action1 = mock(VmPollingAction.class);
+        VmPollingAction action2 = mock(VmPollingAction.class);
+        backend.registerAction(action1);
+        backend.registerAction(action2);
+        backend.doScheduledActions(); // Triggers both
+        backend.unregisterAction(action1);
+        backend.doScheduledActions(); // Triggers only action2
+
+        verify(action1, times(1)).run(eq(vmId), eq(pid));
+        verify(action2, times(2)).run(eq(vmId), eq(pid));
+    }
+
+    @Test
+    public void verifyVmStatusChangedStartedAndActiveResultInPolling() {
+        String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2";
+        int pid1 = 123, pid2 = 456;
+        backend.vmStatusChanged(Status.VM_STARTED, vmId1, pid1);
+        backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2);
+        VmPollingAction action = mock(VmPollingAction.class);
+        backend.registerAction(action);
+        backend.doScheduledActions();
+
+        verify(action).run(eq(vmId1), eq(pid1));
+        verify(action).run(eq(vmId2), eq(pid2));
+    }
+
+    @Test
+    public void verifyVmStatusChangedStopsResultsInNoMorePolling() {
+        String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2";
+        int pid1 = 123, pid2 = 456;
+        backend.vmStatusChanged(Status.VM_ACTIVE, vmId1, pid1);
+        backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2);
+        VmPollingAction action = mock(VmPollingAction.class);
+        backend.registerAction(action);
+        backend.doScheduledActions(); // Triggers for both vms
+        backend.vmStatusChanged(Status.VM_STOPPED, vmId1, pid1);
+        backend.doScheduledActions(); // Triggers only for vm2
+
+        verify(action, times(1)).run(eq(vmId1), eq(pid1));
+        verify(action, times(2)).run(eq(vmId2), eq(pid2));
+    }
+
+    @Test
+    public void verifyGetSetObserveNewJvmWorksAsExpected() {
+        String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2";
+        int pid1 = 123, pid2 = 456;
+        backend.vmStatusChanged(Status.VM_ACTIVE, vmId1, pid1);
+        backend.setObserveNewJvm(false);
+        backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2); // Should be ignored.
+        VmPollingAction action = mock(VmPollingAction.class);
+        backend.registerAction(action);
+        backend.doScheduledActions();
+
+        verify(action).run(eq(vmId1), eq(pid1));
+        verify(action, never()).run(eq(vmId2), eq(pid2));
+    }
+    
+    private static class BadVmPollingAction implements VmPollingAction {
+        
+        private final Map<String, Integer> callCounts = new HashMap<>();
+        
+        @Override
+        public void run(String vmId, int pid) {
+            Integer currCount = callCounts.remove(vmId);
+            if (currCount == null) {
+                currCount = Integer.valueOf(1);
+            } else {
+                currCount++;
+            }
+            callCounts.put(vmId, Integer.valueOf(currCount));
+            throw new RuntimeException("doScheduledActions() testing!");
+        }
+        
+        private Integer getCallCount(String vmId) {
+            return callCounts.get(vmId);
+        }
+        
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/VmStatusListenerRegistrarTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.testutils.StubBundleContext;
+
+public class VmStatusListenerRegistrarTest {
+
+    @Test
+    public void testRegister() {
+        StubBundleContext context = new StubBundleContext();
+        VmStatusListener listener = mock(VmStatusListener.class);
+
+        VmStatusListenerRegistrar registerer = new VmStatusListenerRegistrar(context);
+        registerer.register(listener);
+
+        assertTrue(context.isServiceRegistered(VmStatusListener.class.getName(), listener.getClass()));
+        assertEquals(1, context.getAllServices().size());
+    }
+
+    @Test
+    public void testUnregister() {
+        StubBundleContext context = new StubBundleContext();
+        VmStatusListener listener = mock(VmStatusListener.class);
+
+        VmStatusListenerRegistrar registerer = new VmStatusListenerRegistrar(context);
+        registerer.register(listener);
+        registerer.unregister(listener);
+
+        assertFalse(context.isServiceRegistered(VmStatusListener.class.getName(), listener.getClass()));
+        assertEquals(0, context.getAllServices().size());
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/VmUpdateImplTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import com.redhat.thermostat.jvm.overview.agent.internal.VmListenerWrapper;
+import com.redhat.thermostat.jvm.overview.agent.internal.VmUpdateImpl;
+import org.junit.Before;
+import org.junit.Test;
+
+import sun.jvmstat.monitor.Monitor;
+
+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);
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/JvmStatHostListenerTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.AdditionalMatchers.not;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
+import com.redhat.thermostat.jvm.overview.agent.VmBlacklist;
+import com.redhat.thermostat.jvm.overview.agent.VmStatusListener.Status;
+import com.redhat.thermostat.jvm.overview.agent.internal.model.VmInfoDAO;
+import com.redhat.thermostat.jvm.overview.agent.model.VmInfo;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import com.redhat.thermostat.common.portability.ProcessUserInfo;
+import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder;
+import com.redhat.thermostat.storage.core.WriterID;
+
+import sun.jvmstat.monitor.HostIdentifier;
+import sun.jvmstat.monitor.Monitor;
+import sun.jvmstat.monitor.MonitorException;
+import sun.jvmstat.monitor.MonitoredHost;
+import sun.jvmstat.monitor.MonitoredVm;
+import sun.jvmstat.monitor.StringMonitor;
+import sun.jvmstat.monitor.VmIdentifier;
+import sun.jvmstat.monitor.event.VmStatusChangeEvent;
+
+public class JvmStatHostListenerTest {
+    
+    private static String INFO_CMDLINE = "/path/to/executable command line args";
+    private static String INFO_JAVAHOME = "/path/to/java";
+    private static String INFO_JAVAVER = "1.9001";
+    private static String INFO_MAINCLASS = "MyMainClass";
+    private static String INFO_VMARGS = "-Xarg1 -Xarg2";
+    private static String INFO_VMINFO = "Info";
+    private static String INFO_VMNAME = "MyJVM";
+    private static String INFO_VMVER = "90.01";
+    private static long INFO_VMUSERID = 2000;
+    private static String INFO_VMUSERNAME = "User";
+    private static final long INFO_STARTTIME = Long.MIN_VALUE;
+
+    private JvmStatHostListener hostListener;
+    private MonitoredHost host;
+    private MonitoredVm monitoredVm1;
+    private MonitoredVm monitoredVm2;
+    private JvmStatDataExtractor extractor;
+    private VmInfoDAO vmInfoDAO;
+    private VmStatusChangeNotifier notifier;
+    private VmBlacklist blacklist;
+
+    @Before
+    public void setup() throws MonitorException, URISyntaxException {
+        vmInfoDAO = mock(VmInfoDAO.class);
+        notifier = mock(VmStatusChangeNotifier.class);
+        
+        ProcessUserInfoBuilder userInfoBuilder = mock(ProcessUserInfoBuilder.class);
+        ProcessUserInfo userInfo = new ProcessUserInfo(INFO_VMUSERID, INFO_VMUSERNAME);
+        when(userInfoBuilder.build(any(int.class))).thenReturn(userInfo);
+
+        WriterID id = mock(WriterID.class);
+        blacklist = mock(VmBlacklist.class);
+        hostListener = new JvmStatHostListener(vmInfoDAO, notifier, userInfoBuilder, id, blacklist);
+        
+        host = mock(MonitoredHost.class);
+        HostIdentifier hostId = mock(HostIdentifier.class);
+        monitoredVm1 = mock(MonitoredVm.class);
+        monitoredVm2 = mock(MonitoredVm.class);
+        StringMonitor monitor = mock(StringMonitor.class);
+        Monitor monitor2 = mock(Monitor.class);
+        VmIdentifier vmId1 = new VmIdentifier("1");
+        VmIdentifier vmId2 = new VmIdentifier("2");
+
+        when(monitor2.getValue()).thenReturn(100l);
+        when(host.getHostIdentifier()).thenReturn(hostId);
+        when(host.getMonitoredVm(eq(vmId1))).thenReturn(monitoredVm1);
+        when(host.getMonitoredVm(eq(vmId2))).thenReturn(monitoredVm2);
+        when(hostId.resolve(eq(vmId1))).thenReturn(vmId1);
+        when(hostId.resolve(eq(vmId2))).thenReturn(vmId2);
+        when(monitoredVm1.findByName("sun.rt.vmInitDoneTime")).thenReturn(monitor2);
+        when(monitoredVm2.findByName("sun.rt.vmInitDoneTime")).thenReturn(monitor2);
+        when(monitoredVm1.findByName(not(eq("sun.rt.vmInitDoneTime")))).thenReturn(monitor);
+        when(monitoredVm2.findByName(not(eq("sun.rt.vmInitDoneTime")))).thenReturn(monitor);
+        when(monitor.stringValue()).thenReturn("test");
+        when(monitor.getValue()).thenReturn("test");
+        extractor = mock(JvmStatDataExtractor.class);
+        
+        when(extractor.getCommandLine()).thenReturn(INFO_CMDLINE);
+        when(extractor.getJavaHome()).thenReturn(INFO_JAVAHOME);
+        when(extractor.getJavaVersion()).thenReturn(INFO_JAVAVER);
+        when(extractor.getMainClass()).thenReturn(INFO_MAINCLASS);
+        when(extractor.getVmArguments()).thenReturn(INFO_VMARGS);
+        when(extractor.getVmInfo()).thenReturn(INFO_VMINFO);
+        when(extractor.getVmName()).thenReturn(INFO_VMNAME);
+        when(extractor.getVmVersion()).thenReturn(INFO_VMVER);
+        when(extractor.getVmStartTime()).thenReturn(INFO_STARTTIME);
+    }
+    
+    @Test
+    public void testNewVM() throws InterruptedException, MonitorException {
+        startVMs();
+        
+        assertTrue(hostListener.getMonitoredVms().containsKey(1));
+        assertTrue(hostListener.getMonitoredVms().containsKey(2));
+        assertEquals(monitoredVm1, hostListener.getMonitoredVms().get(1).getSecond());
+        assertEquals(monitoredVm2, hostListener.getMonitoredVms().get(2).getSecond());
+        
+        // Check valid UUIDs
+        UUID uuid1 = UUID.fromString(hostListener.getMonitoredVms().get(1).getFirst());
+        UUID uuid2 = UUID.fromString(hostListener.getMonitoredVms().get(2).getFirst());
+        assertFalse(uuid1.equals(uuid2));
+        
+        verify(notifier, times(2)).notifyVmStatusChange(eq(Status.VM_STARTED), anyString(), (isA(Integer.class)));
+    }
+    
+    @Test
+    public void testNewVMBlackListed() throws InterruptedException, MonitorException {
+        when(blacklist.isBlacklisted(anyString())).thenReturn(true).thenReturn(false);
+        startVMs();
+        
+        assertFalse(hostListener.getMonitoredVms().containsKey(1));
+        assertTrue(hostListener.getMonitoredVms().containsKey(2));
+        assertEquals(monitoredVm2, hostListener.getMonitoredVms().get(2).getSecond());
+        
+        UUID uuid = UUID.fromString(hostListener.getMonitoredVms().get(2).getFirst());
+        verify(notifier).notifyVmStatusChange(eq(Status.VM_STARTED), eq(uuid.toString()), (isA(Integer.class)));
+    }
+    
+    @Test
+    public void testStoppedVM() throws InterruptedException, MonitorException {
+        final Set<Integer> stopped = new HashSet<>();
+        stopped.add(1);
+        
+        startVMs();
+        
+        // Trigger a change event
+        VmStatusChangeEvent event = mock(VmStatusChangeEvent.class);
+        when(event.getMonitoredHost()).thenReturn(host);
+        when(event.getStarted()).thenReturn(Collections.<Integer>emptySet());
+        when(event.getTerminated()).thenReturn(stopped);
+        hostListener.vmStatusChanged(event);
+        
+        // Ensure only 1 removed
+        assertFalse(hostListener.getMonitoredVms().containsKey(1));
+        assertTrue(hostListener.getMonitoredVms().containsKey(2));
+        assertEquals(monitoredVm2, hostListener.getMonitoredVms().get(2).getSecond());
+
+        verify(notifier).notifyVmStatusChange(eq(Status.VM_STOPPED), anyString(), (isA(Integer.class)));
+
+    }
+    
+    @Test
+    public void testReusedPid() throws MonitorException {
+        final Set<Integer> started = new HashSet<>();
+        started.add(1);
+        // Start VM
+        VmStatusChangeEvent event = mock(VmStatusChangeEvent.class);
+        when(event.getMonitoredHost()).thenReturn(host);
+        when(event.getStarted()).thenReturn(started);
+        when(event.getTerminated()).thenReturn(Collections.<Integer>emptySet());
+        hostListener.vmStatusChanged(event);
+        
+        ArgumentCaptor<String> vmIdCaptor = ArgumentCaptor.forClass(String.class);
+        
+        // Stop VM
+        event = mock(VmStatusChangeEvent.class);
+        when(event.getMonitoredHost()).thenReturn(host);
+        when(event.getStarted()).thenReturn(Collections.<Integer>emptySet());
+        when(event.getTerminated()).thenReturn(started);
+        hostListener.vmStatusChanged(event);
+        
+        // Start new VM
+        event = mock(VmStatusChangeEvent.class);
+        when(event.getMonitoredHost()).thenReturn(host);
+        when(event.getStarted()).thenReturn(started);
+        when(event.getTerminated()).thenReturn(Collections.<Integer>emptySet());
+        hostListener.vmStatusChanged(event);
+        
+        verify(notifier, times(2)).notifyVmStatusChange(eq(Status.VM_STARTED), vmIdCaptor.capture(), eq(1));
+        List<String> vmIds = vmIdCaptor.getAllValues();
+        
+        assertEquals(2, vmIds.size());
+        String vmId1 = vmIds.get(0);
+        String vmId2 = vmIds.get(1);
+        assertNotNull(vmId1);
+        assertNotNull(vmId2);
+        assertFalse(vmId1.equals(vmId2));
+    }
+
+    private void startVMs() throws InterruptedException, MonitorException {
+        final Set<Integer> started = new HashSet<>();
+        started.add(1);
+        started.add(2);
+
+        // Trigger a change event
+        VmStatusChangeEvent event = mock(VmStatusChangeEvent.class);
+        when(event.getMonitoredHost()).thenReturn(host);
+        when(event.getStarted()).thenReturn(started);
+        when(event.getTerminated()).thenReturn(Collections.<Integer>emptySet());
+        hostListener.vmStatusChanged(event);
+    }
+
+    @Test
+    public void testCreateVmInfo() throws MonitorException {
+        final String INFO_ID = "vmId";
+        final int INFO_PID = 1;
+        final long INFO_STOPTIME = Long.MAX_VALUE;
+        VmInfo info = hostListener.createVmInfo(INFO_ID, INFO_PID, INFO_STOPTIME, extractor);
+        
+        assertEquals(INFO_PID, info.getVmPid());
+        assertEquals(INFO_STARTTIME, info.getStartTimeStamp());
+        assertEquals(INFO_STOPTIME, info.getStopTimeStamp());
+        assertEquals(INFO_CMDLINE, info.getJavaCommandLine());
+        assertEquals(INFO_JAVAHOME, info.getJavaHome());
+        assertEquals(INFO_JAVAVER, info.getJavaVersion());
+        assertEquals(INFO_MAINCLASS, info.getMainClass());
+        assertEquals(INFO_VMARGS, info.getVmArguments());
+        assertEquals(INFO_VMINFO, info.getVmInfo());
+        assertEquals(INFO_VMNAME, info.getVmName());
+        assertEquals(INFO_VMVER, info.getVmVersion());
+        assertEquals(INFO_VMUSERID, info.getUid());
+        assertEquals(INFO_VMUSERNAME, info.getUsername());
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/ProcessEnvironmentBuilderTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal;
+
+import com.redhat.thermostat.common.portability.PortableProcess;
+import com.redhat.thermostat.jvm.overview.agent.internal.model.ProcessEnvironmentBuilder;
+import com.redhat.thermostat.jvm.overview.agent.internal.model.ProcessEnvironmentBuilderImpl;
+import com.redhat.thermostat.shared.config.OS;
+
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * test windows process env builder
+ */
+public class ProcessEnvironmentBuilderTest {
+
+    private PortableProcess whelp;
+
+    private static final int FAKE_PID = 4567;
+    private static final String PATH_KEY = "PATH";
+    private static final String FAKE_PATH = "testpath";
+
+    private static final Map<String,String> goodMap = new HashMap<>();
+
+    @Before
+    public void setup() {
+        whelp = mock(PortableProcess.class);
+        goodMap.put(PATH_KEY, FAKE_PATH);
+        when(whelp.getEnvironment(anyInt())).thenReturn(null);
+        when(whelp.getEnvironment(eq(FAKE_PID))).thenReturn(goodMap);
+    }
+
+    @Test
+    public void testSimpleBuild() {
+        Assume.assumeTrue(OS.IS_WINDOWS);
+        final Map<String,String> info = new ProcessEnvironmentBuilderImpl().build(FAKE_PID);
+        assertNotNull(info);
+    }
+
+    @Test
+    public void testGetInfoFromGoodPid() {
+        final ProcessEnvironmentBuilder ib = new ProcessEnvironmentBuilderImpl(whelp);
+        final Map<String,String> info  = ib.build(FAKE_PID);
+        assertFalse(info.isEmpty());
+        assertTrue(info.containsKey(PATH_KEY));
+        assertEquals(FAKE_PATH, info.get(PATH_KEY));
+    }
+
+    @Test
+    public void testGetInfoFromBadPid() {
+        final ProcessEnvironmentBuilder ib = new ProcessEnvironmentBuilderImpl(whelp);
+        final Map<String,String> info  = ib.build(FAKE_PID+1);
+        assertTrue(info == null || info.isEmpty());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/TestLogHandler.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal;
+
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+/*
+ * Test log handler used for VmMonitor log testing.
+ */
+public class TestLogHandler extends Handler {
+    
+    private static final String PROCESS_NOT_FOUND = "Process not found";
+    private static final String EXPECTED_UNABLE_TO_ATTACH_PROC_NOT_FOUND_FMT =
+            "Tried to attach to a process which no longer exists. Pid was %d";
+    private static final String EXPECTED_UNABLE_TO_ATTACH_MSG_FMT =
+            "unable to attach to vm %d";
+    private boolean unableToAttachLoggedWarning;
+    private boolean unableToAttachLoggedFinest;
+    private final String unableToAttachMsg;
+    private final String procNotFoundMsg;
+    
+    public TestLogHandler(int pid) {
+        unableToAttachMsg = String.format(EXPECTED_UNABLE_TO_ATTACH_MSG_FMT, pid);
+        procNotFoundMsg = String.format(EXPECTED_UNABLE_TO_ATTACH_PROC_NOT_FOUND_FMT, pid);
+    }
+    
+    @Override
+    public void publish(LogRecord record) {
+        String logMessage = record.getMessage();
+        if (record.getLevel().intValue() >= Level.WARNING.intValue() && 
+                logMessage.equals(unableToAttachMsg)) {
+            unableToAttachLoggedWarning = diagnoseRecord(record);
+        }
+        if (record.getLevel().intValue() == Level.FINEST.intValue() &&
+                logMessage.equals(procNotFoundMsg)) {
+            unableToAttachLoggedFinest = diagnoseRecord(record);
+        }
+    }
+
+    private boolean diagnoseRecord(LogRecord record) {
+        Throwable thrown = record.getThrown();
+        if (thrown != null && thrown.getCause() instanceof IllegalArgumentException) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void flush() {
+        // nothing
+    }
+
+    @Override
+    public void close() throws SecurityException {
+        // nothing
+    }
+    
+    public boolean isUnableToAttachLoggedAsWarning() {
+        return unableToAttachLoggedWarning;
+    }
+
+    public boolean isUnableToAttachLoggedAsWarningUnrelated() {
+        return !unableToAttachLoggedWarning && !unableToAttachLoggedFinest;
+    }
+
+    public boolean isUnableToAttachLoggedAsFinest() {
+        return unableToAttachLoggedFinest;
+    }
+    
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/VmListenerWrapperTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.redhat.thermostat.jvm.overview.agent.VmUpdate;
+import com.redhat.thermostat.jvm.overview.agent.VmUpdateException;
+import com.redhat.thermostat.jvm.overview.agent.VmUpdateListener;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import com.redhat.thermostat.common.internal.test.Bug;
+
+import sun.jvmstat.monitor.Monitor;
+import sun.jvmstat.monitor.MonitorException;
+import sun.jvmstat.monitor.MonitoredVm;
+import sun.jvmstat.monitor.event.VmEvent;
+
+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);
+    }
+    
+    /**
+     * Verify that a bad listener which throws exceptions gets removed
+     * from the JVM beyond a threshold.
+     * @throws MonitorException 
+     */
+    @Bug(id = "3242",
+         summary = "Adverse Backend breaks other Backends badly ",
+         url = "http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=3242")
+    @Test
+    public void testMonitorsUpdatedListenerExceptions() throws MonitorException {
+        final int beyondThresholdLimit = 11;
+        VmUpdateListener badListener = new VmUpdateListener() {
+            @Override
+            public void countersUpdated(VmUpdate update) {
+                throw new RuntimeException("countersUpdated() testing!");
+            }
+        };
+        VmListenerWrapper vmListenerWrapper = new VmListenerWrapper(badListener, monitoredVm);
+        VmEvent event = mock(VmEvent.class);
+        for (int i = 0; i < beyondThresholdLimit; i++) {
+            when(event.getMonitoredVm()).thenReturn(monitoredVm);
+            
+            vmListenerWrapper.monitorsUpdated(event);
+            
+        }
+        verify(monitoredVm, times(1)).removeVmListener(vmListenerWrapper);
+    }
+
+    @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/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/VmStatusChangeNotifierTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import java.util.ConcurrentModificationException;
+
+import com.redhat.thermostat.jvm.overview.agent.VmStatusListener;
+import com.redhat.thermostat.jvm.overview.agent.VmStatusListener.Status;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+
+import com.redhat.thermostat.testutils.StubBundleContext;
+
+public class VmStatusChangeNotifierTest {
+
+    @Test
+    public void verifyWorksWithoutAnyListeners() {
+        final String VM_ID = "vmId";
+        final int VM_PID = 2;
+        StubBundleContext bundleContext = new StubBundleContext();
+
+        VmStatusChangeNotifier notifier = new VmStatusChangeNotifier(bundleContext);
+        notifier.start();
+        notifier.notifyVmStatusChange(Status.VM_STARTED, VM_ID, VM_PID);
+
+        notifier.notifyVmStatusChange(Status.VM_STOPPED, VM_ID, VM_PID);
+    }
+
+    @Test
+    public void verifyAllListenersAreNotified() {
+        final String VM_ID = "vmId";
+        final int VM_PID = 2;
+        StubBundleContext bundleContext = new StubBundleContext();
+
+        VmStatusListener listener = mock(VmStatusListener.class);
+        bundleContext.registerService(VmStatusListener.class, listener, null);
+
+        VmStatusChangeNotifier notifier = new VmStatusChangeNotifier(bundleContext);
+        notifier.start();
+        notifier.notifyVmStatusChange(Status.VM_STARTED, VM_ID, VM_PID);
+
+        verify(listener).vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID);
+
+        notifier.notifyVmStatusChange(Status.VM_STOPPED, VM_ID, VM_PID);
+
+        verify(listener).vmStatusChanged(Status.VM_STOPPED, VM_ID, VM_PID);
+    }
+
+    @Test
+    public void verifyListenersAddedAfterVmStartRecieveVmActiveEvent() {
+        final String VM_ID = "vmId";
+        final int VM_PID = 2;
+        StubBundleContext bundleContext = new StubBundleContext();
+
+        VmStatusChangeNotifier notifier = new VmStatusChangeNotifier(bundleContext);
+        notifier.start();
+        notifier.notifyVmStatusChange(Status.VM_STARTED, VM_ID, VM_PID);
+
+        VmStatusListener listener = mock(VmStatusListener.class);
+        bundleContext.registerService(VmStatusListener.class, listener, null);
+
+        verify(listener).vmStatusChanged(Status.VM_ACTIVE, VM_ID, VM_PID);
+
+    }
+    
+    /*
+     * Some backends might activate on activation of another backend. If both of
+     * them are also VmStatusListener's, a concurrent modification exception
+     * might be thrown. This tests verifies it's OK to do so (concurrent modification).
+     */
+    @Test
+    public void canAddListenersWhileFiringEvent() throws InterruptedException {
+        StubBundleContext bundleContext = new StubBundleContext();
+        VmStatusChangeNotifier notifier = new VmStatusChangeNotifier(bundleContext);
+        
+        // Add > 2 listeners. One of them registers another listener in vmStatusChanged()
+        // Thus provoking ConcurrentModificationException.
+        bundleContext.registerService(VmStatusListener.class, new TestVmStatusListener(bundleContext), null);
+        bundleContext.registerService(VmStatusListener.class, new VmStatusListener() {
+
+            @Override
+            public void vmStatusChanged(Status newStatus, String vmId,
+                    int pid) {
+                Debug.println("Second registered listener fired");
+            }
+            
+            @Override
+            public int hashCode() {
+                return 2; // second listener to be fired
+            }
+            
+        }, null);
+        bundleContext.registerService(VmStatusListener.class, new VmStatusListener() {
+
+            @Override
+            public void vmStatusChanged(Status newStatus, String vmId,
+                    int pid) {
+                Debug.println("Third registered listener fired");
+            }
+            
+            @Override
+            public int hashCode() {
+                return 3;
+            }
+            
+        }, null);
+        notifier.start();
+        
+        try {
+            notifier.notifyVmStatusChange(Status.VM_STARTED, "foo-vmid", 333);
+            // this will trigger the newly added listener being invoked and counting
+            // down the latch.
+            notifier.notifyVmStatusChange(Status.VM_STARTED, "foo-other", 9999);
+            // pass
+        } catch (ConcurrentModificationException e) {
+            fail("Unexpected conncurrent modification exception!");
+        }
+    }
+    
+    static class TestVmStatusListener implements VmStatusListener {
+
+        private final BundleContext context;
+        
+        private TestVmStatusListener(BundleContext context) {
+            this.context = context;
+        }
+        
+        @Override
+        public void vmStatusChanged(Status newStatus, String vmId, int pid) {
+            Debug.println("First registered listener fired");
+            context.registerService(VmStatusListener.class, new VmStatusListener() {
+
+                @Override
+                public void vmStatusChanged(Status newStatus, String vmId,
+                        int pid) {
+                    Debug.println("Listener registered in listener (between first and second) fired");
+                }
+                
+                @Override
+                public int hashCode() {
+                    // Pick a large hash code since that tends to result in
+                    // the listener being fired later on.
+                    return 101;
+                }
+                
+            }, null);
+        }
+        
+        @Override
+        public int hashCode() {
+            // Heuristic for HashMap it tends to be picked first when iterating over
+            return 1;
+        }
+        
+    }
+    
+    static class Debug {
+        
+        static final boolean debugOn = false; // set to true for debug output
+        
+        static void println(String msg) {
+            if (debugOn) {
+                System.err.println(msg);
+            }
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/model/InfoBuilderFactoryTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal.model;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class InfoBuilderFactoryTest {
+
+    @Test
+    public void testCreateProcessEnvironmentBuilder() {
+        final InfoBuilderFactory builder = new InfoBuilderFactoryImpl();
+        final ProcessEnvironmentBuilder hib = builder.createProcessEnvironmentBuilder();
+        assertNotNull(hib);
+        assertTrue(hib instanceof ProcessEnvironmentBuilderImpl);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/model/VmInfoDAOTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal.model;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyListOf;
+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.when;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.redhat.thermostat.jvm.overview.agent.internal.model.VmInfoDAOImpl.HttpHelper;
+import com.redhat.thermostat.jvm.overview.agent.internal.model.VmInfoDAOImpl.JsonHelper;
+import com.redhat.thermostat.jvm.overview.agent.internal.model.VmInfoDAOImpl.VmInfoUpdate;
+import com.redhat.thermostat.jvm.overview.agent.model.VmInfo;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.client.util.StringContentProvider;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpStatus;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+public class VmInfoDAOTest {
+
+    private static final String URL = "http://localhost:26000/api/v100/vm-info/systems/*/agents/foo-agent";
+    private static final String UPDATE_URL = URL + "/jvms/vmId";
+    private static final String SOME_JSON = "{\"some\" : \"json\"}";
+    private static final String SOME_OTHER_JSON = "{\"some\" : {\"other\" : \"json\"}}";
+    private static final String CONTENT_TYPE = "application/json";
+    
+    private VmInfo info;
+    private JsonHelper jsonHelper;
+    private HttpHelper httpHelper;
+    private StringContentProvider contentProvider;
+    private Request request;
+    private ContentResponse response;
+
+    @Before
+    public void setUp() throws Exception {
+        String vmId = "vmId";
+        int vmPid = 1;
+        long startTime = 2L;
+        long stopTime = Long.MIN_VALUE;
+        String jVersion = "java 1.0";
+        String jHome = "/path/to/jdk/home";
+        String mainClass = "Hello.class";
+        String commandLine = "World";
+        String vmArgs = "-XX=+FastestJITPossible";
+        String vmName = "Hotspot";
+        String vmInfo = "Some info";
+        String vmVersion = "1.0";
+        Map<String, String> props = new HashMap<>();
+        Map<String, String> env = new HashMap<>();
+        String[] libs = new String[0];
+        long uid = 2000L;
+        String username = "myUser";
+        info = new VmInfo("foo-agent", vmId, vmPid, startTime, stopTime, jVersion, jHome,
+                mainClass, commandLine, vmName, vmInfo, vmVersion, vmArgs,
+                props, env, libs, uid, username);
+        
+        httpHelper = mock(HttpHelper.class);
+        contentProvider = mock(StringContentProvider.class);
+        when(httpHelper.createContentProvider(anyString())).thenReturn(contentProvider);
+        request = mock(Request.class);
+        when(httpHelper.newRequest(anyString())).thenReturn(request);
+        response = mock(ContentResponse.class);
+        when(response.getStatus()).thenReturn(HttpStatus.OK_200);
+        when(request.send()).thenReturn(response);
+        
+        jsonHelper = mock(JsonHelper.class);
+        when(jsonHelper.toJson(anyListOf(VmInfo.class))).thenReturn(SOME_JSON);
+        when(jsonHelper.toJson(any(VmInfoUpdate.class))).thenReturn(SOME_OTHER_JSON);
+    }
+
+    @Test
+    public void testPutVmInfo() throws Exception {
+        VmInfoDAO dao = new VmInfoDAOImpl(httpHelper, jsonHelper);
+        dao.putVmInfo(info);
+        
+        verify(httpHelper).newRequest(URL);
+        verify(request).method(HttpMethod.POST);
+        verify(jsonHelper).toJson(eq(Arrays.asList(info)));
+        verify(httpHelper).createContentProvider(SOME_JSON);
+        verify(request).content(contentProvider, CONTENT_TYPE);
+        verify(request).send();
+        verify(response).getStatus();
+    }
+
+    @Test
+    public void testPutVmStoppedTime() throws Exception {
+        VmInfoDAO dao = new VmInfoDAOImpl(httpHelper, jsonHelper);
+        dao.putVmStoppedTime("foo-agent", "vmId", 3L);
+
+        verify(httpHelper).newRequest(UPDATE_URL);
+        verify(request).method(HttpMethod.PUT);
+        
+        ArgumentCaptor<VmInfoUpdate> updateCaptor = ArgumentCaptor.forClass(VmInfoUpdate.class);
+        verify(jsonHelper).toJson(updateCaptor.capture());
+        VmInfoUpdate update = updateCaptor.getValue();
+        assertEquals(3L, update.getStoppedTime());
+                
+        verify(httpHelper).createContentProvider(SOME_OTHER_JSON);
+        verify(request).content(contentProvider, CONTENT_TYPE);
+        verify(request).send();
+        verify(response).getStatus();
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/model/VmInfoTypeAdapterTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2012-2017 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.jvm.overview.agent.internal.model;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.redhat.thermostat.jvm.overview.agent.internal.model.VmInfoDAOImpl.VmInfoUpdate;
+import com.redhat.thermostat.jvm.overview.agent.internal.model.VmInfoTypeAdapter.VmInfoUpdateTypeAdapter;
+import com.redhat.thermostat.jvm.overview.agent.model.VmInfo;
+import org.junit.Test;
+
+public class VmInfoTypeAdapterTest {
+    
+    @Test
+    public void testWrite() throws Exception {
+        VmInfoTypeAdapter adapter = new VmInfoTypeAdapter();
+        final String expected = "[{\"agentId\":\"agent1\",\"vmId\":\"vm1\",\"vmPid\":8000,"
+                + "\"startTimeStamp\":{\"$numberLong\":\"50000\"},\"stopTimeStamp\":"
+                + "{\"$numberLong\":\"-9223372036854775808\"},\"javaVersion\":\"1.8.0\","
+                + "\"javaHome\":\"/path/to/java\",\"mainClass\":\"myClass\",\"javaCommandLine\":\"java myClass\","
+                + "\"vmName\":\"myJVM\",\"vmArguments\":\"-Dhello\",\"vmInfo\":\"interesting\","
+                + "\"vmVersion\":\"1800\",\"propertiesAsArray\":[{\"key\":\"A\",\"value\":\"B\"},"
+                + "{\"key\":\"C\",\"value\":\"D\"}],\"environmentAsArray\":[{\"key\":\"E\",\"value\":\"F\"},"
+                + "{\"key\":\"G\",\"value\":\"H\"}],\"loadedNativeLibraries\":[],\"uid\":{\"$numberLong\":\"1234\"},"
+                + "\"username\":\"test\"},"
+                + "{\"agentId\":\"agent2\",\"vmId\":\"vm2\",\"vmPid\":9000,\"startTimeStamp\":"
+                + "{\"$numberLong\":\"100000\"},\"stopTimeStamp\":{\"$numberLong\":\"200000\"},"
+                + "\"javaVersion\":\"1.7.0\",\"javaHome\":\"/path/to/jre\",\"mainClass\":\"myOtherClass\","
+                + "\"javaCommandLine\":\"otherClass.sh\",\"vmName\":\"myOtherJVM\",\"vmArguments\":\"-Dworld\","
+                + "\"vmInfo\":\"info\",\"vmVersion\":\"1700\",\"propertiesAsArray\":[],\"environmentAsArray\":"
+                + "[{\"key\":\"A\",\"value\":\"B\"},{\"key\":\"C\",\"value\":\"D\"}],"
+                + "\"loadedNativeLibraries\":[\"libhello\",\"libworld\"],\"uid\":{\"$numberLong\":\"5678\"}"
+                + ",\"username\":\"user\"}]";
+        
+        final Map<String, String> props = new HashMap<>();
+        props.put("A", "B");
+        props.put("C", "D");
+        final Map<String, String> env = new HashMap<>();
+        env.put("E", "F");
+        env.put("G", "H");
+        VmInfo first = new VmInfo("agent1", "vm1", 8000, 50000L, Long.MIN_VALUE, "1.8.0", "/path/to/java", "myClass", 
+                "java myClass", "myJVM", "interesting", "1800", "-Dhello", props, env, new String[0], 1234L, "test");
+        
+        final Map<String, String> props2 = new HashMap<>();
+        final Map<String, String> env2 = new HashMap<>();
+        env2.put("A", "B");
+        env2.put("C", "D");
+        final String[] libs = { "libhello", "libworld" };
+        VmInfo second = new VmInfo("agent2", "vm2", 9000, 100000L, 200000L, "1.7.0", "/path/to/jre", "myOtherClass",
+                                   "otherClass.sh", "myOtherJVM", "info", "1700", "-Dworld", props2, env2, libs, 5678L, "user");
+        List<VmInfo> infos = Arrays.asList(first, second);
+        
+        String json = adapter.toJson(infos);
+        assertEquals(expected, json);
+    }
+    
+    @Test
+    public void testUpdate() throws Exception {
+        VmInfoUpdateTypeAdapter adapter = new VmInfoUpdateTypeAdapter();
+        final String expected = "{\"set\":{\"stopTimeStamp\":{\"$numberLong\":\"5000\"}}}";
+        
+        VmInfoUpdate update = new VmInfoUpdate(5000L);
+        String json = adapter.toJson(update);
+        assertEquals(expected, json);
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/distribution/assemblies/plugin-assembly.xml	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Copyright 2012-2017 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.
+
+-->
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+  <id>plugin-assembly</id>
+  <formats>
+    <format>zip</format>
+  </formats>
+  <includeBaseDirectory>false</includeBaseDirectory>
+  
+  <dependencySets>
+    <dependencySet>
+      <includes>
+        <include>com.redhat.thermostat:thermostat-jvm-overview-agent</include>
+      </includes>
+      <useProjectArtifact>false</useProjectArtifact>
+      <useStrictFiltering>true</useStrictFiltering>
+      <outputDirectory>plugins/${thermostat.plugin}</outputDirectory>
+    </dependencySet>
+  </dependencySets>
+
+  <fileSets>
+    <fileSet>
+      <includes>
+        <include>thermostat-plugin.xml</include>
+      </includes>
+      <outputDirectory>plugins/${thermostat.plugin}</outputDirectory>
+      <filtered>true</filtered>
+    </fileSet>
+  </fileSets>
+</assembly>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/distribution/pom.xml	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Copyright 2012-2017 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.redhat.thermostat</groupId>
+    <artifactId>thermostat-jvm-overview</artifactId>
+    <version>1.99.12-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>thermostat-jvm-overview-distribution</artifactId>
+  <packaging>pom</packaging>
+
+  <name>Thermostat JVM Overview plugin distribution</name>
+  
+  <properties>
+    <thermostat.plugin>jvm-overview</thermostat.plugin>
+  </properties>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <configuration>
+          <descriptors>
+            <descriptor>assemblies/plugin-assembly.xml</descriptor>
+          </descriptors>
+          <appendAssemblyId>false</appendAssemblyId>
+        </configuration>
+        <executions>
+          <execution>
+            <id>assemble-plugin</id>
+            <phase>package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  
+  <dependencies>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-jvm-overview-agent</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+
+</project>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/distribution/thermostat-plugin.xml	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,51 @@
+<?xml version="1.0"?>
+<!--
+
+ Copyright 2012-2017 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.
+
+-->
+<plugin xmlns="http://icedtea.classpath.org/thermostat/plugins/v1.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://icedtea.classpath.org/thermostat/plugins/v1.0 thermostat-plugin.xsd">
+  <extensions>
+    <extension>
+      <name>agent</name>
+      <bundles>
+        <bundle><symbolic-name>com.redhat.thermostat.jvm.overview</symbolic-name><version>${project.version}</version></bundle>
+      </bundles>
+    </extension>
+  </extensions>
+</plugin>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/jvm-overview/pom.xml	Fri Jun 09 16:38:44 2017 +0200
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Copyright 2012-2017 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.redhat.thermostat</groupId>
+    <artifactId>thermostat-plugins</artifactId>
+    <version>1.99.12-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>thermostat-jvm-overview</artifactId>
+  <packaging>pom</packaging>
+
+  <name>Thermostat JVM Overview plugin</name>
+
+  <modules>
+    <module>agent</module>
+    <module>distribution</module>
+  </modules>
+
+</project>
+
--- a/plugins/pom.xml	Thu Jun 08 20:16:03 2017 +0200
+++ b/plugins/pom.xml	Fri Jun 09 16:38:44 2017 +0200
@@ -54,14 +54,15 @@
     <!--<module>thread</module>-->
     <module>killvm</module>
     <module>host-overview</module>
+    <module>jvm-overview</module>
+    <module>vm-gc</module>
+    <module>vm-memory</module>
     <!--<module>host-cpu</module>-->
     <!--<module>host-memory</module>-->
     <!--<module>vm-byteman</module>-->
     <!--<module>vm-cpu</module>-->
-    <module>vm-gc</module>
     <!--<module>vm-classstat</module>-->
     <!--<module>vm-compiler</module>-->
-    <module>vm-memory</module>
     <!--<module>vm-heap-analysis</module>-->
     <!--<module>vm-io</module>-->
     <!--<module>vm-jmx</module>-->
--- a/plugins/vm-gc/agent/pom.xml	Thu Jun 08 20:16:03 2017 +0200
+++ b/plugins/vm-gc/agent/pom.xml	Fri Jun 09 16:38:44 2017 +0200
@@ -122,6 +122,11 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-jvm-overview-agent</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-common-test</artifactId>
       <version>${project.version}</version>
       <scope>test</scope>
--- a/plugins/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackend.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/plugins/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackend.java	Fri Jun 09 16:38:44 2017 +0200
@@ -36,17 +36,16 @@
 
 package com.redhat.thermostat.vm.gc.agent.internal;
 
+import com.redhat.thermostat.jvm.overview.agent.VmListenerBackend;
+import com.redhat.thermostat.jvm.overview.agent.VmStatusListenerRegistrar;
+import com.redhat.thermostat.jvm.overview.agent.VmUpdateListener;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.Service;
 import org.osgi.framework.BundleContext;
-
-import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
 import com.redhat.thermostat.backend.Backend;
-import com.redhat.thermostat.backend.VmListenerBackend;
-import com.redhat.thermostat.backend.VmUpdateListener;
 import com.redhat.thermostat.common.Version;
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.vm.gc.common.Constants;
--- a/plugins/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcDataExtractor.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/plugins/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcDataExtractor.java	Fri Jun 09 16:38:44 2017 +0200
@@ -36,8 +36,8 @@
 
 package com.redhat.thermostat.vm.gc.agent.internal;
 
-import com.redhat.thermostat.backend.VmUpdate;
-import com.redhat.thermostat.backend.VmUpdateException;
+import com.redhat.thermostat.jvm.overview.agent.VmUpdate;
+import com.redhat.thermostat.jvm.overview.agent.VmUpdateException;
 
 /**
  * A helper class to provide type-safe access to commonly used jvmstat monitors
--- a/plugins/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcVmListener.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/plugins/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcVmListener.java	Fri Jun 09 16:38:44 2017 +0200
@@ -39,10 +39,10 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-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.jvm.overview.agent.VmUpdate;
+import com.redhat.thermostat.jvm.overview.agent.VmUpdateException;
+import com.redhat.thermostat.jvm.overview.agent.VmUpdateListener;
 import com.redhat.thermostat.vm.gc.common.VmGcStatDAO;
 import com.redhat.thermostat.vm.gc.common.model.VmGcStat;
 
--- a/plugins/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackendTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/plugins/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackendTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -44,13 +44,13 @@
 import static org.mockito.Mockito.when;
 import static org.mockito.Mockito.verify;
 
+import com.redhat.thermostat.jvm.overview.agent.VmStatusListenerRegistrar;
 import org.junit.Before;
 import org.junit.Test;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Version;
 
-import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
 import com.redhat.thermostat.common.Ordered;
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.vm.gc.agent.internal.VmGcBackend.ListenerCreator;
--- a/plugins/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcDataExtractorTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/plugins/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcDataExtractorTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -41,12 +41,11 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import com.redhat.thermostat.jvm.overview.agent.VmUpdate;
+import com.redhat.thermostat.jvm.overview.agent.VmUpdateException;
 import org.junit.Before;
 import org.junit.Test;
 
-import com.redhat.thermostat.backend.VmUpdate;
-import com.redhat.thermostat.backend.VmUpdateException;
-
 public class VmGcDataExtractorTest {
 
     private VmGcDataExtractor extractor;
--- a/plugins/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcVmListenerTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/plugins/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcVmListenerTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -47,11 +47,11 @@
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
+import com.redhat.thermostat.jvm.overview.agent.VmUpdateException;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 
-import com.redhat.thermostat.backend.VmUpdateException;
 import com.redhat.thermostat.vm.gc.common.VmGcStatDAO;
 import com.redhat.thermostat.vm.gc.common.model.VmGcStat;
 
--- a/plugins/vm-memory/agent/pom.xml	Thu Jun 08 20:16:03 2017 +0200
+++ b/plugins/vm-memory/agent/pom.xml	Fri Jun 09 16:38:44 2017 +0200
@@ -111,6 +111,11 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-jvm-overview-agent</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-common-test</artifactId>
       <version>${project.version}</version>
       <scope>test</scope>
--- a/plugins/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/Activator.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/plugins/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/Activator.java	Fri Jun 09 16:38:44 2017 +0200
@@ -36,14 +36,14 @@
 
 package com.redhat.thermostat.vm.memory.agent.internal;
 
+import com.redhat.thermostat.jvm.overview.agent.VmListenerBackend;
+import com.redhat.thermostat.jvm.overview.agent.VmStatusListenerRegistrar;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
 
-import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
 import com.redhat.thermostat.backend.Backend;
 import com.redhat.thermostat.backend.BackendService;
-import com.redhat.thermostat.backend.VmListenerBackend;
 import com.redhat.thermostat.common.MultipleServiceTracker;
 import com.redhat.thermostat.common.MultipleServiceTracker.Action;
 import com.redhat.thermostat.common.MultipleServiceTracker.DependencyProvider;
--- a/plugins/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackend.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/plugins/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackend.java	Fri Jun 09 16:38:44 2017 +0200
@@ -36,10 +36,10 @@
 
 package com.redhat.thermostat.vm.memory.agent.internal;
 
-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.jvm.overview.agent.VmListenerBackend;
+import com.redhat.thermostat.jvm.overview.agent.VmStatusListenerRegistrar;
+import com.redhat.thermostat.jvm.overview.agent.VmUpdateListener;
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.vm.memory.common.Constants;
 import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO;
@@ -50,9 +50,11 @@
     private final VmMemoryStatDAO vmMemoryStats;
     private final VmTlabStatDAO tlabStats;
     
-    public VmMemoryBackend(VmMemoryStatDAO vmMemoryStatDAO, VmTlabStatDAO vmTlabStatDAO,
-            Version version,
-            VmStatusListenerRegistrar registrar, WriterID writerId) {
+    public VmMemoryBackend(VmMemoryStatDAO vmMemoryStatDAO,
+                           VmTlabStatDAO vmTlabStatDAO,
+                           Version version,
+                           VmStatusListenerRegistrar registrar,
+                           WriterID writerId) {
         super("VM Memory Backend",
                 "Gathers memory statistics about a JVM",
                 "Red Hat, Inc.",
--- a/plugins/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryDataExtractor.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/plugins/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryDataExtractor.java	Fri Jun 09 16:38:44 2017 +0200
@@ -36,8 +36,8 @@
 
 package com.redhat.thermostat.vm.memory.agent.internal;
 
-import com.redhat.thermostat.backend.VmUpdate;
-import com.redhat.thermostat.backend.VmUpdateException;
+import com.redhat.thermostat.jvm.overview.agent.VmUpdate;
+import com.redhat.thermostat.jvm.overview.agent.VmUpdateException;
 import com.redhat.thermostat.vm.memory.common.model.VmMemoryStat.Generation;
 
 /**
--- a/plugins/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryVmListener.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/plugins/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryVmListener.java	Fri Jun 09 16:38:44 2017 +0200
@@ -41,12 +41,12 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import com.redhat.thermostat.backend.VmUpdate;
-import com.redhat.thermostat.backend.VmUpdateException;
-import com.redhat.thermostat.backend.VmUpdateListener;
 import com.redhat.thermostat.common.Clock;
 import com.redhat.thermostat.common.SystemClock;
 import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.jvm.overview.agent.VmUpdate;
+import com.redhat.thermostat.jvm.overview.agent.VmUpdateException;
+import com.redhat.thermostat.jvm.overview.agent.VmUpdateListener;
 import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO;
 import com.redhat.thermostat.vm.memory.common.VmTlabStatDAO;
 import com.redhat.thermostat.vm.memory.common.model.VmMemoryStat;
--- a/plugins/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/ActivatorTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/plugins/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/ActivatorTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -43,13 +43,13 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import com.redhat.thermostat.jvm.overview.agent.VmListenerBackend;
 import org.junit.Test;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.Version;
 
 import com.redhat.thermostat.backend.Backend;
 import com.redhat.thermostat.backend.BackendService;
-import com.redhat.thermostat.backend.VmListenerBackend;
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.testutils.StubBundleContext;
 import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO;
--- a/plugins/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackendTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/plugins/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackendTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -40,10 +40,10 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import com.redhat.thermostat.jvm.overview.agent.VmStatusListenerRegistrar;
 import org.junit.Before;
 import org.junit.Test;
 
-import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
 import com.redhat.thermostat.common.Ordered;
 import com.redhat.thermostat.common.Version;
 import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO;
--- a/plugins/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryDataExtractorTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/plugins/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryDataExtractorTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -41,11 +41,11 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import com.redhat.thermostat.jvm.overview.agent.VmUpdate;
+import com.redhat.thermostat.jvm.overview.agent.VmUpdateException;
 import org.junit.Before;
 import org.junit.Test;
 
-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 {
--- a/plugins/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryVmListenerTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/plugins/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryVmListenerTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -46,12 +46,12 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import com.redhat.thermostat.jvm.overview.agent.VmUpdate;
+import com.redhat.thermostat.jvm.overview.agent.VmUpdateException;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 
-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.VmTlabStatDAO;
 import com.redhat.thermostat.vm.memory.common.model.VmMemoryStat;
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/HostsVMsLoader.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright 2012-2017 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.storage.core;
-
-import java.util.Collection;
-
-
-/**
- * Provides a way to load the current hosts and VMs.
- */
-public interface HostsVMsLoader {
-
-    Collection<HostRef> getHosts();
-    Collection<VmRef> getVMs(HostRef host);
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/VmBoundaryPojoGetter.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,120 +0,0 @@
-/*
- * Copyright 2012-2017 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.storage.core;
-
-import java.util.logging.Logger;
-
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.model.TimeStampedPojo;
-
-public class VmBoundaryPojoGetter<T extends TimeStampedPojo>  {
-
-    // QUERY %s WHERE 'agentId' = ?s AND \
-    //                        'vmId' = ?s \
-    //                        SORT 'timeStamp' DSC  \
-    //                        LIMIT 1
-    public static final String DESC_NEWEST_VM_STAT = "QUERY %s " +
-            "WHERE '" + Key.AGENT_ID.getName() + "' = ?s " +
-            "AND '" + Key.VM_ID.getName() + "' = ?s " +
-            "SORT '" + Key.TIMESTAMP.getName() + "' DSC " +
-            "LIMIT 1";
-
-    // QUERY %s WHERE 'agentId' = ?s AND \
-    //                        'vmId' = ?s \
-    //                        SORT 'timeStamp' ASC  \
-    //                        LIMIT 1
-    public static final String DESC_OLDEST_VM_STAT = "QUERY %s " +
-            "WHERE '" + Key.AGENT_ID.getName() + "' = ?s " +
-            "AND '" + Key.VM_ID.getName() + "' = ?s " +
-            "SORT '" + Key.TIMESTAMP.getName() + "' ASC " +
-            "LIMIT 1";
-
-    private static final Logger logger = LoggingUtils.getLogger(VmBoundaryPojoGetter.class);
-
-    private final Category<T> cat;
-    private final String queryNewest;
-    private final String queryOldest;
-
-    public VmBoundaryPojoGetter(Category<T> cat) {
-        this.cat = cat;
-        this.queryNewest = String.format(DESC_NEWEST_VM_STAT, cat.getName());
-        this.queryOldest = String.format(DESC_OLDEST_VM_STAT, cat.getName());
-    }
-
-    /**
-     * @deprecated use {@link #getNewestStat(VmId, AgentId)}
-     */
-    @Deprecated
-    public T getNewestStat(VmRef ref) {
-        return runAgentAndVmIdQuery(ref.getVmId(), ref.getHostRef().getAgentId(), queryNewest);
-    }
-
-    public T getNewestStat(VmId vmId, AgentId agentId) {
-        return runAgentAndVmIdQuery(vmId.get(), agentId.get(), queryNewest);
-    }
-
-    /**
-     * @deprecated use {@link #getOldestStat(VmId, AgentId)}
-     */
-    @Deprecated
-    public T getOldestStat(VmRef ref) {
-        return runAgentAndVmIdQuery(ref.getVmId(), ref.getHostRef().getAgentId(), queryOldest);
-    }
-
-    public T getOldestStat(VmId vmId, AgentId agentId) {
-        return runAgentAndVmIdQuery(vmId.get(), agentId.get(), queryOldest);
-    }
-
-    private T runAgentAndVmIdQuery(final String vmId, final String agentId, final String descriptor) {
-        return null;
-    }
-
-    //Package private for testing
-    String getNewestQueryDesc() {
-        return queryNewest;
-    }
-
-    //Package private for testing
-    String getOldestQueryDesc() {
-        return queryOldest;
-    }
-
-    protected Logger getLogger() {
-        return logger;
-    }
-
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/VmId.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright 2012-2017 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.storage.core;
-
-/**
- * This class uniquely identifies a Java Virtual Machine
- *
- */
-public class VmId extends Id {
-
-    public VmId(String id) {
-        super(id);
-    }
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/VmLatestPojoListGetter.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-/*
- * Copyright 2012-2017 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.storage.core;
-
-import java.util.List;
-import java.util.logging.Logger;
-
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.model.TimeStampedPojo;
-
-/**
- * Get a {@link List} of {@link TimeStampedPojo}s newer than a given time stamp.
- *
- * @see VmTimeIntervalPojoListGetter
- */
-public class VmLatestPojoListGetter<T extends TimeStampedPojo> {
-
-    public static final String VM_LATEST_QUERY_FORMAT = "QUERY %s WHERE '"
-            + Key.AGENT_ID.getName() + "' = ?s AND '"
-            + Key.VM_ID.getName() + "' = ?s AND '"
-            + Key.TIMESTAMP.getName() + "' > ?l SORT '"
-            + Key.TIMESTAMP.getName() + "' DSC";
-    private static final Logger logger = LoggingUtils.getLogger(VmLatestPojoListGetter.class);
-
-    private final Category<T> cat;
-    private final String queryLatest;
-
-    public VmLatestPojoListGetter(Category<T> cat) {
-        this.cat = cat;
-        this.queryLatest = String.format(VM_LATEST_QUERY_FORMAT, cat.getName());
-    }
-
-    /**
-     * @deprecated use {@link #getLatest(AgentId, VmId, long)}
-     */
-    @Deprecated
-    public List<T> getLatest(VmRef vmRef, long since) {
-        return getLatest(new AgentId(vmRef.getHostRef().getAgentId()), new VmId(vmRef.getVmId()), since);
-    }
-
-    public List<T> getLatest(final AgentId agentId, final VmId vmId, final long since) {
-        return null;
-    }
-
-    // package private for tests
-    String getQueryLatestDesc() {
-        return queryLatest;
-    }
-
-    public Logger getLogger() {
-        return logger;
-    }
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/VmRef.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-/*
- * Copyright 2012-2017 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.storage.core;
-
-import com.redhat.thermostat.storage.model.VmInfo;
-
-public class VmRef implements Ref {
-
-    private final HostRef hostRef;
-    private final String id;
-    private final Integer pid;
-    private final String name;
-
-    public VmRef(HostRef hostRef, String id, Integer pid, String name) {
-        this.hostRef = hostRef;
-        this.id = id;
-        this.pid = pid;
-        this.name = name;
-    }
-
-    public VmRef(HostRef hostRef, VmInfo vmInfo) {
-        this.hostRef = hostRef;
-        this.id = vmInfo.getVmId();
-        this.pid = vmInfo.getVmPid();
-        this.name = vmInfo.getMainClass();
-    }
-
-    @Override
-    public String toString() {
-        return name;
-    }
-
-    public HostRef getHostRef() {
-        return hostRef;
-    }
-    
-    public String getVmId() {
-        return id;
-    }
-    
-    public Integer getPid() {
-        return pid;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null) {
-            return false;
-        }
-        if (obj == this) {
-            return true;
-        }
-        if (obj.getClass() != this.getClass()) {
-            return false;
-        }
-        VmRef other = (VmRef) obj;
-        if (equals(this.hostRef, other.hostRef)
-                && equals(this.id, other.id)
-                && equals(this.pid, other.pid) && equals(this.name, other.name)) {
-            return true;
-        }
-        return false;
-    }
-
-    private static boolean equals(Object obj1, Object obj2) {
-        return (obj1 == null && obj2 == null) || (obj1 != null && obj1.equals(obj2));
-    }
-
-    @Override
-    public int hashCode() {
-        return id.hashCode();
-    }
-
-    @Override
-    public String getStringID() {
-        return id;
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/VmTimeIntervalPojoListGetter.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +0,0 @@
-/*
- * Copyright 2012-2017 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.storage.core;
-
-import java.util.List;
-import java.util.logging.Logger;
-
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.model.TimeStampedPojo;
-
-/**
- * Get a {@link List} of {@link TimeStampedPojo}s in a given time interval
- * range.
- *
- * @see VmLatestPojoListGetter
- */
-public class VmTimeIntervalPojoListGetter<T extends TimeStampedPojo>  {
-
-    // The query for VmTimeIntervalPojoListGetter should query for since <= timestamp < to
-    // in order not to miss data for multiple consecutive queries of the form [a, b), [b, c), ...
-    // If the query were since < timestamp < to then queries of (a, b), (b, c), ... would
-    // result in missed data at the endpoints (b, ...)
-    public static final String VM_INTERVAL_QUERY_FORMAT = "QUERY %s WHERE '"
-            + Key.AGENT_ID.getName() + "' = ?s AND '"
-            + Key.VM_ID.getName() + "' = ?s AND '"
-            + Key.TIMESTAMP.getName() + "' >= ?l AND '"
-            + Key.TIMESTAMP.getName() + "' < ?l SORT '"
-            + Key.TIMESTAMP.getName() + "' DSC";
-
-    private static final Logger logger = LoggingUtils.getLogger(VmTimeIntervalPojoListGetter.class);
-
-    private final Category<T> cat;
-    private final String query;
-
-    public VmTimeIntervalPojoListGetter(Category<T> cat) {
-        this.cat = cat;
-        this.query = String.format(VM_INTERVAL_QUERY_FORMAT, cat.getName());
-    }
-
-    /**
-     * @deprecated use {@link #getLatest(AgentId, VmId, long, long)}
-     */
-    @Deprecated
-    public List<T> getLatest(final VmRef vmRef, final long since, final long to) {
-        return getLatest(new AgentId(vmRef.getHostRef().getAgentId()), new VmId(vmRef.getVmId()), since, to);
-    }
-
-    public List<T> getLatest(final AgentId agentId, final VmId vmId, final long since, final long to) {
-        return null;
-    }
-
-    // package private for tests
-    String getQueryLatestDesc() {
-        return query;
-    }
-
-    protected Logger getLogger() {
-        return logger;
-    }
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/dao/VmInfoDAO.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright 2012-2017 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.storage.dao;
-
-import java.util.Set;
-
-import com.redhat.thermostat.annotations.Service;
-import com.redhat.thermostat.storage.core.AgentId;
-import com.redhat.thermostat.storage.core.VmId;
-import com.redhat.thermostat.storage.model.VmInfo;
-
-@Service
-public interface VmInfoDAO {
-
-    /** @return {@code null} if no information can be found */
-    VmInfo getVmInfo(VmId id);
-
-    /**
-     *
-     * @param agentId The id of host to get the VM(s) for.
-     * @return A set of the VmId(s).
-     */
-    Set<VmId> getVmIds(AgentId agentId);
-
-    void putVmInfo(VmInfo info);
-
-    void putVmStoppedTime(String agentId, String vmId, long since);
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/Activator.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/Activator.java	Fri Jun 09 16:38:44 2017 +0200
@@ -48,11 +48,9 @@
 import com.redhat.thermostat.storage.dao.AgentInfoDAO;
 import com.redhat.thermostat.storage.dao.BackendInfoDAO;
 import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.storage.internal.dao.AgentInfoDAOImpl;
 import com.redhat.thermostat.storage.internal.dao.BackendInfoDAOImpl;
 import com.redhat.thermostat.storage.internal.dao.NetworkInterfaceInfoDAOImpl;
-import com.redhat.thermostat.storage.internal.dao.VmInfoDAOImpl;
 
 public class Activator implements BundleActivator {
     
@@ -84,10 +82,6 @@
         NetworkInterfaceInfoDAO networkInfoDao = new NetworkInterfaceInfoDAOImpl();
         reg = context.registerService(NetworkInterfaceInfoDAO.class.getName(), networkInfoDao, null);
         regs.add(reg);
-
-        VmInfoDAO vmInfoDao = new VmInfoDAOImpl();
-        reg = context.registerService(VmInfoDAO.class.getName(), vmInfoDao, null);
-        regs.add(reg);
     }
 
     private void unregisterServices() {
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOImpl.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,249 +0,0 @@
-/*
- * Copyright 2012-2017 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.storage.internal.dao;
-
-import java.io.IOException;
-import java.net.URI;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.client.HttpContentResponse;
-import org.eclipse.jetty.client.HttpRequest;
-import org.eclipse.jetty.client.api.ContentResponse;
-import org.eclipse.jetty.client.api.Request;
-import org.eclipse.jetty.client.util.StringContentProvider;
-import org.eclipse.jetty.http.HttpMethod;
-import org.eclipse.jetty.http.HttpStatus;
-
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.core.AgentId;
-import com.redhat.thermostat.storage.core.VmId;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
-import com.redhat.thermostat.storage.internal.dao.VmInfoTypeAdapter.VmInfoUpdateTypeAdapter;
-import com.redhat.thermostat.storage.model.VmInfo;
-
-public class VmInfoDAOImpl implements VmInfoDAO {
-    
-    private final Logger logger = LoggingUtils.getLogger(VmInfoDAOImpl.class);
-    
-    private static final String GATEWAY_URL = "http://localhost:26000/api/v100"; // TODO configurable
-    private static final String GATEWAY_PATH = "/vm-info/systems/*/agents/";
-    private static final String GATEWAY_PATH_JVM_SUFFIX = "/jvms/";
-    private static final String CONTENT_TYPE = "application/json";
-    
-    private final HttpHelper httpHelper;
-    private final JsonHelper jsonHelper;
-
-    public VmInfoDAOImpl() throws Exception {
-        this(new HttpHelper(new HttpClient()), new JsonHelper(new VmInfoTypeAdapter(), new VmInfoUpdateTypeAdapter()));
-    }
-
-    VmInfoDAOImpl(HttpHelper httpHelper, JsonHelper jsonHelper) throws Exception {
-        this.jsonHelper = jsonHelper;
-        this.httpHelper = httpHelper;
-        
-        this.httpHelper.startClient();
-    }
-
-    @Override
-    public VmInfo getVmInfo(final VmId id) {
-        return null; // TODO Remove once VM Id completer is removed
-    }
-
-    @Override
-    public Set<VmId> getVmIds(AgentId agentId) {
-        return Collections.emptySet(); // TODO Remove once VM Id completer is removed
-    }
-
-    @Override
-    public void putVmInfo(final VmInfo info) {
-        try {
-            // Encode as JSON and send as POST request
-            String json = jsonHelper.toJson(Arrays.asList(info));
-            StringContentProvider provider = httpHelper.createContentProvider(json);
-            
-            String url = getAddURL(info.getAgentId());
-            Request httpRequest = httpHelper.newRequest(url);
-            httpRequest.method(HttpMethod.POST);
-            httpRequest.content(provider, CONTENT_TYPE);
-            sendRequest(httpRequest);
-        } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) {
-           logger.log(Level.WARNING, "Failed to send JVM information to web gateway", e);
-        }
-    }
-
-    @Override
-    public void putVmStoppedTime(final String agentId, final String vmId, final long timestamp) {
-        try {
-            // Encode as JSON and send as PUT request
-            VmInfoUpdate update = new VmInfoUpdate(timestamp);
-            String json = jsonHelper.toJson(update);
-            StringContentProvider provider = httpHelper.createContentProvider(json);
-            
-            String url = getUpdateURL(agentId, vmId);
-            Request httpRequest = httpHelper.newRequest(url);
-            httpRequest.method(HttpMethod.PUT);
-            httpRequest.content(provider, CONTENT_TYPE);
-            sendRequest(httpRequest);
-        } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) {
-           logger.log(Level.WARNING, "Failed to send JVM information update to web gateway", e);
-        }
-    }
-
-    private void sendRequest(Request httpRequest)
-            throws InterruptedException, TimeoutException, ExecutionException, IOException {
-        ContentResponse resp = httpRequest.send();
-        int status = resp.getStatus();
-        if (status != HttpStatus.OK_200) {
-            throw new IOException("Gateway returned HTTP status " + String.valueOf(status) + " - " + resp.getReason());
-        }
-    }
-    
-    private String getAddURL(String agentId) {
-        StringBuilder builder = buildURL(agentId);
-        return builder.toString();
-    }
-
-    private StringBuilder buildURL(String agentId) {
-        StringBuilder builder = new StringBuilder();
-        builder.append(GATEWAY_URL);
-        builder.append(GATEWAY_PATH);
-        builder.append(agentId);
-        return builder;
-    }
-    
-    private String getUpdateURL(String agentId, String vmId) {
-        StringBuilder builder = buildURL(agentId);
-        builder.append(GATEWAY_PATH_JVM_SUFFIX);
-        builder.append(vmId);
-        return builder.toString();
-    }
-    
-    static class VmInfoUpdate {
-        
-        private final long stoppedTime;
-        
-        VmInfoUpdate(long stoppedTime) {
-           this.stoppedTime = stoppedTime;
-        }
-        
-        long getStoppedTime() {
-            return stoppedTime;
-        }
-    }
-    
-    
-    // For testing purposes
-    static class JsonHelper {
-        
-        private final VmInfoTypeAdapter typeAdapter;
-        private final VmInfoUpdateTypeAdapter updateTypeAdapter;
-        
-        public JsonHelper(VmInfoTypeAdapter typeAdapter, VmInfoUpdateTypeAdapter updateTypeAdapter) {
-            this.typeAdapter = typeAdapter;
-            this.updateTypeAdapter = updateTypeAdapter;
-        }
-        
-        String toJson(List<VmInfo> infos) throws IOException {
-            return typeAdapter.toJson(infos);
-        }
-        
-        String toJson(VmInfoUpdate update) throws IOException {
-            return updateTypeAdapter.toJson(update);
-        }
-        
-    }
-    
-    // For testing purposes
-    static class HttpHelper {
-        
-        private final HttpClient httpClient;
-
-        HttpHelper(HttpClient httpClient) {
-            this.httpClient = httpClient;
-        }
-        
-        void startClient() throws Exception {
-            httpClient.start();
-        }
-        
-        StringContentProvider createContentProvider(String content) {
-            return new StringContentProvider(content);
-        }
-        
-        Request newRequest(String url) {
-            return new MockRequest(httpClient, URI.create(url));
-        }
-        
-    }
-    
-    // FIXME This class should be removed when the web gateway has a microservice for this DAO
-    private static class MockRequest extends HttpRequest {
-
-        MockRequest(HttpClient client, URI uri) {
-            super(client, uri);
-        }
-        
-        @Override
-        public ContentResponse send() throws InterruptedException, TimeoutException, ExecutionException {
-            return new MockResponse();
-        }
-        
-    }
-    
-    // FIXME This class should be removed when the web gateway has a microservice for this DAO
-    private static class MockResponse extends HttpContentResponse {
-
-        MockResponse() {
-            super(null, null, null);
-        }
-        
-        @Override
-        public int getStatus() {
-            return HttpStatus.OK_200;
-        }
-        
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/VmInfoTypeAdapter.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,198 +0,0 @@
-/*
- * Copyright 2012-2017 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.storage.internal.dao;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import com.google.gson.TypeAdapter;
-import com.google.gson.stream.JsonReader;
-import com.google.gson.stream.JsonWriter;
-import com.redhat.thermostat.storage.internal.dao.VmInfoDAOImpl.VmInfoUpdate;
-import com.redhat.thermostat.storage.model.VmInfo;
-
-public class VmInfoTypeAdapter extends TypeAdapter<List<VmInfo>> {
-    
-    private static final String AGENT_ID = "agentId";
-    private static final String VM_ID = "vmId";
-    private static final String VM_PID = "vmPid";
-    private static final String JAVA_VERSION = "javaVersion";
-    private static final String JAVA_HOME = "javaHome";
-    private static final String MAIN_CLASS = "mainClass";
-    private static final String JAVA_COMMAND_LINE = "javaCommandLine";
-    private static final String VM_ARGUMENTS = "vmArguments";
-    private static final String VM_NAME = "vmName";
-    private static final String VM_INFO = "vmInfo";
-    private static final String VM_VERSION = "vmVersion";
-    private static final String PROPERTIES_AS_ARRAY = "propertiesAsArray";
-    private static final String ENVIRONMENT_AS_ARRAY = "environmentAsArray";
-    private static final String LOADED_NATIVE_LIBRARIES = "loadedNativeLibraries";
-    private static final String START_TIME_STAMP = "startTimeStamp";
-    private static final String STOP_TIME_STAMP = "stopTimeStamp";
-    private static final String UID = "uid";
-    private static final String USERNAME = "username";
-    private static final String TYPE_LONG = "$numberLong";
-    private static final String KEY = "key";
-    private static final String VALUE = "value";
-    
-    @Override
-    public void write(JsonWriter out, List<VmInfo> value) throws IOException {
-        // Request is an array of VmInfo objects
-        out.beginArray();
-        
-        for (VmInfo info : value) {
-            writeVmInfo(out, info);
-        }
-        
-        out.endArray();
-    }
-
-    private void writeVmInfo(JsonWriter out, VmInfo info) throws IOException {
-        out.beginObject();
-        
-        // Write each field of VmInfo as part of a JSON object
-        out.name(AGENT_ID);
-        out.value(info.getAgentId());
-        out.name(VM_ID);
-        out.value(info.getVmId());
-        out.name(VM_PID);
-        out.value(info.getVmPid());
-        out.name(START_TIME_STAMP);
-        writeLong(out, info.getStartTimeStamp());
-        out.name(STOP_TIME_STAMP);
-        writeLong(out, info.getStopTimeStamp());
-        out.name(JAVA_VERSION);
-        out.value(info.getJavaVersion());
-        out.name(JAVA_HOME);
-        out.value(info.getJavaHome());
-        out.name(MAIN_CLASS);
-        out.value(info.getMainClass());
-        out.name(JAVA_COMMAND_LINE);
-        out.value(info.getJavaCommandLine());
-        out.name(VM_NAME);
-        out.value(info.getVmName());
-        out.name(VM_ARGUMENTS);
-        out.value(info.getVmArguments());
-        out.name(VM_INFO);
-        out.value(info.getVmInfo());
-        out.name(VM_VERSION);
-        out.value(info.getVmVersion());
-        out.name(PROPERTIES_AS_ARRAY);
-        writeStringMap(out, info.getProperties());
-        out.name(ENVIRONMENT_AS_ARRAY);
-        writeStringMap(out, info.getEnvironment());
-        out.name(LOADED_NATIVE_LIBRARIES);
-        writeStringArray(out, info.getLoadedNativeLibraries());
-        out.name(UID);
-        writeLong(out, info.getUid());
-        out.name(USERNAME);
-        out.value(info.getUsername());
-        
-        out.endObject();
-    }
-    
-    private void writeStringMap(JsonWriter out, Map<String, String> map) throws IOException {
-        // Write contents of Map as an array of JSON objects
-        out.beginArray();
-        
-        Set<Entry<String, String>> entries = map.entrySet();
-        for (Map.Entry<String, String> entry : entries) {
-            // Create JSON object with key and value labeled as JSON names
-            out.beginObject();
-            out.name(KEY);
-            out.value(entry.getKey());
-            out.name(VALUE);
-            out.value(entry.getValue());
-            out.endObject();
-        }
-        
-        out.endArray();
-    }
-    
-    private void writeStringArray(JsonWriter out, String[] array) throws IOException {
-        // Write String[] as JSON array
-        out.beginArray();
-        
-        for (String item : array) {
-            out.value(item);
-        }
-        
-        out.endArray();
-    }
-    
-    private static void writeLong(JsonWriter out, long value) throws IOException {
-        // Write MongoDB representation of a Long
-        out.beginObject();
-        out.name(TYPE_LONG);
-        out.value(String.valueOf(value));
-        out.endObject();
-    }
-
-    @Override
-    public List<VmInfo> read(JsonReader in) throws IOException {
-        throw new UnsupportedOperationException();
-    }
-    
-    static class VmInfoUpdateTypeAdapter extends TypeAdapter<VmInfoUpdate> {
-
-        private static final String SET = "set";
-        
-        @Override
-        public void write(JsonWriter out, VmInfoUpdate value) throws IOException {
-            // List fields to update as part of a JSON object with name "set"
-            out.beginObject();
-            out.name(SET);
-            
-            out.beginObject();
-            out.name(STOP_TIME_STAMP);
-            writeLong(out, value.getStoppedTime());
-            out.endObject();
-            
-            out.endObject();
-        }
-
-        @Override
-        public VmInfoUpdate read(JsonReader in) throws IOException {
-            throw new UnsupportedOperationException();
-        }
-        
-    }
-    
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/model/VmInfo.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,387 +0,0 @@
-/*
- * Copyright 2012-2017 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.storage.model;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import com.redhat.thermostat.storage.core.Entity;
-import com.redhat.thermostat.storage.core.Persist;
-
-@Entity
-public class VmInfo extends BasePojo {
-
-    public enum AliveStatus {
-        RUNNING,
-        EXITED,
-        /**
-         * We don't know what the status of this VM is. Possible cause: agent
-         * was shut down before the VM was.
-         */
-        UNKNOWN,
-    }
-
-    @Entity
-    public static class KeyValuePair implements Pojo {
-    
-        private String key;
-        private String value;
-
-        public KeyValuePair() {
-            this(null, null);
-        }
-
-        public KeyValuePair(String key, String value) {
-            this.key = key;
-            this.value = value;
-        }
-
-        @Persist
-        public String getKey() {
-            return key;
-        }
-
-        @Persist
-        public void setKey(String key) {
-            this.key = key;
-        }
-
-        @Persist
-        public String getValue() {
-            return value;
-        }
-
-        @Persist
-        public void setValue(String value) {
-            this.value = value;
-        }
-
-        
-    }
-
-    private String vmId;
-    private int vmPid = 0;
-    private long startTime = System.currentTimeMillis();
-    private long stopTime = Long.MIN_VALUE;
-    private String javaVersion = "unknown";
-    private String javaHome = "unknown";
-    private String javaCommandLine = "unknown";
-    private String mainClass = "unknown";
-    private String vmName = "unknown";
-    private String vmInfo = "unknown";
-    private String vmVersion = "unknown";
-    private String vmArguments = "unknown";
-    private Map<String, String> properties = new HashMap<String, String>();
-    private Map<String, String> environment = new HashMap<String, String>();
-    private String[] loadedNativeLibraries;
-    private long uid;
-    private String username;
-
-    public VmInfo() {
-        /* use defaults */
-        super(null);
-    }
-
-    public VmInfo(String writerId, String vmId, int vmPid, long startTime, long stopTime,
-            String javaVersion, String javaHome,
-            String mainClass, String commandLine,
-            String vmName, String vmInfo, String vmVersion, String vmArguments,
-            Map<String, String> properties, Map<String, String> environment, String[] loadedNativeLibraries,
-            long uid, String username) {
-        super(writerId);
-        this.vmId = vmId;
-        this.vmPid = vmPid;
-        this.startTime = startTime;
-        this.stopTime = stopTime;
-        this.javaVersion = javaVersion;
-        this.javaHome = javaHome;
-        this.mainClass = mainClass;
-        this.javaCommandLine = commandLine;
-        this.vmName = vmName;
-        this.vmInfo = vmInfo;
-        this.vmVersion = vmVersion;
-        this.vmArguments = vmArguments;
-        this.properties = properties;
-        this.environment = environment;
-        this.loadedNativeLibraries = loadedNativeLibraries;
-        this.uid = uid;
-        this.username = username;
-    }
-
-    @Persist
-    public String getVmId() {
-        return vmId;
-    }
-
-    @Persist
-    public void setVmId(String vmId) {
-        this.vmId = vmId;
-    }
-
-    @Persist
-    public int getVmPid() {
-        return vmPid;
-    }
-
-    @Persist
-    public void setVmPid(int vmPid) {
-        this.vmPid = vmPid;
-    }
-
-    @Persist
-    public long getStartTimeStamp() {
-        return startTime;
-    }
-
-    @Persist
-    public void setStartTimeStamp(long startTime) {
-        this.startTime = startTime;
-    }
-
-    @Persist
-    public long getStopTimeStamp() {
-        return stopTime;
-    }
-
-    @Persist
-    public void setStopTimeStamp(long stopTime) {
-        this.stopTime = stopTime;
-    }
-
-    @Persist
-    public String getJavaVersion() {
-        return javaVersion;
-    }
-
-    @Persist
-    public void setJavaVersion(String javaVersion) {
-        this.javaVersion = javaVersion;
-    }
-
-    @Persist
-    public String getJavaHome() {
-        return javaHome;
-    }
-
-    @Persist
-    public void setJavaHome(String javaHome) {
-        this.javaHome = javaHome;
-    }
-
-    /**
-     * If java is invoked as {@code java -jar foo.jar}, then the main class name
-     * is {@code foo.jar}.
-     */
-    @Persist
-    public String getMainClass() {
-        return mainClass;
-    }
-
-    @Persist
-    public void setMainClass(String mainClass) {
-        this.mainClass = mainClass;
-    }
-
-    @Persist
-    public String getJavaCommandLine() {
-        return javaCommandLine;
-    }
-
-    @Persist
-    public void setJavaCommandLine(String javaCommandLine) {
-        this.javaCommandLine = javaCommandLine;
-    }
-
-    @Persist
-    public String getVmName() {
-        return vmName;
-    }
-
-    @Persist
-    public void setVmName(String vmName) {
-        this.vmName = vmName;
-    }
-
-    @Persist
-    public String getVmArguments() {
-        return vmArguments;
-    }
-
-    @Persist
-    public void setVmArguments(String vmArguments) {
-        this.vmArguments = vmArguments;
-    }
-
-    @Persist
-    public String getVmInfo() {
-        return vmInfo;
-    }
-
-    @Persist
-    public void setVmInfo(String vmInfo) {
-        this.vmInfo = vmInfo;
-    }
-
-    @Persist
-    public String getVmVersion() {
-        return vmVersion;
-    }
-
-    @Persist
-    public void setVmVersion(String vmVersion) {
-        this.vmVersion = vmVersion;
-    }
-
-    /**
-     * @deprecated This can incorrectly show a VM as running when the actual
-     *             status is unknown. Use {@link #isAlive(AgentInformation)}
-     *             instead.
-     */
-    @Deprecated
-    public boolean isAlive() {
-        return getStartTimeStamp() > getStopTimeStamp();
-    }
-
-    public AliveStatus isAlive(AgentInformation agentInfo) {
-        if (agentInfo.isAlive()) {
-            return (isAlive() ? AliveStatus.RUNNING : AliveStatus.EXITED);
-        } else {
-            return (isAlive() ? AliveStatus.UNKNOWN: AliveStatus.EXITED);
-        }
-    }
-
-    public Map<String, String> getProperties() {
-        return properties;
-    }
-
-    public void setProperties(Map<String, String> properties) {
-        this.properties = properties;
-    }
-
-    @Persist
-    public KeyValuePair[] getPropertiesAsArray() {
-        return getMapAsArray(properties);
-    }
-
-    @Persist
-    public void setPropertiesAsArray(KeyValuePair[] properties) {
-        this.properties = getArrayAsMap(properties);
-    }
-
-    public Map<String, String> getEnvironment() {
-        return environment;
-    }
-
-    public void setEnvironment(Map<String, String> environment) {
-        this.environment = environment;
-    }
-
-    @Persist
-    public KeyValuePair[] getEnvironmentAsArray() {
-        return getMapAsArray(environment);
-    }
-
-    @Persist
-    public void setEnvironmentAsArray(KeyValuePair[] environment) {
-        this.environment = getArrayAsMap(environment);
-    }
-
-    private KeyValuePair[] getMapAsArray(Map<String, String> map) {
-        if (map == null) {
-            return null;
-        }
-        Set<String> keys = map.keySet();
-        KeyValuePair[] tuples = new KeyValuePair[keys.size()];
-        int i = 0;
-        for (String key: keys) {
-            tuples[i] = new KeyValuePair(key, map.get(key));
-            i++;
-        }
-        return tuples;
-    }
-
-    private Map<String,String> getArrayAsMap(KeyValuePair[] tuples) {
-        if (tuples == null) {
-            return null;
-        }
-        Map<String,String> map = new HashMap<>();
-        for (KeyValuePair tuple : tuples) {
-            map.put(tuple.getKey(), tuple.getValue());
-        }
-        return map;
-    }
-
-    @Persist
-    public String[] getLoadedNativeLibraries() {
-        return loadedNativeLibraries;
-    }
-
-    @Persist
-    public void setLoadedNativeLibraries(String[] loadedNativeLibraries) {
-        this.loadedNativeLibraries = loadedNativeLibraries;
-    }
-    
-    /**
-     * Returns the system user id for the owner of this JVM process,
-     * or -1 if an owner could not be found.
-     */
-    @Persist
-    public long getUid() {
-        return uid;
-    }
-    
-    @Persist
-    public void setUid(long uid) {
-        this.uid = uid;
-    }
-    
-    /**
-     * Returns the system user name for the owner of this JVM process,
-     * or null if an owner could not be found.
-     */
-    @Persist
-    public String getUsername() {
-        return username;
-    }
-    
-    @Persist
-    public void setUsername(String username) {
-        this.username = username;
-    }
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/VmIdTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Copyright 2012-2017 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.storage.core;
-
-public class VmIdTest extends IdTest {
-
-    @Override
-    protected VmId createId(String id) { return new VmId(id); }
-}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/ActivatorTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/ActivatorTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -51,11 +51,9 @@
 import com.redhat.thermostat.storage.dao.AgentInfoDAO;
 import com.redhat.thermostat.storage.dao.BackendInfoDAO;
 import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.storage.internal.dao.AgentInfoDAOImpl;
 import com.redhat.thermostat.storage.internal.dao.BackendInfoDAOImpl;
 import com.redhat.thermostat.storage.internal.dao.NetworkInterfaceInfoDAOImpl;
-import com.redhat.thermostat.storage.internal.dao.VmInfoDAOImpl;
 import com.redhat.thermostat.testutils.StubBundleContext;
 
 public class ActivatorTest {
@@ -69,7 +67,6 @@
 
         assertTrue(context.isServiceRegistered(WriterID.class.getName(), WriterIDImpl.class));
         assertTrue(context.isServiceRegistered(NetworkInterfaceInfoDAO.class.getName(), NetworkInterfaceInfoDAOImpl.class));
-        assertTrue(context.isServiceRegistered(VmInfoDAO.class.getName(), VmInfoDAOImpl.class));
         assertTrue(context.isServiceRegistered(AgentInfoDAO.class.getName(), AgentInfoDAOImpl.class));
         assertTrue(context.isServiceRegistered(BackendInfoDAO.class.getName(), BackendInfoDAOImpl.class));
 
@@ -90,7 +87,6 @@
         activator.stop(context);
         
         assertFalse(context.isServiceRegistered(NetworkInterfaceInfoDAO.class.getName(), NetworkInterfaceInfoDAOImpl.class));
-        assertFalse(context.isServiceRegistered(VmInfoDAO.class.getName(), VmInfoDAOImpl.class));
         assertFalse(context.isServiceRegistered(AgentInfoDAO.class.getName(), AgentInfoDAOImpl.class));
         assertFalse(context.isServiceRegistered(BackendInfoDAO.class.getName(), BackendInfoDAOImpl.class));
         assertFalse(context.isServiceRegistered(WriterID.class.getName(), WriterIDImpl.class));
@@ -114,7 +110,6 @@
         activator.start(context);
 
         assertTrue(context.isServiceRegistered(NetworkInterfaceInfoDAO.class.getName(), NetworkInterfaceInfoDAOImpl.class));
-        assertTrue(context.isServiceRegistered(VmInfoDAO.class.getName(), VmInfoDAOImpl.class));
         assertTrue(context.isServiceRegistered(AgentInfoDAO.class.getName(), AgentInfoDAOImpl.class));
         assertTrue(context.isServiceRegistered(BackendInfoDAO.class.getName(), BackendInfoDAOImpl.class));
         assertTrue(context.isServiceRegistered(WriterID.class.getName(), WriterIDImpl.class));
@@ -127,7 +122,6 @@
         activator.start(context);
 
         assertTrue(context.isServiceRegistered(NetworkInterfaceInfoDAO.class.getName(), NetworkInterfaceInfoDAOImpl.class));
-        assertTrue(context.isServiceRegistered(VmInfoDAO.class.getName(), VmInfoDAOImpl.class));
         assertTrue(context.isServiceRegistered(AgentInfoDAO.class.getName(), AgentInfoDAOImpl.class));
         assertTrue(context.isServiceRegistered(BackendInfoDAO.class.getName(), BackendInfoDAOImpl.class));
         assertTrue(context.isServiceRegistered(WriterID.class.getName(), WriterIDImpl.class));
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,153 +0,0 @@
-/*
- * Copyright 2012-2017 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.storage.internal.dao;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyListOf;
-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.when;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.eclipse.jetty.client.api.ContentResponse;
-import org.eclipse.jetty.client.api.Request;
-import org.eclipse.jetty.client.util.StringContentProvider;
-import org.eclipse.jetty.http.HttpMethod;
-import org.eclipse.jetty.http.HttpStatus;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
-import com.redhat.thermostat.storage.internal.dao.VmInfoDAOImpl.HttpHelper;
-import com.redhat.thermostat.storage.internal.dao.VmInfoDAOImpl.JsonHelper;
-import com.redhat.thermostat.storage.internal.dao.VmInfoDAOImpl.VmInfoUpdate;
-import com.redhat.thermostat.storage.model.VmInfo;
-
-public class VmInfoDAOTest {
-
-    private static final String URL = "http://localhost:26000/api/v100/vm-info/systems/*/agents/foo-agent";
-    private static final String UPDATE_URL = URL + "/jvms/vmId";
-    private static final String SOME_JSON = "{\"some\" : \"json\"}";
-    private static final String SOME_OTHER_JSON = "{\"some\" : {\"other\" : \"json\"}}";
-    private static final String CONTENT_TYPE = "application/json";
-    
-    private VmInfo info;
-    private JsonHelper jsonHelper;
-    private HttpHelper httpHelper;
-    private StringContentProvider contentProvider;
-    private Request request;
-    private ContentResponse response;
-
-    @Before
-    public void setUp() throws Exception {
-        String vmId = "vmId";
-        int vmPid = 1;
-        long startTime = 2L;
-        long stopTime = Long.MIN_VALUE;
-        String jVersion = "java 1.0";
-        String jHome = "/path/to/jdk/home";
-        String mainClass = "Hello.class";
-        String commandLine = "World";
-        String vmArgs = "-XX=+FastestJITPossible";
-        String vmName = "Hotspot";
-        String vmInfo = "Some info";
-        String vmVersion = "1.0";
-        Map<String, String> props = new HashMap<>();
-        Map<String, String> env = new HashMap<>();
-        String[] libs = new String[0];
-        long uid = 2000L;
-        String username = "myUser";
-        info = new VmInfo("foo-agent", vmId, vmPid, startTime, stopTime, jVersion, jHome,
-                mainClass, commandLine, vmName, vmInfo, vmVersion, vmArgs,
-                props, env, libs, uid, username);
-        
-        httpHelper = mock(HttpHelper.class);
-        contentProvider = mock(StringContentProvider.class);
-        when(httpHelper.createContentProvider(anyString())).thenReturn(contentProvider);
-        request = mock(Request.class);
-        when(httpHelper.newRequest(anyString())).thenReturn(request);
-        response = mock(ContentResponse.class);
-        when(response.getStatus()).thenReturn(HttpStatus.OK_200);
-        when(request.send()).thenReturn(response);
-        
-        jsonHelper = mock(JsonHelper.class);
-        when(jsonHelper.toJson(anyListOf(VmInfo.class))).thenReturn(SOME_JSON);
-        when(jsonHelper.toJson(any(VmInfoUpdate.class))).thenReturn(SOME_OTHER_JSON);
-    }
-
-    @Test
-    public void testPutVmInfo() throws Exception {
-        VmInfoDAO dao = new VmInfoDAOImpl(httpHelper, jsonHelper);
-        dao.putVmInfo(info);
-        
-        verify(httpHelper).newRequest(URL);
-        verify(request).method(HttpMethod.POST);
-        verify(jsonHelper).toJson(eq(Arrays.asList(info)));
-        verify(httpHelper).createContentProvider(SOME_JSON);
-        verify(request).content(contentProvider, CONTENT_TYPE);
-        verify(request).send();
-        verify(response).getStatus();
-    }
-
-    @Test
-    public void testPutVmStoppedTime() throws Exception {
-        VmInfoDAO dao = new VmInfoDAOImpl(httpHelper, jsonHelper);
-        dao.putVmStoppedTime("foo-agent", "vmId", 3L);
-
-        verify(httpHelper).newRequest(UPDATE_URL);
-        verify(request).method(HttpMethod.PUT);
-        
-        ArgumentCaptor<VmInfoUpdate> updateCaptor = ArgumentCaptor.forClass(VmInfoUpdate.class);
-        verify(jsonHelper).toJson(updateCaptor.capture());
-        VmInfoUpdate update = updateCaptor.getValue();
-        assertEquals(3L, update.getStoppedTime());
-                
-        verify(httpHelper).createContentProvider(SOME_OTHER_JSON);
-        verify(request).content(contentProvider, CONTENT_TYPE);
-        verify(request).send();
-        verify(response).getStatus();
-    }
-
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/VmInfoTypeAdapterTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-/*
- * Copyright 2012-2017 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.storage.internal.dao;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.internal.dao.VmInfoDAOImpl.VmInfoUpdate;
-import com.redhat.thermostat.storage.internal.dao.VmInfoTypeAdapter.VmInfoUpdateTypeAdapter;
-import com.redhat.thermostat.storage.model.VmInfo;
-
-public class VmInfoTypeAdapterTest {
-    
-    @Test
-    public void testWrite() throws Exception {
-        VmInfoTypeAdapter adapter = new VmInfoTypeAdapter();
-        final String expected = "[{\"agentId\":\"agent1\",\"vmId\":\"vm1\",\"vmPid\":8000,"
-                + "\"startTimeStamp\":{\"$numberLong\":\"50000\"},\"stopTimeStamp\":"
-                + "{\"$numberLong\":\"-9223372036854775808\"},\"javaVersion\":\"1.8.0\","
-                + "\"javaHome\":\"/path/to/java\",\"mainClass\":\"myClass\",\"javaCommandLine\":\"java myClass\","
-                + "\"vmName\":\"myJVM\",\"vmArguments\":\"-Dhello\",\"vmInfo\":\"interesting\","
-                + "\"vmVersion\":\"1800\",\"propertiesAsArray\":[{\"key\":\"A\",\"value\":\"B\"},"
-                + "{\"key\":\"C\",\"value\":\"D\"}],\"environmentAsArray\":[{\"key\":\"E\",\"value\":\"F\"},"
-                + "{\"key\":\"G\",\"value\":\"H\"}],\"loadedNativeLibraries\":[],\"uid\":{\"$numberLong\":\"1234\"},"
-                + "\"username\":\"test\"},"
-                + "{\"agentId\":\"agent2\",\"vmId\":\"vm2\",\"vmPid\":9000,\"startTimeStamp\":"
-                + "{\"$numberLong\":\"100000\"},\"stopTimeStamp\":{\"$numberLong\":\"200000\"},"
-                + "\"javaVersion\":\"1.7.0\",\"javaHome\":\"/path/to/jre\",\"mainClass\":\"myOtherClass\","
-                + "\"javaCommandLine\":\"otherClass.sh\",\"vmName\":\"myOtherJVM\",\"vmArguments\":\"-Dworld\","
-                + "\"vmInfo\":\"info\",\"vmVersion\":\"1700\",\"propertiesAsArray\":[],\"environmentAsArray\":"
-                + "[{\"key\":\"A\",\"value\":\"B\"},{\"key\":\"C\",\"value\":\"D\"}],"
-                + "\"loadedNativeLibraries\":[\"libhello\",\"libworld\"],\"uid\":{\"$numberLong\":\"5678\"}"
-                + ",\"username\":\"user\"}]";
-        
-        final Map<String, String> props = new HashMap<>();
-        props.put("A", "B");
-        props.put("C", "D");
-        final Map<String, String> env = new HashMap<>();
-        env.put("E", "F");
-        env.put("G", "H");
-        VmInfo first = new VmInfo("agent1", "vm1", 8000, 50000L, Long.MIN_VALUE, "1.8.0", "/path/to/java", "myClass", 
-                "java myClass", "myJVM", "interesting", "1800", "-Dhello", props, env, new String[0], 1234L, "test");
-        
-        final Map<String, String> props2 = new HashMap<>();
-        final Map<String, String> env2 = new HashMap<>();
-        env2.put("A", "B");
-        env2.put("C", "D");
-        final String[] libs = { "libhello", "libworld" };
-        VmInfo second = new VmInfo("agent2", "vm2", 9000, 100000L, 200000L, "1.7.0", "/path/to/jre", "myOtherClass", 
-                "otherClass.sh", "myOtherJVM", "info", "1700", "-Dworld", props2, env2, libs, 5678L, "user");
-        List<VmInfo> infos = Arrays.asList(first, second);
-        
-        String json = adapter.toJson(infos);
-        assertEquals(expected, json);
-    }
-    
-    @Test
-    public void testUpdate() throws Exception {
-        VmInfoUpdateTypeAdapter adapter = new VmInfoUpdateTypeAdapter();
-        final String expected = "{\"set\":{\"stopTimeStamp\":{\"$numberLong\":\"5000\"}}}";
-        
-        VmInfoUpdate update = new VmInfoUpdate(5000L);
-        String json = adapter.toJson(update);
-        assertEquals(expected, json);
-    }
-    
-}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/model/PojoModelInstantiationTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/model/PojoModelInstantiationTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -44,7 +44,6 @@
         AgentInformation.class,
         BackendInformation.class,
         NetworkInterfaceInfo.class,
-        VmInfo.class,
     };
 
     @Override
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/InfoBuilderFactoryImpl.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/*
- * Copyright 2012-2017 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.system.internal;
-
-import com.redhat.thermostat.backend.system.internal.models.InfoBuilderFactory;
-import com.redhat.thermostat.backend.system.internal.models.ProcessEnvironmentBuilder;
-import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder;
-import com.redhat.thermostat.common.portability.ProcessUserInfoBuilderFactory;
-import com.redhat.thermostat.common.portability.UserNameUtil;
-import com.redhat.thermostat.common.portability.linux.ProcDataSource;
-
-/**
- * Allows callers to access Windows-specific builders portably
- */
-public class InfoBuilderFactoryImpl implements InfoBuilderFactory {
-
-    public InfoBuilderFactoryImpl() {
-    }
-
-    public ProcessEnvironmentBuilder createProcessEnvironmentBuilder() {
-        return new ProcessEnvironmentBuilderImpl();
-    }
-
-    public ProcessUserInfoBuilder createProcessUserInfoBuilder(final UserNameUtil userNameUtil) {
-        return ProcessUserInfoBuilderFactory.createBuilder(new ProcDataSource(), userNameUtil);
-    }
-}
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/JvmStatDataExtractor.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-/*
- * Copyright 2012-2017 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.system.internal;
-
-import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredVm;
-import sun.jvmstat.monitor.MonitoredVmUtil;
-
-/**
- * A helper class to provide type-safe access to commonly used jvmstat monitors
- * <p>
- * Implementation details: For local vms, jvmstat uses a ByteBuffer
- * corresponding to mmap()ed hsperfdata file. The hsperfdata file is updated
- * asynchronously by the vm that created the file. The polling that jvmstat api
- * provides is merely an abstraction over this (possibly always up-to-date)
- * ByteBuffer. So the data this class extracts is as current as possible, and
- * does not correspond to when the jvmstat update events fired.
- */
-public class JvmStatDataExtractor {
-
-    /*
-     * Note, there may be a performance issue to consider here. We have a lot of
-     * string constants. When we start adding some of the more heavyweight
-     * features, and running into CPU issues this may need to be reconsidered in
-     * order to avoid the String pool overhead. See also:
-     * http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#intern()
-     */
-
-    private final MonitoredVm vm;
-
-    public JvmStatDataExtractor(MonitoredVm vm) {
-        this.vm = vm;
-    }
-
-    public String getCommandLine() throws MonitorException {
-        return MonitoredVmUtil.commandLine(vm);
-    }
-
-    public String getMainClass() throws MonitorException {
-        return MonitoredVmUtil.mainClass(vm, true);
-    }
-
-    public String getJavaVersion() throws MonitorException {
-        return (String) vm.findByName("java.property.java.version").getValue();
-    }
-
-    public String getJavaHome() throws MonitorException {
-        return (String) vm.findByName("java.property.java.home").getValue();
-    }
-
-    public String getVmName() throws MonitorException {
-        return (String) vm.findByName("java.property.java.vm.name").getValue();
-    }
-
-    public String getVmInfo() throws MonitorException {
-        return (String) vm.findByName("java.property.java.vm.info").getValue();
-    }
-
-    public String getVmVersion() throws MonitorException {
-        return (String) vm.findByName("java.property.java.vm.version").getValue();
-    }
-
-    public String getVmArguments() throws MonitorException {
-        return MonitoredVmUtil.jvmArgs(vm);
-    }
-
-    public long getVmStartTime() throws MonitorException {
-        return (long) vm.findByName("sun.rt.vmInitDoneTime").getValue();
-    }
-
-}
-
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/JvmStatHostListener.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,188 +0,0 @@
-/*
- * Copyright 2012-2017 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.system.internal;
-
-import java.net.URISyntaxException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.redhat.thermostat.agent.VmBlacklist;
-import com.redhat.thermostat.agent.VmStatusListener.Status;
-import com.redhat.thermostat.backend.system.internal.models.InfoBuilderFactory;
-import com.redhat.thermostat.common.Pair;
-import com.redhat.thermostat.common.portability.ProcessUserInfo;
-import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.core.WriterID;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
-import com.redhat.thermostat.storage.model.VmInfo;
-
-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.HostEvent;
-import sun.jvmstat.monitor.event.HostListener;
-import sun.jvmstat.monitor.event.VmStatusChangeEvent;
-
-class JvmStatHostListener implements HostListener {
-
-    private static final Logger logger = LoggingUtils.getLogger(JvmStatHostListener.class);
-
-    private final VmInfoDAO vmInfoDAO;
-    private final VmStatusChangeNotifier notifier;
-    private final ProcessUserInfoBuilder userInfoBuilder;
-    private final WriterID writerId;
-    private Map<Integer, Pair<String, MonitoredVm>> monitoredVms  = new HashMap<>();
-    private final VmBlacklist blacklist;
-
-    JvmStatHostListener(VmInfoDAO vmInfoDAO, VmStatusChangeNotifier notifier,
-                        ProcessUserInfoBuilder userInfoBuilder, WriterID writerId,
-                        VmBlacklist blacklist) {
-        this.vmInfoDAO = vmInfoDAO;
-        this.notifier = notifier;
-        this.userInfoBuilder = userInfoBuilder;
-        this.writerId = writerId;
-        this.blacklist = blacklist;
-    }
-
-    @Override
-    public void disconnected(HostEvent event) {
-        logger.warning("Disconnected from host");
-    }
-
-    @SuppressWarnings("unchecked") // Unchecked casts to (Set<Integer>).
-    @Override
-    public void vmStatusChanged(VmStatusChangeEvent event) {
-        MonitoredHost host = event.getMonitoredHost();
-
-        for (Integer newVm : (Set<Integer>) event.getStarted()) {
-            try {
-                logger.fine("New vm: " + newVm);
-                sendNewVM(newVm, host);
-            } catch (MonitorException e) {
-                logger.log(Level.WARNING, "error getting info for new vm " + newVm, e);
-            } catch (URISyntaxException e) {
-                logger.log(Level.WARNING, "error getting info for new vm " + newVm, e);
-            }
-        }
-
-        for (Integer stoppedVm : (Set<Integer>) event.getTerminated()) {
-            try {
-                logger.fine("stopped vm: " + stoppedVm);
-                sendStoppedVM(stoppedVm, host);
-            } catch (URISyntaxException e) {
-                logger.log(Level.WARNING, "error getting info for stopped vm " + stoppedVm, e);
-            } catch (MonitorException e) {
-                logger.log(Level.WARNING, "error getting info for stopped vm " + stoppedVm, e);
-            }
-        }
-    }
-
-    private void sendNewVM(Integer vmPid, MonitoredHost host)
-            throws MonitorException, URISyntaxException {
-        // Propagate any MonitorException, and do not notify Backends or remember
-        // VMs when we fail to extract the necessary information.
-        // http://icedtea.classpath.org/pipermail/thermostat/2013-November/008702.html
-        MonitoredVm vm = host.getMonitoredVm(host.getHostIdentifier().resolve(
-                new VmIdentifier(vmPid.toString())));
-        if (vm != null) {
-            JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
-            String vmId = UUID.randomUUID().toString();
-            long stopTime = Long.MIN_VALUE;
-            VmInfo info = createVmInfo(vmId, vmPid, stopTime, extractor);
-
-            // Check blacklist
-            if (!blacklist.isBlacklisted(info.getMainClass())) {
-                vmInfoDAO.putVmInfo(info);
-
-                notifier.notifyVmStatusChange(Status.VM_STARTED, vmId, vmPid);
-                logger.finer("Sent VM_STARTED messsage");
-
-                monitoredVms.put(vmPid, new Pair<>(vmId, vm));
-            }
-            else {
-                logger.info("Skipping VM: " + vmPid);
-            }
-        }
-    }
-
-    VmInfo createVmInfo(String vmId, Integer vmPid, long stopTime,
-            JvmStatDataExtractor extractor) throws MonitorException {
-        Map<String, String> properties = new HashMap<String, String>();
-        Map<String, String> environment = InfoBuilderFactory.INSTANCE.createProcessEnvironmentBuilder().build(vmPid);
-        // TODO actually figure out the loaded libraries.
-        String[] loadedNativeLibraries = new String[0];
-        ProcessUserInfo userInfo = userInfoBuilder.build(vmPid);
-        VmInfo info = new VmInfo(writerId.getWriterID(), vmId, vmPid, extractor.getVmStartTime(), stopTime,
-                extractor.getJavaVersion(), extractor.getJavaHome(),
-                extractor.getMainClass(), extractor.getCommandLine(),
-                extractor.getVmName(), extractor.getVmInfo(), extractor.getVmVersion(), extractor.getVmArguments(),
-                properties, environment, loadedNativeLibraries, userInfo.getUid(), userInfo.getUsername());
-        return info;
-    }
-
-    private void sendStoppedVM(Integer vmPid, MonitoredHost host) throws URISyntaxException, MonitorException {
-        
-        VmIdentifier resolvedVmID = host.getHostIdentifier().resolve(new VmIdentifier(vmPid.toString()));
-        if (resolvedVmID != null && monitoredVms.containsKey(vmPid)) {
-            Pair<String, MonitoredVm> vmData = monitoredVms.remove(vmPid);
-            
-            String vmId = vmData.getFirst();
-            notifier.notifyVmStatusChange(Status.VM_STOPPED, vmId, vmPid);
-
-            long stopTime = System.currentTimeMillis();
-            vmInfoDAO.putVmStoppedTime(writerId.getWriterID(), vmId, stopTime);
-
-            MonitoredVm vm = vmData.getSecond();
-            vm.detach();
-        }
-    }
-
-    /*
-     * For testing purposes only.
-     */
-    Map<Integer, Pair<String, MonitoredVm>> getMonitoredVms() {
-        return monitoredVms;
-    }
-    
-}
-
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/ProcessEnvironmentBuilderImpl.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * Copyright 2012-2017 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.system.internal;
-
-import com.redhat.thermostat.backend.system.internal.models.ProcessEnvironmentBuilder;
-import com.redhat.thermostat.common.portability.PortableProcess;
-import com.redhat.thermostat.common.portability.PortableProcessFactory;
-
-import java.util.Map;
-
-/**
- * Build process environment information via portable helper classes
- */
-class ProcessEnvironmentBuilderImpl implements ProcessEnvironmentBuilder {
-
-    private final PortableProcess helper;
-
-    ProcessEnvironmentBuilderImpl() {
-        this(PortableProcessFactory.getInstance());
-    }
-
-    ProcessEnvironmentBuilderImpl(PortableProcess wh) {
-        helper = wh;
-    }
-
-    @Override
-    public Map<String, String> build(int pid) {
-        return helper.getEnvironment(pid);
-    }
-}
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/SystemBackend.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/SystemBackend.java	Fri Jun 09 16:38:44 2017 +0200
@@ -36,64 +36,37 @@
 
 package com.redhat.thermostat.backend.system.internal;
 
-import java.net.URISyntaxException;
 import java.util.Timer;
 import java.util.TimerTask;
-import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import com.redhat.thermostat.agent.VmBlacklist;
 import com.redhat.thermostat.backend.BaseBackend;
-import com.redhat.thermostat.backend.system.internal.models.InfoBuilderFactory;
 import com.redhat.thermostat.common.Version;
-import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder;
-import com.redhat.thermostat.common.portability.UserNameUtil;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.storage.model.NetworkInterfaceInfo;
 
-import sun.jvmstat.monitor.HostIdentifier;
-import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredHost;
-
 public class SystemBackend extends BaseBackend {
 
     private static final Logger logger = LoggingUtils.getLogger(SystemBackend.class);
 
     private NetworkInterfaceInfoDAO networkInterfaces;
-    private VmInfoDAO vmInfoDAO;
 
     private long procCheckInterval = 1000; // TODO make this configurable.
 
     private Timer timer = null;
 
-    private HostIdentifier hostId = null;
-    private MonitoredHost host = null;
-    private JvmStatHostListener hostListener = null;
+    private final NetworkInfoBuilder networkInfoBuilder;
 
-    private final NetworkInfoBuilder networkInfoBuilder;
-    private final ProcessUserInfoBuilder userInfoBuilder;
-    private final VmStatusChangeNotifier notifier;
-    private final WriterID writerId;
-    private final VmBlacklist blacklist;
-
-    public SystemBackend(NetworkInterfaceInfoDAO netInfoDAO, VmInfoDAO vmInfoDAO,
-            Version version, VmStatusChangeNotifier notifier, UserNameUtil userNameUtil, WriterID writerId,
-            VmBlacklist blacklist) {
+    public SystemBackend(NetworkInterfaceInfoDAO netInfoDAO,
+            Version version, WriterID writerId) {
         super("System Backend",
                 "Gathers basic information from the system",
-                "Red Hat, Inc.",
+                "Red Hat, Inc.", "1.0",
                 true);
         this.networkInterfaces = netInfoDAO;
-        this.vmInfoDAO = vmInfoDAO;
-        this.notifier = notifier;
-        this.writerId = writerId;
-        this.blacklist = blacklist;
         setVersion(version.getVersionNumber());
-
-        userInfoBuilder = InfoBuilderFactory.INSTANCE.createProcessUserInfoBuilder(userNameUtil);
         networkInfoBuilder = new NetworkInfoBuilder(writerId);
     }
 
@@ -117,18 +90,6 @@
             }
         }, 0, procCheckInterval);
 
-        try {
-            hostId = new HostIdentifier((String) null);
-            hostListener = new JvmStatHostListener(vmInfoDAO, notifier, 
-                    userInfoBuilder, writerId, blacklist);
-            host = MonitoredHost.getMonitoredHost(hostId);
-            host.addHostListener(hostListener);
-        } catch (MonitorException me) {
-            logger.log(Level.WARNING, "problems with connecting jvmstat to local machine", me);
-        } catch (URISyntaxException use) {
-            logger.log(Level.WARNING, "problems with connecting jvmstat to local machine", use);
-        }
-
         return true;
     }
 
@@ -141,14 +102,6 @@
         timer.cancel();
         timer = null;
 
-        try {
-            host.removeHostListener(hostListener);
-        } catch (MonitorException me) {
-            logger.log(Level.INFO, "something went wrong in jvmstat's listening to this host");
-        }
-        host = null;
-        hostId = null;
-
         return true;
     }
 
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/SystemBackendActivator.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/SystemBackendActivator.java	Fri Jun 09 16:38:44 2017 +0200
@@ -40,7 +40,6 @@
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
 
-import com.redhat.thermostat.agent.VmBlacklist;
 import com.redhat.thermostat.backend.Backend;
 import com.redhat.thermostat.backend.BackendService;
 import com.redhat.thermostat.common.MultipleServiceTracker;
@@ -50,7 +49,6 @@
 import com.redhat.thermostat.common.portability.UserNameUtil;
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
 
 @SuppressWarnings("rawtypes")
 public class SystemBackendActivator implements BundleActivator {
@@ -58,33 +56,25 @@
     private MultipleServiceTracker tracker;
     private SystemBackend backend;
     private ServiceRegistration reg;
-    private VmStatusChangeNotifier notifier;
-    
+
     @Override
     public void start(final BundleContext context) throws Exception {
-        
-        notifier = new VmStatusChangeNotifier(context);
-        notifier.start();
-        
+
         Class<?>[] deps = new Class<?>[] {
                 BackendService.class,
                 NetworkInterfaceInfoDAO.class,
-                VmInfoDAO.class,
                 UserNameUtil.class,
                 WriterID.class, // system backend uses it
-                VmBlacklist.class,
         };
         tracker = new MultipleServiceTracker(context, deps, new Action() {
             @Override
             public void dependenciesAvailable(DependencyProvider services) {
                 NetworkInterfaceInfoDAO netInfoDAO = services.get(NetworkInterfaceInfoDAO.class);
-                VmInfoDAO vmInfoDAO = services.get(VmInfoDAO.class);
-                UserNameUtil userNameUtil = services.get(UserNameUtil.class);
                 Version version = new Version(context.getBundle());
                 WriterID id = services.get(WriterID.class);
-                VmBlacklist blacklist = services.get(VmBlacklist.class);
-                backend = new SystemBackend(netInfoDAO, vmInfoDAO, version, notifier, 
-                        userNameUtil, id, blacklist);
+//                UserNameUtil userNameUtil = services.get(UserNameUtil.class);
+//                VmBlacklist blacklist = services.get(VmBlacklist.class);
+                backend = new SystemBackend(netInfoDAO, version, id);
                 reg = context.registerService(Backend.class, backend, null);
             }
             
@@ -107,7 +97,6 @@
             backend.deactivate();
         }
         tracker.close();
-        notifier.stop();
     }
 }
 
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/VmStatusChangeNotifier.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,139 +0,0 @@
-/*
- * Copyright 2012-2017 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.system.internal;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.ServiceTracker;
-
-import com.redhat.thermostat.agent.VmStatusListener;
-import com.redhat.thermostat.agent.VmStatusListener.Status;
-
-/**
- * Notifies any and all {@link VmStatusListener} registered as OSGi Services
- * about VM status changes: {@link VmStatusListener.Status#VM_STARTED} and
- * {@link VmStatusListener.Status#VM_STOPPED}.
- * <p>
- * Any listeners registered after a {@link VmStatusListener.Status#VM_STARTED}
- * was delivered receive a {@link VmStatusListener.Status#VM_ACTIVE} event
- * instead as an indication that a VM was started at some unknown point
- * previously.
- */
-public class VmStatusChangeNotifier {
-
-    private final Object listenerLock = new Object();
-    private final Map<Integer, String> activePids;
-    private final Map<VmStatusListener, Set<Integer>> listeners = new ConcurrentHashMap<>();
-
-    private final ServiceTracker tracker;
-
-    public VmStatusChangeNotifier(BundleContext bundleContext) {
-        this.activePids = new HashMap<>();
-
-        tracker = new ServiceTracker(bundleContext, VmStatusListener.class, null) {
-            @Override
-            public VmStatusListener addingService(ServiceReference reference) {
-                VmStatusListener listener = (VmStatusListener) super.addingService(reference);
-
-                synchronized (listenerLock) {
-                    Set<Integer> notifiedAbout = new TreeSet<>();
-                    for (Entry<Integer, String> entry : activePids.entrySet()) {
-                        Integer pid = entry.getKey();
-                        listener.vmStatusChanged(Status.VM_ACTIVE, entry.getValue(), pid);
-                        notifiedAbout.add(pid);
-                    }
-
-                    listeners.put(listener, notifiedAbout);
-                }
-
-                return listener;
-            }
-
-            @Override
-            public void removedService(ServiceReference reference,
-                    Object service) {
-                VmStatusListener listener = (VmStatusListener) service;
-                listeners.remove(listener);
-                super.removedService(reference, service);
-            }
-        };
-    }
-
-    public void start() {
-        tracker.open();
-    }
-
-    public void stop() {
-        tracker.close();
-    }
-
-    /**
-     * Notify all registered listeners about a Vm status change.
-     *
-     * @param newStatus either {@link VmStatusListener.Status#VM_STARTED} or
-     * {@link VmStatusListener.Status#VM_STOPPED}
-     * @param vmId unique identifier for the VM
-     * @param pid process ID for the VM
-     */
-    public void notifyVmStatusChange(VmStatusListener.Status newStatus, String vmId, int pid) {
-        if (newStatus == Status.VM_ACTIVE) {
-            throw new IllegalArgumentException("Dont pass in " + Status.VM_ACTIVE + ", that will be handled automatically");
-        }
-
-        synchronized (listenerLock) {
-            for (Entry<VmStatusListener, Set<Integer>> entry : listeners.entrySet()) {
-                entry.getKey().vmStatusChanged(newStatus, vmId, pid);
-                entry.getValue().add(pid);
-            }
-
-            if (newStatus == Status.VM_STARTED) {
-                activePids.put(pid, vmId);
-            } else {
-                activePids.remove(pid);
-            }
-        }
-    }
-
-}
-
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/models/InfoBuilderFactory.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * Copyright 2012-2017 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.system.internal.models;
-
-import com.redhat.thermostat.backend.system.internal.InfoBuilderFactoryImpl;
-import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder;
-import com.redhat.thermostat.common.portability.UserNameUtil;
-
-/**
- * Allows callers to access OS-specific builders portably
- */
-public interface InfoBuilderFactory {
-
-    static InfoBuilderFactory INSTANCE = new InfoBuilderFactoryImpl();
-
-    public ProcessEnvironmentBuilder createProcessEnvironmentBuilder();
-
-    public ProcessUserInfoBuilder createProcessUserInfoBuilder(final UserNameUtil userNameUtil);
-}
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/models/ProcessEnvironmentBuilder.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * Copyright 2012-2017 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.system.internal.models;
-
-import java.util.Map;
-
-/**
- * Interface for fetching a process environment
- * An environment is represented as a map of name-value pairs
- */
-public interface ProcessEnvironmentBuilder {
-    Map<String,String> build(int pid);
-}
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/InfoBuilderFactoryTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright 2012-2017 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.system.internal;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.backend.system.internal.models.InfoBuilderFactory;
-import com.redhat.thermostat.backend.system.internal.models.ProcessEnvironmentBuilder;
-
-public class InfoBuilderFactoryTest {
-
-    @Test
-    public void testCreateProcessEnvironmentBuilder() {
-        final InfoBuilderFactory builder = new InfoBuilderFactoryImpl();
-        final ProcessEnvironmentBuilder hib = builder.createProcessEnvironmentBuilder();
-        assertNotNull(hib);
-        assertTrue(hib instanceof ProcessEnvironmentBuilderImpl);
-    }
-}
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/JvmStatDataExtractorTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,167 +0,0 @@
-/*
- * Copyright 2012-2017 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.system.internal;
-
-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.MonitorException;
-import sun.jvmstat.monitor.MonitoredVm;
-import sun.jvmstat.monitor.StringMonitor;
-
-public class JvmStatDataExtractorTest {
-
-    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;
-    }
-
-    @Test
-    public void testCommandLine() throws MonitorException {
-        final String MONITOR_NAME = "sun.rt.javaCommand";
-        final String MONITOR_VALUE = "command line java";
-        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
-
-        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
-        String returned = extractor.getCommandLine();
-
-        verify(vm).findByName(eq(MONITOR_NAME));
-        assertEquals(MONITOR_VALUE, returned);
-    }
-
-    @Test
-    public void testMainClass() throws MonitorException {
-        final String MONITOR_NAME = "sun.rt.javaCommand";
-        final String MONITOR_VALUE = "some.package.Main";
-        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
-
-        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
-        String returned = extractor.getMainClass();
-
-        verify(vm).findByName(eq(MONITOR_NAME));
-        assertEquals(MONITOR_VALUE, returned);
-    }
-
-    @Test
-    public void testJavaVersion() throws MonitorException {
-        final String MONITOR_NAME = "java.property.java.version";
-        final String MONITOR_VALUE = "some java version";
-        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
-
-        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
-        String returned = extractor.getJavaVersion();
-
-        verify(vm).findByName(eq(MONITOR_NAME));
-        assertEquals(MONITOR_VALUE, returned);
-    }
-
-    @Test
-    public void testJavaHome() throws MonitorException {
-        final String MONITOR_NAME = "java.property.java.home";
-        final String MONITOR_VALUE = "${java.home}";
-        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
-
-        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
-        String returned = extractor.getJavaHome();
-
-        verify(vm).findByName(eq(MONITOR_NAME));
-        assertEquals(MONITOR_VALUE, returned);
-    }
-
-    @Test
-    public void testVmName() throws MonitorException {
-        final String MONITOR_NAME = "java.property.java.vm.name";
-        final String MONITOR_VALUE = "${vm.name}";
-        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
-
-        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
-        String returned = extractor.getVmName();
-
-        verify(vm).findByName(eq(MONITOR_NAME));
-        assertEquals(MONITOR_VALUE, returned);
-    }
-
-    @Test
-    public void testVmInfo() throws MonitorException {
-        final String MONITOR_NAME = "java.property.java.vm.info";
-        final String MONITOR_VALUE = "${vm.info}";
-        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
-
-        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
-        String returned = extractor.getVmInfo();
-
-        verify(vm).findByName(eq(MONITOR_NAME));
-        assertEquals(MONITOR_VALUE, returned);
-    }
-
-    @Test
-    public void testVmVersion() throws MonitorException {
-        final String MONITOR_NAME = "java.property.java.vm.version";
-        final String MONITOR_VALUE = "${vm.version}";
-        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
-
-        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
-        String returned = extractor.getVmVersion();
-
-        verify(vm).findByName(eq(MONITOR_NAME));
-        assertEquals(MONITOR_VALUE, returned);
-    }
-
-    @Test
-    public void testVmArguments() throws MonitorException {
-        final String MONITOR_NAME = "java.rt.vmArgs";
-        final String MONITOR_VALUE = "${vm.arguments}";
-        MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE);
-
-        JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
-        String returned = extractor.getVmArguments();
-
-        verify(vm).findByName(eq(MONITOR_NAME));
-        assertEquals(MONITOR_VALUE, returned);
-    }
-
-}
-
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/JvmStatHostListenerTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,277 +0,0 @@
-/*
- * Copyright 2012-2017 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.system.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.AdditionalMatchers.not;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.net.URISyntaxException;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.UUID;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import com.redhat.thermostat.agent.VmBlacklist;
-import com.redhat.thermostat.agent.VmStatusListener.Status;
-import com.redhat.thermostat.common.portability.ProcessUserInfo;
-import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder;
-import com.redhat.thermostat.storage.core.WriterID;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
-import com.redhat.thermostat.storage.model.VmInfo;
-
-import sun.jvmstat.monitor.HostIdentifier;
-import sun.jvmstat.monitor.Monitor;
-import sun.jvmstat.monitor.MonitorException;
-import sun.jvmstat.monitor.MonitoredHost;
-import sun.jvmstat.monitor.MonitoredVm;
-import sun.jvmstat.monitor.StringMonitor;
-import sun.jvmstat.monitor.VmIdentifier;
-import sun.jvmstat.monitor.event.VmStatusChangeEvent;
-
-public class JvmStatHostListenerTest {
-    
-    private static String INFO_CMDLINE = "/path/to/executable command line args";
-    private static String INFO_JAVAHOME = "/path/to/java";
-    private static String INFO_JAVAVER = "1.9001";
-    private static String INFO_MAINCLASS = "MyMainClass";
-    private static String INFO_VMARGS = "-Xarg1 -Xarg2";
-    private static String INFO_VMINFO = "Info";
-    private static String INFO_VMNAME = "MyJVM";
-    private static String INFO_VMVER = "90.01";
-    private static long INFO_VMUSERID = 2000;
-    private static String INFO_VMUSERNAME = "User";
-    private static final long INFO_STARTTIME = Long.MIN_VALUE;
-
-    private JvmStatHostListener hostListener;
-    private MonitoredHost host;
-    private MonitoredVm monitoredVm1;
-    private MonitoredVm monitoredVm2;
-    private JvmStatDataExtractor extractor;
-    private VmInfoDAO vmInfoDAO;
-    private VmStatusChangeNotifier notifier;
-    private VmBlacklist blacklist;
-
-    @Before
-    public void setup() throws MonitorException, URISyntaxException {
-        vmInfoDAO = mock(VmInfoDAO.class);
-        notifier = mock(VmStatusChangeNotifier.class);
-        
-        ProcessUserInfoBuilder userInfoBuilder = mock(ProcessUserInfoBuilder.class);
-        ProcessUserInfo userInfo = new ProcessUserInfo(INFO_VMUSERID, INFO_VMUSERNAME);
-        when(userInfoBuilder.build(any(int.class))).thenReturn(userInfo);
-
-        WriterID id = mock(WriterID.class);
-        blacklist = mock(VmBlacklist.class);
-        hostListener = new JvmStatHostListener(vmInfoDAO, notifier, userInfoBuilder, id, blacklist);
-        
-        host = mock(MonitoredHost.class);
-        HostIdentifier hostId = mock(HostIdentifier.class);
-        monitoredVm1 = mock(MonitoredVm.class);
-        monitoredVm2 = mock(MonitoredVm.class);
-        StringMonitor monitor = mock(StringMonitor.class);
-        Monitor monitor2 = mock(Monitor.class);
-        VmIdentifier vmId1 = new VmIdentifier("1");
-        VmIdentifier vmId2 = new VmIdentifier("2");
-
-        when(monitor2.getValue()).thenReturn(100l);
-        when(host.getHostIdentifier()).thenReturn(hostId);
-        when(host.getMonitoredVm(eq(vmId1))).thenReturn(monitoredVm1);
-        when(host.getMonitoredVm(eq(vmId2))).thenReturn(monitoredVm2);
-        when(hostId.resolve(eq(vmId1))).thenReturn(vmId1);
-        when(hostId.resolve(eq(vmId2))).thenReturn(vmId2);
-        when(monitoredVm1.findByName("sun.rt.vmInitDoneTime")).thenReturn(monitor2);
-        when(monitoredVm2.findByName("sun.rt.vmInitDoneTime")).thenReturn(monitor2);
-        when(monitoredVm1.findByName(not(eq("sun.rt.vmInitDoneTime")))).thenReturn(monitor);
-        when(monitoredVm2.findByName(not(eq("sun.rt.vmInitDoneTime")))).thenReturn(monitor);
-        when(monitor.stringValue()).thenReturn("test");
-        when(monitor.getValue()).thenReturn("test");
-        extractor = mock(JvmStatDataExtractor.class);
-        
-        when(extractor.getCommandLine()).thenReturn(INFO_CMDLINE);
-        when(extractor.getJavaHome()).thenReturn(INFO_JAVAHOME);
-        when(extractor.getJavaVersion()).thenReturn(INFO_JAVAVER);
-        when(extractor.getMainClass()).thenReturn(INFO_MAINCLASS);
-        when(extractor.getVmArguments()).thenReturn(INFO_VMARGS);
-        when(extractor.getVmInfo()).thenReturn(INFO_VMINFO);
-        when(extractor.getVmName()).thenReturn(INFO_VMNAME);
-        when(extractor.getVmVersion()).thenReturn(INFO_VMVER);
-        when(extractor.getVmStartTime()).thenReturn(INFO_STARTTIME);
-    }
-    
-    @Test
-    public void testNewVM() throws InterruptedException, MonitorException {
-        startVMs();
-        
-        assertTrue(hostListener.getMonitoredVms().containsKey(1));
-        assertTrue(hostListener.getMonitoredVms().containsKey(2));
-        assertEquals(monitoredVm1, hostListener.getMonitoredVms().get(1).getSecond());
-        assertEquals(monitoredVm2, hostListener.getMonitoredVms().get(2).getSecond());
-        
-        // Check valid UUIDs
-        UUID uuid1 = UUID.fromString(hostListener.getMonitoredVms().get(1).getFirst());
-        UUID uuid2 = UUID.fromString(hostListener.getMonitoredVms().get(2).getFirst());
-        assertFalse(uuid1.equals(uuid2));
-        
-        verify(notifier, times(2)).notifyVmStatusChange(eq(Status.VM_STARTED), anyString(), (isA(Integer.class)));
-    }
-    
-    @Test
-    public void testNewVMBlackListed() throws InterruptedException, MonitorException {
-        when(blacklist.isBlacklisted(anyString())).thenReturn(true).thenReturn(false);
-        startVMs();
-        
-        assertFalse(hostListener.getMonitoredVms().containsKey(1));
-        assertTrue(hostListener.getMonitoredVms().containsKey(2));
-        assertEquals(monitoredVm2, hostListener.getMonitoredVms().get(2).getSecond());
-        
-        UUID uuid = UUID.fromString(hostListener.getMonitoredVms().get(2).getFirst());
-        verify(notifier).notifyVmStatusChange(eq(Status.VM_STARTED), eq(uuid.toString()), (isA(Integer.class)));
-    }
-    
-    @Test
-    public void testStoppedVM() throws InterruptedException, MonitorException {
-        final Set<Integer> stopped = new HashSet<>();
-        stopped.add(1);
-        
-        startVMs();
-        
-        // Trigger a change event
-        VmStatusChangeEvent event = mock(VmStatusChangeEvent.class);
-        when(event.getMonitoredHost()).thenReturn(host);
-        when(event.getStarted()).thenReturn(Collections.<Integer>emptySet());
-        when(event.getTerminated()).thenReturn(stopped);
-        hostListener.vmStatusChanged(event);
-        
-        // Ensure only 1 removed
-        assertFalse(hostListener.getMonitoredVms().containsKey(1));
-        assertTrue(hostListener.getMonitoredVms().containsKey(2));
-        assertEquals(monitoredVm2, hostListener.getMonitoredVms().get(2).getSecond());
-
-        verify(notifier).notifyVmStatusChange(eq(Status.VM_STOPPED), anyString(), (isA(Integer.class)));
-
-    }
-    
-    @Test
-    public void testReusedPid() throws MonitorException {
-        final Set<Integer> started = new HashSet<>();
-        started.add(1);
-        // Start VM
-        VmStatusChangeEvent event = mock(VmStatusChangeEvent.class);
-        when(event.getMonitoredHost()).thenReturn(host);
-        when(event.getStarted()).thenReturn(started);
-        when(event.getTerminated()).thenReturn(Collections.<Integer>emptySet());
-        hostListener.vmStatusChanged(event);
-        
-        ArgumentCaptor<String> vmIdCaptor = ArgumentCaptor.forClass(String.class);
-        
-        // Stop VM
-        event = mock(VmStatusChangeEvent.class);
-        when(event.getMonitoredHost()).thenReturn(host);
-        when(event.getStarted()).thenReturn(Collections.<Integer>emptySet());
-        when(event.getTerminated()).thenReturn(started);
-        hostListener.vmStatusChanged(event);
-        
-        // Start new VM
-        event = mock(VmStatusChangeEvent.class);
-        when(event.getMonitoredHost()).thenReturn(host);
-        when(event.getStarted()).thenReturn(started);
-        when(event.getTerminated()).thenReturn(Collections.<Integer>emptySet());
-        hostListener.vmStatusChanged(event);
-        
-        verify(notifier, times(2)).notifyVmStatusChange(eq(Status.VM_STARTED), vmIdCaptor.capture(), eq(1));
-        List<String> vmIds = vmIdCaptor.getAllValues();
-        
-        assertEquals(2, vmIds.size());
-        String vmId1 = vmIds.get(0);
-        String vmId2 = vmIds.get(1);
-        assertNotNull(vmId1);
-        assertNotNull(vmId2);
-        assertFalse(vmId1.equals(vmId2));
-    }
-
-    private void startVMs() throws InterruptedException, MonitorException {
-        final Set<Integer> started = new HashSet<>();
-        started.add(1);
-        started.add(2);
-
-        // Trigger a change event
-        VmStatusChangeEvent event = mock(VmStatusChangeEvent.class);
-        when(event.getMonitoredHost()).thenReturn(host);
-        when(event.getStarted()).thenReturn(started);
-        when(event.getTerminated()).thenReturn(Collections.<Integer>emptySet());
-        hostListener.vmStatusChanged(event);
-    }
-
-    @Test
-    public void testCreateVmInfo() throws MonitorException {
-        final String INFO_ID = "vmId";
-        final int INFO_PID = 1;
-        final long INFO_STOPTIME = Long.MAX_VALUE;
-        VmInfo info = hostListener.createVmInfo(INFO_ID, INFO_PID, INFO_STOPTIME, extractor);
-        
-        assertEquals(INFO_PID, info.getVmPid());
-        assertEquals(INFO_STARTTIME, info.getStartTimeStamp());
-        assertEquals(INFO_STOPTIME, info.getStopTimeStamp());
-        assertEquals(INFO_CMDLINE, info.getJavaCommandLine());
-        assertEquals(INFO_JAVAHOME, info.getJavaHome());
-        assertEquals(INFO_JAVAVER, info.getJavaVersion());
-        assertEquals(INFO_MAINCLASS, info.getMainClass());
-        assertEquals(INFO_VMARGS, info.getVmArguments());
-        assertEquals(INFO_VMINFO, info.getVmInfo());
-        assertEquals(INFO_VMNAME, info.getVmName());
-        assertEquals(INFO_VMVER, info.getVmVersion());
-        assertEquals(INFO_VMUSERID, info.getUid());
-        assertEquals(INFO_VMUSERNAME, info.getUsername());
-    }
-}
-
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/ProcessEnvironmentBuilderTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/*
- * Copyright 2012-2017 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.system.internal;
-
-import com.redhat.thermostat.common.portability.PortableProcess;
-import com.redhat.thermostat.backend.system.internal.models.ProcessEnvironmentBuilder;
-import com.redhat.thermostat.shared.config.OS;
-
-import org.junit.Assume;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-/**
- * test windows process env builder
- */
-public class ProcessEnvironmentBuilderTest {
-
-    private PortableProcess whelp;
-
-    private static final int FAKE_PID = 4567;
-    private static final String PATH_KEY = "PATH";
-    private static final String FAKE_PATH = "testpath";
-
-    private static final Map<String,String> goodMap = new HashMap<>();
-
-    @Before
-    public void setup() {
-        whelp = mock(PortableProcess.class);
-        goodMap.put(PATH_KEY, FAKE_PATH);
-        when(whelp.getEnvironment(anyInt())).thenReturn(null);
-        when(whelp.getEnvironment(eq(FAKE_PID))).thenReturn(goodMap);
-    }
-
-    @Test
-    public void testSimpleBuild() {
-        Assume.assumeTrue(OS.IS_WINDOWS);
-        final Map<String,String> info = new ProcessEnvironmentBuilderImpl().build(FAKE_PID);
-        assertNotNull(info);
-    }
-
-    @Test
-    public void testGetInfoFromGoodPid() {
-        final ProcessEnvironmentBuilder ib = new ProcessEnvironmentBuilderImpl(whelp);
-        final Map<String,String> info  = ib.build(FAKE_PID);
-        assertFalse(info.isEmpty());
-        assertTrue(info.containsKey(PATH_KEY));
-        assertEquals(FAKE_PATH, info.get(PATH_KEY));
-    }
-
-    @Test
-    public void testGetInfoFromBadPid() {
-        final ProcessEnvironmentBuilder ib = new ProcessEnvironmentBuilderImpl(whelp);
-        final Map<String,String> info  = ib.build(FAKE_PID+1);
-        assertTrue(info == null || info.isEmpty());
-    }
-}
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/SystemBackendTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ b/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/SystemBackendTest.java	Fri Jun 09 16:38:44 2017 +0200
@@ -42,17 +42,12 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Test;
 
-import com.redhat.thermostat.agent.VmBlacklist;
 import com.redhat.thermostat.common.Version;
-import com.redhat.thermostat.common.portability.UserNameUtil;
-import com.redhat.thermostat.shared.config.OS;
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
 
 public class SystemBackendTest {
 
@@ -62,17 +57,11 @@
     @Before
     public void setUp() {
         NetworkInterfaceInfoDAO nDAO = mock(NetworkInterfaceInfoDAO.class);
-        VmInfoDAO vmInfoDAO = mock(VmInfoDAO.class);
-
         Version version = mock(Version.class);
         when(version.getVersionNumber()).thenReturn(VERSION);
-        
-        VmStatusChangeNotifier notifier = mock(VmStatusChangeNotifier.class);
-        UserNameUtil util = mock(UserNameUtil.class);
+        WriterID id = mock(WriterID.class);
 
-        WriterID id = mock(WriterID.class);
-        VmBlacklist blacklist = mock(VmBlacklist.class);
-        b = new SystemBackend(nDAO, vmInfoDAO, version, notifier, util, id, blacklist);
+        b = new SystemBackend(nDAO, version, id);
     }
 
     @Test
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/VmStatusChangeNotifierTest.java	Thu Jun 08 20:16:03 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,206 +0,0 @@
-/*
- * Copyright 2012-2017 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.system.internal;
-
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import java.util.ConcurrentModificationException;
-
-import org.junit.Test;
-import org.osgi.framework.BundleContext;
-
-import com.redhat.thermostat.agent.VmStatusListener;
-import com.redhat.thermostat.agent.VmStatusListener.Status;
-import com.redhat.thermostat.testutils.StubBundleContext;
-
-public class VmStatusChangeNotifierTest {
-
-    @Test
-    public void verifyWorksWithoutAnyListeners() {
-        final String VM_ID = "vmId";
-        final int VM_PID = 2;
-        StubBundleContext bundleContext = new StubBundleContext();
-
-        VmStatusChangeNotifier notifier = new VmStatusChangeNotifier(bundleContext);
-        notifier.start();
-        notifier.notifyVmStatusChange(Status.VM_STARTED, VM_ID, VM_PID);
-
-        notifier.notifyVmStatusChange(Status.VM_STOPPED, VM_ID, VM_PID);
-    }
-
-    @Test
-    public void verifyAllListenersAreNotified() {
-        final String VM_ID = "vmId";
-        final int VM_PID = 2;
-        StubBundleContext bundleContext = new StubBundleContext();
-
-        VmStatusListener listener = mock(VmStatusListener.class);
-        bundleContext.registerService(VmStatusListener.class, listener, null);
-
-        VmStatusChangeNotifier notifier = new VmStatusChangeNotifier(bundleContext);
-        notifier.start();
-        notifier.notifyVmStatusChange(Status.VM_STARTED, VM_ID, VM_PID);
-
-        verify(listener).vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID);
-
-        notifier.notifyVmStatusChange(Status.VM_STOPPED, VM_ID, VM_PID);
-
-        verify(listener).vmStatusChanged(Status.VM_STOPPED, VM_ID, VM_PID);
-    }
-
-    @Test
-    public void verifyListenersAddedAfterVmStartRecieveVmActiveEvent() {
-        final String VM_ID = "vmId";
-        final int VM_PID = 2;
-        StubBundleContext bundleContext = new StubBundleContext();
-
-        VmStatusChangeNotifier notifier = new VmStatusChangeNotifier(bundleContext);
-        notifier.start();
-        notifier.notifyVmStatusChange(Status.VM_STARTED, VM_ID, VM_PID);
-
-        VmStatusListener listener = mock(VmStatusListener.class);
-        bundleContext.registerService(VmStatusListener.class, listener, null);
-
-        verify(listener).vmStatusChanged(Status.VM_ACTIVE, VM_ID, VM_PID);
-
-    }
-    
-    /*
-     * Some backends might activate on activation of another backend. If both of
-     * them are also VmStatusListener's, a concurrent modification exception
-     * might be thrown. This tests verifies it's OK to do so (concurrent modification).
-     */
-    @Test
-    public void canAddListenersWhileFiringEvent() throws InterruptedException {
-        StubBundleContext bundleContext = new StubBundleContext();
-        VmStatusChangeNotifier notifier = new VmStatusChangeNotifier(bundleContext);
-        
-        // Add > 2 listeners. One of them registers another listener in vmStatusChanged()
-        // Thus provoking ConcurrentModificationException.
-        bundleContext.registerService(VmStatusListener.class, new TestVmStatusListener(bundleContext), null);
-        bundleContext.registerService(VmStatusListener.class, new VmStatusListener() {
-
-            @Override
-            public void vmStatusChanged(Status newStatus, String vmId,
-                    int pid) {
-                Debug.println("Second registered listener fired");
-            }
-            
-            @Override
-            public int hashCode() {
-                return 2; // second listener to be fired
-            }
-            
-        }, null);
-        bundleContext.registerService(VmStatusListener.class, new VmStatusListener() {
-
-            @Override
-            public void vmStatusChanged(Status newStatus, String vmId,
-                    int pid) {
-                Debug.println("Third registered listener fired");
-            }
-            
-            @Override
-            public int hashCode() {
-                return 3;
-            }
-            
-        }, null);
-        notifier.start();
-        
-        try {
-            notifier.notifyVmStatusChange(Status.VM_STARTED, "foo-vmid", 333);
-            // this will trigger the newly added listener being invoked and counting
-            // down the latch.
-            notifier.notifyVmStatusChange(Status.VM_STARTED, "foo-other", 9999);
-            // pass
-        } catch (ConcurrentModificationException e) {
-            fail("Unexpected conncurrent modification exception!");
-        }
-    }
-    
-    static class TestVmStatusListener implements VmStatusListener {
-
-        private final BundleContext context;
-        
-        private TestVmStatusListener(BundleContext context) {
-            this.context = context;
-        }
-        
-        @Override
-        public void vmStatusChanged(Status newStatus, String vmId, int pid) {
-            Debug.println("First registered listener fired");
-            context.registerService(VmStatusListener.class, new VmStatusListener() {
-
-                @Override
-                public void vmStatusChanged(Status newStatus, String vmId,
-                        int pid) {
-                    Debug.println("Listener registered in listener (between first and second) fired");
-                }
-                
-                @Override
-                public int hashCode() {
-                    // Pick a large hash code since that tends to result in
-                    // the listener being fired later on.
-                    return 101;
-                }
-                
-            }, null);
-        }
-        
-        @Override
-        public int hashCode() {
-            // Heuristic for HashMap it tends to be picked first when iterating over
-            return 1;
-        }
-        
-    }
-    
-    static class Debug {
-        
-        static final boolean debugOn = false; // set to true for debug output
-        
-        static void println(String msg) {
-            if (debugOn) {
-                System.err.println(msg);
-            }
-        }
-    }
-}
-