changeset 2544:4933c471f51e

Changes for Windows compatibility This patch modifies several of the backends to add Windows compatibility. It also: 1) moves WindowsHelper into agent-core (from system-backend) so the entire agent has access to it. 2) moves ProcDataSource to a 'linux' subpackage to emphasize the non-portable nature of code that references it. 3) orders the network interfaces so that interfaces with IP (V4 and or V6) addresses appear first (Windows has a lot of virtual addresses that aren't used) 4) Assumes use of GNU Make for conditional native code compilation After this patch is pushed, Windows builds come up and have many panels working. Notable issues include: system-wide CPU usage, VM profiling, NUMA and thread tables not working, etc. Reviewed-by: sgehwolf Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2016-December/021806.html
author Simon Tooke <stooke@redhat.com>
date Thu, 08 Dec 2016 10:23:22 -0500
parents 4254f69340ee
children b75afb726267
files agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/CommandChannelDelegate.java agent/core/Makefile agent/core/pom.xml agent/core/src/main/java/com/redhat/thermostat/agent/utils/ProcDataSource.java agent/core/src/main/java/com/redhat/thermostat/agent/utils/SysConf.java agent/core/src/main/java/com/redhat/thermostat/agent/utils/linux/ProcDataSource.java agent/core/src/main/java/com/redhat/thermostat/agent/utils/windows/WindowsHelperImpl.java agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImpl.java agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/ProcessUserInfoBuilder.java agent/core/src/main/native/WindowsHelperImpl.c agent/core/src/test/java/com/redhat/thermostat/agent/utils/ProcDataSourceTest.java agent/core/src/test/java/com/redhat/thermostat/agent/utils/SysConfTest.java agent/core/src/test/java/com/redhat/thermostat/agent/utils/linux/ProcDataSourceTest.java agent/core/src/test/java/com/redhat/thermostat/agent/utils/windows/WindowsHelperImplTest.java distribution/pom.xml host-cpu/agent/src/main/java/com/redhat/thermostat/host/cpu/agent/internal/CpuStatBuilder.java host-cpu/agent/src/main/java/com/redhat/thermostat/host/cpu/agent/internal/HostCpuBackend.java host-cpu/agent/src/test/java/com/redhat/thermostat/host/cpu/agent/internal/CpuStatBuilderTest.java host-memory/agent/src/main/java/com/redhat/thermostat/host/memory/agent/internal/HostMemoryBackend.java host-memory/agent/src/main/java/com/redhat/thermostat/host/memory/agent/internal/MemoryStatBuilder.java host-memory/agent/src/test/java/com/redhat/thermostat/host/memory/agent/internal/MemoryStatBuilderTest.java numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/Activator.java numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaCollector.java numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaLinuxCollectorImpl.java numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaWindowsCollectorImpl.java numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaCollectorTest.java numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaLinuxCollectorTest.java system-backend/Makefile system-backend/pom.xml system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/NetworkInfoBuilder.java system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/linux/HostInfoBuilderImpl.java system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/linux/LinuxInfoBuilderFactory.java system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/linux/ProcessEnvironmentBuilderImpl.java system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/linux/ProcessUserInfoBuilderImpl.java system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/windows/WindowsHelperImpl.java system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/windows/WindowsHostInfoBuilderImpl.java system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/windows/WindowsProcessEnvironmentBuilderImpl.java system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/windows/WindowsUserInfoBuilderImpl.java system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/linux/HostInfoBuilderTest.java system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/linux/ProcessEnvironmentBuilderTest.java system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/linux/ProcessUserInfoBuilderTest.java system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/windows/WindowsHelperImplTest.java system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/windows/WindowsHostInfoBuilderTest.java system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/windows/WindowsProcessEnvironmentBuilderTest.java system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/windows/WindowsProcessUserInfoBuilderTest.java vm-byteman/agent/src/main/java/com/redhat/thermostat/vm/byteman/agent/internal/BytemanRequestReceiver.java vm-byteman/agent/src/main/java/com/redhat/thermostat/vm/byteman/agent/internal/ProcessUserInfoBuilder.java vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/LinuxProcessStatusInfoBuilderImpl.java vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/ProcessStatusInfoBuilder.java vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/VmCpuBackend.java vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/WindowsProcessStatusInfoBuilderImpl.java vm-cpu/agent/src/test/java/com/redhat/thermostat/vm/cpu/agent/internal/LinuxProcessStatusInfoBuilderTest.java vm-cpu/agent/src/test/java/com/redhat/thermostat/vm/cpu/agent/internal/ProcessStatusInfoBuilderTest.java vm-io/agent/src/main/java/com/redhat/thermostat/vm/io/agent/internal/ProcIoDataReader.java vm-io/agent/src/main/java/com/redhat/thermostat/vm/io/agent/internal/VmIoBackend.java vm-io/agent/src/test/java/com/redhat/thermostat/vm/io/agent/internal/ProcIoDataReaderTest.java
diffstat 56 files changed, 1773 insertions(+), 1067 deletions(-) [+]
line wrap: on
line diff
--- a/agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/CommandChannelDelegate.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/CommandChannelDelegate.java	Thu Dec 08 10:23:22 2016 -0500
@@ -130,7 +130,8 @@
     @Override
     public void startListening(String hostname, int port) throws IOException {
         // Determine if this process is running as a privileged user
-        if (userInfoBuilder.isPrivilegedUser()) {
+        // NOTE: on Windows, security is handled by permission bits, not userid.
+        if (OS.IS_UNIX && userInfoBuilder.isPrivilegedUser()) {
             // Get owner of command channel script, which will also be the user running it
             Path cmdPath = fsUtils.getPath(binPath.getAbsolutePath(), CMD_NAME);
             UserPrincipal unprivilegedPrincipal = fsUtils.getOwner(cmdPath);
--- a/agent/core/Makefile	Wed Dec 07 10:55:51 2016 -0500
+++ b/agent/core/Makefile	Thu Dec 08 10:23:22 2016 -0500
@@ -4,11 +4,20 @@
 MYLDFLAGS  = -fPIC -shared $(EXTRA_CFLAGS)
 COPY       = cp -a
 
-JNI_PLATFORM = linux
 CLASSPATH  = target/classes/
 TARGET_DIR = target
-SO_PREFIX  = lib
-SO_SUFFIX  = .so
+
+ifeq ($(OS),Linux)
+    JNI_PLATFORM = linux
+    SO_PREFIX  = lib
+    SO_SUFFIX  = .so
+    MYCFLAGS   += -fPIC
+    MYLDFLAGS  += -fPIC
+else
+    JNI_PLATFORM = win32
+    SO_PREFIX  =
+    SO_SUFFIX  = .dll
+endif
 
 INCLUDE    = -I $(TARGET_DIR) -I "$(JAVA_HOME)/include/" -I "$(JAVA_HOME)/include/$(JNI_PLATFORM)"
 
@@ -22,20 +31,33 @@
 USERNAME_OBJECTS    = $(USERNAME_TARGET:.c=.o)
 USERNAME_EXECUTABLE = $(SO_PREFIX)UserNameUtilWrapper$(SO_SUFFIX)
 
+WINHELPER_SOURCES    = src/main/native/WindowsHelperImpl.c
+WINHELPER_TARGET     = $(TARGET_DIR)/WindowsHelperImpl.c
+WINHELPER_OBJECTS    = $(WINHELPER_TARGET:.c=.o)
+WINHELPER_EXECUTABLE = $(SO_PREFIX)WindowsHelperWrapper$(SO_SUFFIX)
+
+EXECUTABLES          = $(HOSTNAME_EXECUTABLE) $(USERNAME_EXECUTABLE)
+
+ifeq ($(OS),Windows_NT)
+    EXECUTABLES        += $(WINHELPER_EXECUTABLE)
+endif
+
+
 .PHONY:
 JNI_LIST = com.redhat.thermostat.agent.utils.hostname.HostName\
- com.redhat.thermostat.utils.username.internal.UserNameUtilImpl
+ com.redhat.thermostat.utils.username.internal.UserNameUtilImpl\
+ com.redhat.thermostat.agent.utils.windows.WindowsHelperImpl
 
 $(JNI_LIST):
 	$(JAVAH) -force -classpath $(CLASSPATH) -d $(TARGET_DIR) $(JNI_LIST)
 
-all: $(JNI_LIST) init $(HOSTNAME_SOURCES) $(HOSTNAME_EXECUTABLE) \
-  $(USERNAME_SOURCES) $(USERNAME_EXECUTABLE)
+all: $(JNI_LIST) init $(HOSTNAME_SOURCES) $(USERNAME_SOURCES) $(WINHELPER_SOURCES) $(EXECUTABLES)
 
 .PHONY:
 init:
 	$(COPY) $(HOSTNAME_SOURCES) $(HOSTNAME_TARGET)
 	$(COPY) $(USERNAME_SOURCES) $(USERNAME_TARGET)
+	$(COPY) $(WINHELPER_SOURCES) $(WINHELPER_TARGET)
 
 $(HOSTNAME_EXECUTABLE): $(HOSTNAME_OBJECTS)
 	$(CC) $(HOSTNAME_OBJECTS) -o $(TARGET_DIR)/$@ $(MYLDFLAGS) $(LDFLAGS) $(PLATFORM_LIBS)
@@ -43,16 +65,25 @@
 $(USERNAME_EXECUTABLE): $(USERNAME_OBJECTS)
 	$(CC) $(USERNAME_OBJECTS) -o $(TARGET_DIR)/$@ $(MYLDFLAGS) $(LDFLAGS) $(PLATFORM_LIBS)
 
+$(WINHELPER_EXECUTABLE): $(WINHELPER_OBJECTS)
+	$(CC) $(WINHELPER_OBJECTS) -o $(TARGET_DIR)/$@ $(MYLDFLAGS) $(LDFLAGS) $(PLATFORM_LIBS) -l psapi
+
 .c.o:
 	$(CC) $(MYCFLAGS) $(CFLAGS) $(INCLUDE) $< -o $@
 
+.cpp.o:
+	$(CC) $(MYCFLAGS) $(CFLAGS) $(INCLUDE) $< -o $@
+
+
 clean-lib:
 	rm -f $(TARGET_DIR)/$(HOSTNAME_EXECUTABLE)
 	rm -f $(TARGET_DIR)/$(USERNAME_EXECUTABLE)
+	rm -f $(TARGET_DIR)/$(WINHELPER_EXECUTABLE)
 	
 clean-obj:
 	rm -f $(HOSTNAME_OBJECTS) $(HOSTNAME_TARGET)
 	rm -f $(USERNAME_OBJECTS) $(USERNAME_TARGET)
+	rm -f $(WINHELPER_OBJECTS) $(WINHELPER_TARGET)
 	
 clean: clean-obj clean-lib
 	
--- a/agent/core/pom.xml	Wed Dec 07 10:55:51 2016 -0500
+++ b/agent/core/pom.xml	Thu Dec 08 10:23:22 2016 -0500
@@ -149,8 +149,10 @@
               com.redhat.thermostat.agent.config,
               com.redhat.thermostat.agent.utils,
               com.redhat.thermostat.agent.utils.hostname,
+              com.redhat.thermostat.agent.utils.linux,
               com.redhat.thermostat.agent.utils.management,
               com.redhat.thermostat.agent.utils.username,
+              com.redhat.thermostat.agent.utils.windows,
               com.redhat.thermostat.backend,
             </Export-Package>
             <Private-Package>
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/utils/ProcDataSource.java	Wed Dec 07 10:55:51 2016 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +0,0 @@
-/*
- * Copyright 2012-2016 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.utils;
-
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.Reader;
-
-/**
- * Wrapper for files under {@code /proc/}. See proc(5) for details about this.
- */
-public class ProcDataSource {
-
-    private static final String LOAD_FILE = "/proc/loadavg";
-    private static final String STAT_FILE = "/proc/stat";
-    private static final String MEMINFO_FILE = "/proc/meminfo";
-    private static final String CPUINFO_FILE = "/proc/cpuinfo";
-
-    private static final String PID_ENVIRON_FILE = "/proc/${pid}/environ";
-    private static final String PID_IO_FILE = "/proc/${pid}/io";
-    private static final String PID_STAT_FILE = "/proc/${pid}/stat";
-    private static final String PID_STATUS_FILE = "/proc/${pid}/status";
-
-    /**
-     * Returns a reader for /proc/cpuinfo
-     */
-    public Reader getCpuInfoReader() throws IOException {
-        return new FileReader(CPUINFO_FILE);
-    }
-
-    /**
-     * Returns a reader for /proc/loadavg
-     */
-    public Reader getCpuLoadReader() throws IOException {
-        return new FileReader(LOAD_FILE);
-    }
-
-    /**
-     * Returns a reader for /proc/stat. Kernel/System statistics.
-     */
-    public Reader getStatReader() throws IOException {
-        return new FileReader(STAT_FILE);
-    }
-
-    /**
-     * Returns a reader for /proc/meminfo
-     */
-    public Reader getMemInfoReader() throws IOException {
-        return new FileReader(MEMINFO_FILE);
-    }
-
-    /**
-     * Returns a reader for /proc/$PID/environ
-     */
-    public Reader getEnvironReader(int pid) throws IOException {
-        return new FileReader(getPidFile(PID_ENVIRON_FILE, pid));
-    }
-
-    /**
-     * Returns a reader for /proc/$PID/io
-     */
-    public Reader getIoReader(int pid) throws IOException {
-        return new FileReader(getPidFile(PID_IO_FILE, pid));
-    }
-
-    /**
-     * Returns a reader for /proc/$PID/stat
-     */
-    public Reader getStatReader(int pid) throws IOException {
-        return new FileReader(getPidFile(PID_STAT_FILE, pid));
-    }
-    
-    /**
-     * Returns a reader for /proc/$PID/status
-     */
-    public Reader getStatusReader(int pid) throws IOException {
-        return new FileReader(getPidFile(PID_STATUS_FILE, pid));
-    }
-
-    private String getPidFile(String fileName, int pid) {
-        return fileName.replace("${pid}", Integer.toString(pid));
-    }
-
-}
-
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/utils/SysConf.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/utils/SysConf.java	Thu Dec 08 10:23:22 2016 -0500
@@ -36,6 +36,9 @@
 
 package com.redhat.thermostat.agent.utils;
 
+import com.redhat.thermostat.agent.utils.windows.WindowsHelperImpl;
+import com.redhat.thermostat.shared.config.OS;
+
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
@@ -52,6 +55,14 @@
     }
 
     public static long getClockTicksPerSecond() {
+        return OS.IS_LINUX ? getLinuxClockTicksPerSecond() : getWindowsClockTicksPerSecond();
+    }
+
+    private static long getWindowsClockTicksPerSecond() {
+        return WindowsHelperImpl.INSTANCE.getClockTicksPerSecond();
+    }
+
+    public static long getLinuxClockTicksPerSecond() {
         String ticks = sysConf("CLK_TCK");
         try {
             return Long.valueOf(ticks);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/utils/linux/ProcDataSource.java	Thu Dec 08 10:23:22 2016 -0500
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2012-2016 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.utils.linux;
+
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * Wrapper for files under {@code /proc/}. See proc(5) for details about this.
+ */
+public class ProcDataSource {
+
+    private static final String LOAD_FILE = "/proc/loadavg";
+    private static final String STAT_FILE = "/proc/stat";
+    private static final String MEMINFO_FILE = "/proc/meminfo";
+    private static final String CPUINFO_FILE = "/proc/cpuinfo";
+
+    private static final String PID_ENVIRON_FILE = "/proc/${pid}/environ";
+    private static final String PID_IO_FILE = "/proc/${pid}/io";
+    private static final String PID_STAT_FILE = "/proc/${pid}/stat";
+    private static final String PID_STATUS_FILE = "/proc/${pid}/status";
+
+    /**
+     * Returns a reader for /proc/cpuinfo
+     */
+    public Reader getCpuInfoReader() throws IOException {
+        return new FileReader(CPUINFO_FILE);
+    }
+
+    /**
+     * Returns a reader for /proc/loadavg
+     */
+    public Reader getCpuLoadReader() throws IOException {
+        return new FileReader(LOAD_FILE);
+    }
+
+    /**
+     * Returns a reader for /proc/stat. Kernel/System statistics.
+     */
+    public Reader getStatReader() throws IOException {
+        return new FileReader(STAT_FILE);
+    }
+
+    /**
+     * Returns a reader for /proc/meminfo
+     */
+    public Reader getMemInfoReader() throws IOException {
+        return new FileReader(MEMINFO_FILE);
+    }
+
+    /**
+     * Returns a reader for /proc/$PID/environ
+     */
+    public Reader getEnvironReader(int pid) throws IOException {
+        return new FileReader(getPidFile(PID_ENVIRON_FILE, pid));
+    }
+
+    /**
+     * Returns a reader for /proc/$PID/io
+     */
+    public Reader getIoReader(int pid) throws IOException {
+        return new FileReader(getPidFile(PID_IO_FILE, pid));
+    }
+
+    /**
+     * Returns a reader for /proc/$PID/stat
+     */
+    public Reader getStatReader(int pid) throws IOException {
+        return new FileReader(getPidFile(PID_STAT_FILE, pid));
+    }
+    
+    /**
+     * Returns a reader for /proc/$PID/status
+     */
+    public Reader getStatusReader(int pid) throws IOException {
+        return new FileReader(getPidFile(PID_STATUS_FILE, pid));
+    }
+
+    private String getPidFile(String fileName, int pid) {
+        return fileName.replace("${pid}", Integer.toString(pid));
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/utils/windows/WindowsHelperImpl.java	Thu Dec 08 10:23:22 2016 -0500
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2012-2016 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.utils.windows;
+
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.shared.config.NativeLibraryResolver;
+import com.redhat.thermostat.shared.config.OS;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Logger;
+
+/**
+ * Utility class to access Windows native code
+ */
+public class WindowsHelperImpl {
+
+    private static final Logger logger = LoggingUtils.getLogger(WindowsHelperImpl.class);
+
+    /*
+     // from MemoryStatusEx (8 values)
+        DWORD     dwMemoryLoad;
+        DWORDLONG ullTotalPhys;
+        DWORDLONG ullAvailPhys;
+        DWORDLONG ullTotalPageFile;
+        DWORDLONG ullAvailPageFile;
+        DWORDLONG ullTotalVirtual;
+        DWORDLONG ullAvailVirtual;
+        DWORDLONG ullAvailExtendedVirtual;
+
+     // from PERFORMANCE_INFORMATION (13 values)
+        SIZE_T CommitTotal;
+        SIZE_T CommitLimit;
+        SIZE_T CommitPeak;
+        SIZE_T PhysicalTotal;
+        SIZE_T PhysicalAvailable;
+        SIZE_T SystemCache;
+        SIZE_T KernelTotal;
+        SIZE_T KernelPaged;
+        SIZE_T KernelNonpaged;
+        SIZE_T PageSize;
+        DWORD  HandleCount;
+        DWORD  ProcessCount;
+        DWORD  ThreadCount;
+     */
+
+    static {
+        if (OS.IS_WINDOWS) {
+            String lib = NativeLibraryResolver.getAbsoluteLibraryPath("WindowsHelperWrapper");
+            try {
+                System.load(lib);
+                INSTANCE = new WindowsHelperImpl();
+            } catch (UnsatisfiedLinkError e) {
+                logger.severe("Could not load WindowsHelperImpl DLL:" + lib);
+                INSTANCE = null;
+                // do not throw here, because you'll get a NoClassDefFound thrown when running other tests that Mock this class
+            }
+        } else {
+            INSTANCE = null;
+        }
+    }
+
+    public static class MemoryStat {
+
+        private final long timeStamp;
+        private final long total;
+        private final long free;
+        private final long buffers;
+        private final long cached;
+        private final long swapTotal;
+        private final long swapFree;
+        private final long commitLimit;
+
+
+        public MemoryStat() {
+            final long[] info = INSTANCE.getMemoryInfo();
+            this.timeStamp = System.currentTimeMillis();
+            this.total = info[1];
+            this.free = info[2];
+            this.buffers = 0;
+            this.cached = 0;
+            this.swapTotal = 3;
+            this.swapFree = 4;
+            this.commitLimit = 0;
+            // TODO - buffers, cached and commitLimit
+        }
+
+        public MemoryStat(long timeStamp, long total, long free, long buffers, long cached, long swapTotal, long swapFree, long commitLimit) {
+            this.timeStamp = timeStamp;
+            this.total = total;
+            this.free = free;
+            this.buffers = buffers;
+            this.cached = cached;
+            this.swapTotal = swapTotal;
+            this.swapFree = swapFree;
+            this.commitLimit = commitLimit;
+        }
+
+        public long getTimeStamp() {
+            return timeStamp;
+        }
+        public long getTotal() {
+            return total;
+        }
+        public long getFree() {
+            return free;
+        }
+        public long getBuffers() {
+            return buffers;
+        }
+        public long getCached() {
+            return cached;
+        }
+        public long getSwapTotal() {
+            return swapTotal;
+        }
+        public long getSwapFree() {
+            return swapFree;
+        }
+        public long getCommitLimit() {
+            return commitLimit;
+        }
+    }
+
+    public static WindowsHelperImpl INSTANCE;
+
+    private WindowsHelperImpl() {
+    }
+    // local host-wide information
+
+    public String getHostName() {
+        return getHostName0(true);
+    }
+
+    public String getOSName() {
+        return System.getProperty("os.name");
+    }
+
+    public String getOSVersion() {
+        final long info[] = new long[3];  // major, minor, build
+        getOSVersion0(info);
+        return "" + info[0] + "." + info[1] + " (Build " + info[2] + ")";
+    }
+
+    public String getCPUModel() {
+        return getCPUString0();
+    }
+
+    public int getCPUCount() {
+        return getCPUCount0();
+    }
+
+    public long getTotalMemory() {
+        final long info[] = getMemoryInfo();
+        return info[1]; // totalPhysical
+    }
+
+    // local process-specific information
+    public String getUserName(int pid) {
+        return getUserName0(pid,true);
+    }
+
+    public int getUid(int pid) {
+        return getUid0(pid);
+    }
+
+    public Map<String, String> getEnvironment(int pid) {
+        // the environment is returned as a 1D array of alternating env names and values
+        final String[] envArray = getEnvironment0(pid);
+        if (envArray == null || envArray.length == 0) {
+            return Collections.emptyMap();
+        }
+
+        if (envArray.length % 2 != 0) {
+            throw new AssertionError("environment array length not even");
+        }
+
+        final Map<String, String> env = new HashMap<>(envArray.length/2);
+        for (int i = 0; i < envArray.length / 2; i++) {
+            env.put(envArray[i * 2], envArray[i * 2 + 1]);
+        }
+        return env;
+    }
+
+    public long[] getProcessCPUInfo(int pid) {
+        final long[] info = new long[4];
+        getProcessInfo0(pid, info);
+        return info;
+    }
+
+    public long[] getProcessMemInfo(int pid) {
+        final long[] info = new long[4];
+        getProcessInfo0(pid, info);
+        return info;
+    }
+
+
+    private long[] getMemoryInfo() {
+        final long[] mi = new long[8];
+        getGlobalMemoryStatus0(mi);
+        return mi;
+    }
+
+    private long[] getPerformanceInfo() {
+        final long[] mi = new long[13];
+        getPerformanceInfo0(mi);
+        return mi;
+    }
+
+    public long getClockTicksPerSecond() {
+        return getClockTicksPerSecond0();
+    }
+
+    private static native String getHostName0(boolean prependDomain);
+    private static native void getOSVersion0(long[] versionAndBuild);
+    private static native int getUid0(int pid);
+    private static native String getUserName0(int pid, boolean prependDomain);
+    private static native String[] getEnvironment0(int pid);
+    private static native boolean getGlobalMemoryStatus0(long[] info);
+    private static native boolean getPerformanceInfo0(long[] info);
+    private static native boolean getProcessInfo0(int pid, long[] info);
+    private static native String getCPUString0();
+    private static native int getCPUCount0();
+    private static native long getClockTicksPerSecond0();
+}
--- a/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImpl.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImpl.java	Thu Dec 08 10:23:22 2016 -0500
@@ -59,7 +59,7 @@
 import com.redhat.thermostat.agent.ipc.server.AgentIPCService;
 import com.redhat.thermostat.agent.ipc.server.IPCMessage;
 import com.redhat.thermostat.agent.ipc.server.ThermostatIPCCallbacks;
-import com.redhat.thermostat.agent.utils.ProcDataSource;
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
 import com.redhat.thermostat.agent.utils.management.MXBeanConnection;
 import com.redhat.thermostat.agent.utils.management.MXBeanConnectionException;
 import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool;
--- a/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/ProcessUserInfoBuilder.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/ProcessUserInfoBuilder.java	Thu Dec 08 10:23:22 2016 -0500
@@ -42,7 +42,7 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import com.redhat.thermostat.agent.utils.ProcDataSource;
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
 import com.redhat.thermostat.agent.utils.username.UserNameLookupException;
 import com.redhat.thermostat.agent.utils.username.UserNameUtil;
 import com.redhat.thermostat.common.utils.LoggingUtils;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/main/native/WindowsHelperImpl.c	Thu Dec 08 10:23:22 2016 -0500
@@ -0,0 +1,350 @@
+/*
+ * Copyright 2012-2016 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.
+ */
+
+#include "com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl.h"
+#include <jni.h>
+#include <unistd.h>
+#include <string.h>
+
+#if !defined(_WIN32)
+# include <netdb.h>
+#else // windows
+# include <winsock2.h>
+# include <psapi.h>
+#endif
+
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 1025
+#endif /* NI_MAXHOST */
+
+#if defined(NDEBUG)
+static void testLength(JNIEnv* env, jlongArray array, minLength) {}
+#else
+static void testLength(JNIEnv* env, jlongArray array, minLength) {
+    // sanity test
+    jsize len = (*env)->GetArrayLength(env, array);
+    assert(len >= minLength);
+}
+#endif
+
+/*
+ * Class:     com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl
+ * Method:    getHostName0
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL
+Java_com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl_getHostName0
+  (JNIEnv *env, jclass winHelperClass, jboolean prependDomain)
+{
+      char hostname[NI_MAXHOST];
+      memset(hostname, 0, sizeof(hostname));
+
+      if (gethostname(hostname,  sizeof(hostname)) == 0) {
+          return (*env)->NewStringUTF(env, hostname);
+      }
+      return NULL;
+}
+
+/*
+ * Class:     com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl
+ * Method:    getOSVersion0
+ * Signature: ([J)V
+ */
+JNIEXPORT void JNICALL Java_com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl_getOSVersion0
+  (JNIEnv *env, jclass winHelperClass, jlongArray array)
+{
+    testLength(env, array, 3);
+
+    // Get the element pointer
+    jlong* data = (*env)->GetLongArrayElements(env, array, 0);
+
+    OSVERSIONINFOEX vinfo;
+    vinfo.dwOSVersionInfoSize = sizeof(vinfo);
+    GetVersionEx(&vinfo);
+    data[0] = vinfo.dwMajorVersion;
+    data[1] = vinfo.dwMinorVersion;
+    data[2] = vinfo.dwBuildNumber;
+
+    (*env)->ReleaseLongArrayElements(env, array, data, 0);
+}
+
+
+/*
+ * Class:     com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl
+ * Method:    getUid0
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl_getUid0
+  (JNIEnv *env, jclass winHelperClass, jint pid)
+{
+    // TODO - implement this stub
+    return 987654321;
+}
+
+/*
+ * Class:     com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl
+ * Method:    getUserName0
+ * Signature: (I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL
+Java_com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl_getUserName0
+  (JNIEnv *env, jclass winHelperClass, jint pid, jboolean prependDomain)
+{
+    // TODO - implement this stub
+    return (*env)->NewStringUTF(env, "(unavailable)");
+}
+
+/*
+ * Class:     com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl
+ * Method:    getEnvironment0
+ * Signature: ()[Ljava/lang/String;
+ */
+JNIEXPORT jobjectArray JNICALL
+Java_com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl_getEnvironment0
+  (JNIEnv *env, jclass winHelperClass, jint pid)
+{
+    // TODO - implement this stub
+    jobjectArray ret = (jobjectArray)(*env)->NewObjectArray(env, 0, (*env)->FindClass(env, "java/lang/String"), (*env)->NewStringUTF(env, ""));
+    return ret;
+}
+
+
+/*
+ * Class:     com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl
+ * Method:    getGlobalMemoryStatus0
+ * Signature: ([J)V
+ */
+JNIEXPORT boolean JNICALL Java_com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl_getGlobalMemoryStatus0
+  (JNIEnv *env, jclass winHelperClass, jlongArray array)
+{
+    testLength(env, array, 8);
+
+    // Get the element pointer
+    jlong* data = (*env)->GetLongArrayElements(env, array, 0);
+
+    // get the memory info
+    MEMORYSTATUSEX statex;
+    statex.dwLength = sizeof(statex);
+    GlobalMemoryStatusEx(&statex);
+    data[0] = statex.dwMemoryLoad;
+    data[1] = statex.ullTotalPhys;
+    data[2] = statex.ullAvailPhys;
+    data[3] = statex.ullTotalPageFile;
+    data[4] = statex.ullAvailPageFile;
+    data[5] = statex.ullTotalVirtual;
+    data[6] = statex.ullAvailVirtual;
+    data[7] = statex.ullAvailExtendedVirtual;
+
+    (*env)->ReleaseLongArrayElements(env, array, data, 0);
+    return TRUE;
+}
+
+/*
+ * Class:     com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl
+ * Method:    getPerformanceInfo0
+ * Signature: ([J)V
+ */
+JNIEXPORT boolean JNICALL Java_com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl_getPerformanceInfo0
+  (JNIEnv *env, jclass winHelperClass, jlongArray array)
+{
+    testLength(env, array, 13);
+
+    // Get the element pointer
+    jlong* data = (*env)->GetLongArrayElements(env, array, 0);
+
+    /**
+     // from PERFORMANCE_INFORMATION (13 values)
+        SIZE_T CommitTotal;
+        SIZE_T CommitLimit;
+        SIZE_T CommitPeak;
+        SIZE_T PhysicalTotal;
+        SIZE_T PhysicalAvailable;
+        SIZE_T SystemCache;
+        SIZE_T KernelTotal;
+        SIZE_T KernelPaged;
+        SIZE_T KernelNonpaged;
+        SIZE_T PageSize;
+        DWORD  HandleCount;
+        DWORD  ProcessCount;
+        DWORD  ThreadCount;
+     */
+
+    // get the memeory info
+    PERFORMANCE_INFORMATION statex;
+    statex.cb = sizeof(statex);
+    GetPerformanceInfo(&statex, statex.cb);
+    data[0] = statex.CommitTotal;
+    data[1] = statex.CommitLimit;
+    data[2] = statex.CommitPeak;
+    data[3] = statex.PhysicalTotal;
+    data[4] = statex.PhysicalAvailable;
+    data[5] = statex.SystemCache;
+    data[6] = statex.KernelTotal;
+    data[7] = statex.KernelPaged;
+    data[8] = statex.KernelNonpaged;
+    data[9] = statex.PageSize;
+    data[10] = statex.HandleCount;
+    data[11] = statex.ProcessCount;
+    data[12] = statex.ThreadCount;
+
+    (*env)->ReleaseLongArrayElements(env, array, data, 0);
+    return TRUE;
+}
+
+static unsigned __int64 convertFileTimeToInt64( const FILETIME * pFileTime )
+{
+  ULARGE_INTEGER largeInt;
+
+  largeInt.LowPart = pFileTime->dwLowDateTime;
+  largeInt.HighPart = pFileTime->dwHighDateTime;
+
+  return largeInt.QuadPart;
+}
+
+/*
+ * Class:     com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl
+ * Method:    getProcessMemoryInfo0
+ * Signature: (I[J)V
+ */
+JNIEXPORT jboolean JNICALL Java_com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl_getProcessInfo0
+  (JNIEnv *env, jclass winHelperClass, jint pid, jlongArray array)
+{
+    testLength(env, array, 4);
+
+    // Get the element pointer
+    jlong* data = (*env)->GetLongArrayElements(env, array, 0);
+
+    HANDLE hProcess;
+    PROCESS_MEMORY_COUNTERS pmc;
+
+    hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid );
+    if (NULL == hProcess)
+        return FALSE;
+
+    pmc.cb = sizeof(pmc);
+    if ( GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc)) ) {
+        data[0] = pmc.WorkingSetSize;
+    }
+    else {
+        (*env)->ReleaseLongArrayElements(env, array, data, 0);
+        return FALSE;
+    }
+
+    FILETIME creationTime;
+    FILETIME exitTime;
+    FILETIME kernelTime;
+    FILETIME userTime;
+
+    if ( GetProcessTimes( hProcess, &creationTime, &exitTime, &kernelTime, &userTime ) ) {
+        data[1] = convertFileTimeToInt64(&userTime);
+        data[2] = convertFileTimeToInt64(&kernelTime);
+    }
+
+    CloseHandle(hProcess);
+
+    (*env)->ReleaseLongArrayElements(env, array, data, 0);
+    return TRUE;
+}
+
+/*
+ * Class:     com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl
+ * Method:    getCPUString0
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl_getCPUString0
+  (JNIEnv *env, jclass winHelperClass)
+{
+    // Get extended ids.
+    int CPUInfo[4] = {-1};
+    __cpuid(CPUInfo, 0x80000000);
+    unsigned int nExIds = CPUInfo[0];
+
+    // Get the information associated with each extended ID.
+    char CPUBrandString[0x40] = { 0 };
+    for( unsigned int i=0x80000000; i<=nExIds; ++i)
+    {
+        __cpuid(CPUInfo, i);
+
+        // Interpret CPU brand string and cache information.
+        if  (i == 0x80000002)
+        {
+            memcpy( CPUBrandString,
+            CPUInfo,
+            sizeof(CPUInfo));
+        }
+        else if( i == 0x80000003 )
+        {
+            memcpy( CPUBrandString + 16,
+            CPUInfo,
+            sizeof(CPUInfo));
+        }
+        else if( i == 0x80000004 )
+        {
+            memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo));
+        }
+    }
+    return (*env)->NewStringUTF(env, CPUBrandString);
+
+}
+
+/*
+ * Class:     com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl
+ * Method:    getCPUCount0
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl_getCPUCount0
+  (JNIEnv *env, jclass winHelperClass)
+{
+    SYSTEM_INFO sysinfo;
+    GetSystemInfo(&sysinfo);
+
+    return sysinfo.dwNumberOfProcessors;
+}
+
+/*
+ * Class:     com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl
+ * Method:    getClockTicksPerSecond0
+ * Signature: ()I
+ */
+JNIEXPORT jlong JNICALL Java_com_redhat_thermostat_agent_utils_windows_WindowsHelperImpl_getClockTicksPerSecond0
+  (JNIEnv *env, jclass winHelperClass)
+{
+    LARGE_INTEGER freq;
+    QueryPerformanceFrequency(&freq);
+
+    return (jlong)(freq.QuadPart);
+}
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/utils/ProcDataSourceTest.java	Wed Dec 07 10:55:51 2016 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-/*
- * Copyright 2012-2016 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.utils;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.Reader;
-
-import com.redhat.thermostat.shared.config.OS;
-import org.junit.Assume;
-import org.junit.Test;
-
-import com.redhat.thermostat.agent.utils.ProcDataSource;
-import com.redhat.thermostat.testutils.TestUtils;
-
-public class ProcDataSourceTest {
-
-    @Test
-    public void testGetCpuInfoReader() throws IOException {
-        Assume.assumeTrue(OS.IS_UNIX);
-        Reader r = new ProcDataSource().getCpuInfoReader();
-        assertNotNull(r);
-    }
-
-    @Test
-    public void testGetCpuLoadReader() throws IOException {
-        Assume.assumeTrue(OS.IS_UNIX);
-        Reader r = new ProcDataSource().getCpuLoadReader();
-        assertNotNull(r);
-    }
-
-    @Test
-    public void testGetMemInfoReader() throws IOException {
-        Assume.assumeTrue(OS.IS_UNIX);
-        Reader r = new ProcDataSource().getMemInfoReader();
-        assertNotNull(r);
-    }
-
-    @Test
-    public void testGetStatReader() throws IOException {
-        Assume.assumeTrue(OS.IS_UNIX);
-        int pid = TestUtils.getProcessId();
-        Reader r = new ProcDataSource().getStatReader(pid);
-        assertNotNull(r);
-    }
-
-    @Test
-    public void testGetEnvironReader() throws IOException {
-        Assume.assumeTrue(OS.IS_UNIX);
-        int pid = TestUtils.getProcessId();
-        Reader r = new ProcDataSource().getEnvironReader(pid);
-        assertNotNull(r);
-    }
-
-    @Test
-    public void testIoReader() throws Exception {
-        Assume.assumeTrue(OS.IS_UNIX);
-        int pid = TestUtils.getProcessId();
-        Reader r = new ProcDataSource().getIoReader(pid);
-        assertNotNull(r);
-    }
-
-    @Test
-    public void testStatReader() throws Exception {
-        Assume.assumeTrue(OS.IS_UNIX);
-        int pid = TestUtils.getProcessId();
-        Reader r = new ProcDataSource().getStatReader(pid);
-        assertNotNull(r);
-    }
-
-    @Test
-    public void testStatusReader() throws Exception {
-        Assume.assumeTrue(OS.IS_UNIX);
-        int pid = TestUtils.getProcessId();
-        Reader r = new ProcDataSource().getStatusReader(pid);
-        assertNotNull(r);
-    }
-}
-
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/utils/SysConfTest.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/agent/core/src/test/java/com/redhat/thermostat/agent/utils/SysConfTest.java	Thu Dec 08 10:23:22 2016 -0500
@@ -40,8 +40,6 @@
 
 import org.junit.Test;
 
-import com.redhat.thermostat.agent.utils.SysConf;
-
 public class SysConfTest {
 
     @Test
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/test/java/com/redhat/thermostat/agent/utils/linux/ProcDataSourceTest.java	Thu Dec 08 10:23:22 2016 -0500
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2012-2016 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.utils.linux;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import com.redhat.thermostat.shared.config.OS;
+import org.junit.Assume;
+import org.junit.Test;
+
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
+import com.redhat.thermostat.testutils.TestUtils;
+
+public class ProcDataSourceTest {
+
+    @Test
+    public void testGetCpuInfoReader() throws IOException {
+        Assume.assumeTrue(OS.IS_UNIX);
+        Reader r = new ProcDataSource().getCpuInfoReader();
+        assertNotNull(r);
+    }
+
+    @Test
+    public void testGetCpuLoadReader() throws IOException {
+        Assume.assumeTrue(OS.IS_UNIX);
+        Reader r = new ProcDataSource().getCpuLoadReader();
+        assertNotNull(r);
+    }
+
+    @Test
+    public void testGetMemInfoReader() throws IOException {
+        Assume.assumeTrue(OS.IS_UNIX);
+        Reader r = new ProcDataSource().getMemInfoReader();
+        assertNotNull(r);
+    }
+
+    @Test
+    public void testGetStatReader() throws IOException {
+        Assume.assumeTrue(OS.IS_UNIX);
+        int pid = TestUtils.getProcessId();
+        Reader r = new ProcDataSource().getStatReader(pid);
+        assertNotNull(r);
+    }
+
+    @Test
+    public void testGetEnvironReader() throws IOException {
+        Assume.assumeTrue(OS.IS_UNIX);
+        int pid = TestUtils.getProcessId();
+        Reader r = new ProcDataSource().getEnvironReader(pid);
+        assertNotNull(r);
+    }
+
+    @Test
+    public void testIoReader() throws Exception {
+        Assume.assumeTrue(OS.IS_UNIX);
+        int pid = TestUtils.getProcessId();
+        Reader r = new ProcDataSource().getIoReader(pid);
+        assertNotNull(r);
+    }
+
+    @Test
+    public void testStatReader() throws Exception {
+        Assume.assumeTrue(OS.IS_UNIX);
+        int pid = TestUtils.getProcessId();
+        Reader r = new ProcDataSource().getStatReader(pid);
+        assertNotNull(r);
+    }
+
+    @Test
+    public void testStatusReader() throws Exception {
+        Assume.assumeTrue(OS.IS_UNIX);
+        int pid = TestUtils.getProcessId();
+        Reader r = new ProcDataSource().getStatusReader(pid);
+        assertNotNull(r);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/test/java/com/redhat/thermostat/agent/utils/windows/WindowsHelperImplTest.java	Thu Dec 08 10:23:22 2016 -0500
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2012-2016 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.utils.windows;
+
+import com.redhat.thermostat.agent.utils.windows.WindowsHelperImpl;
+import com.redhat.thermostat.shared.config.OS;
+
+import org.junit.Assume;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.util.Map;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * These tests are disabled until we get the DLL path issues sorted out
+ * TODO - These tests currently fail on Windows because the helper DLL isn't on the execution path
+ */
+
+@Ignore
+public class WindowsHelperImplTest {
+
+    @Test
+    public void loadNativeLib() {
+        Assume.assumeTrue(OS.IS_WINDOWS);
+        final WindowsHelperImpl impl = WindowsHelperImpl.INSTANCE;
+        assertNotNull(impl);
+    }
+
+    @Test
+    public void testGetHostInfo() {
+        Assume.assumeTrue(OS.IS_WINDOWS);
+        final WindowsHelperImpl impl = WindowsHelperImpl.INSTANCE;
+        assertNotNull(impl);
+        assertContainsData(impl.getHostName());
+        assertContainsData(impl.getOSName());
+        assertTrue(impl.getOSName().toLowerCase().contains("win"));
+        assertContainsData(impl.getOSVersion());
+        assertContainsData(impl.getCPUModel());
+        assertTrue(impl.getCPUCount() > 0);
+        assertTrue(impl.getTotalMemory() > 0);
+    }
+
+    @Test
+    @Ignore
+    public void testGetProcessInfo() {
+        Assume.assumeTrue(OS.IS_WINDOWS);
+        final WindowsHelperImpl impl = WindowsHelperImpl.INSTANCE;
+        assertNotNull(impl);
+        int pid = /*TODO: retrieve current process identifier*/0;
+        assertContainsData(impl.getUserName(pid));
+        assertTrue(impl.getUid(pid) >= 0);
+        Map<String,String> envMap = impl.getEnvironment(pid);
+        assertNotNull(envMap);
+        assertFalse(envMap.isEmpty());
+    }
+
+    private static void assertContainsData( final String s ) {
+        assertNotNull(s);
+        assertFalse(s.isEmpty());
+    }
+}
--- a/distribution/pom.xml	Wed Dec 07 10:55:51 2016 -0500
+++ b/distribution/pom.xml	Thu Dec 08 10:23:22 2016 -0500
@@ -58,7 +58,7 @@
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <main.basedir>${project.basedir}/..</main.basedir>
   </properties>
-  
+
   <profiles>
     <profile>
       <id>default</id>
@@ -173,7 +173,7 @@
                           todir="${project.build.directory}/image/libs/native" />
                     <copy file="${main.basedir}/agent/core/target/UserNameUtilWrapper.dll"
                           todir="${project.build.directory}/image/libs/native" />
-                    <copy file="${main.basedir}/system-backend/target/WindowsHelperWrapper.dll"
+                    <copy file="${main.basedir}/agent/core/target/WindowsHelperWrapper.dll"
                           todir="${project.build.directory}/image/libs/native" />
                   </target>
                 </configuration>
@@ -212,7 +212,7 @@
             </executions>
           </plugin>
 
-         <plugin>
+          <plugin>
             <groupId>org.codehaus.mojo</groupId>
             <artifactId>exec-maven-plugin</artifactId>
             <executions>
@@ -236,7 +236,7 @@
       </build>
     </profile>
   </profiles>
-    
+
   <build>
     <plugins>
       <!-- skip unit test run-->
@@ -277,7 +277,7 @@
       <plugin>
         <artifactId>maven-assembly-plugin</artifactId>
         <configuration>
-          <appendAssemblyId>false</appendAssemblyId> 
+          <appendAssemblyId>false</appendAssemblyId>
         </configuration>
         <executions>
           <execution>
@@ -620,7 +620,7 @@
         <artifactId>thermostat-storage-mongodb</artifactId>
         <version>${project.version}</version>
     </dependency>
-    
+
     <!-- Plugins -->
 
     <!-- Be sure to add the distribution module of your plugin below
--- a/host-cpu/agent/src/main/java/com/redhat/thermostat/host/cpu/agent/internal/CpuStatBuilder.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/host-cpu/agent/src/main/java/com/redhat/thermostat/host/cpu/agent/internal/CpuStatBuilder.java	Thu Dec 08 10:23:22 2016 -0500
@@ -41,10 +41,11 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import com.redhat.thermostat.agent.utils.ProcDataSource;
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
 import com.redhat.thermostat.common.Clock;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.host.cpu.common.model.CpuStat;
+import com.redhat.thermostat.shared.config.OS;
 import com.redhat.thermostat.storage.core.WriterID;
 
 public class CpuStatBuilder {
@@ -73,8 +74,12 @@
             throw new IllegalStateException("already initialized");
         }
 
+        if (OS.IS_WINDOWS) {
+            logger.log(Level.WARNING, "CPU backend is not yet ported to Windows");
+        }
+
         previousTime = clock.getMonotonicTimeNanos();
-        previousCpuTicks = getCurrentCpuTicks();
+        previousCpuTicks = OS.IS_LINUX ? getCurrentCpuTicksLinux() : getCurrentCpuTicksWindows();
         initialized = true;
     }
 
@@ -85,7 +90,7 @@
 
         long currentRealTime = clock.getRealTimeMillis();
         long currentTime = clock.getMonotonicTimeNanos();
-        long[] currentValues = getCurrentCpuTicks();
+        long[] currentValues = OS.IS_LINUX ? getCurrentCpuTicksLinux() : getCurrentCpuTicksWindows();
 
         double[] cpuUsage = new double[currentValues.length];
 
@@ -102,7 +107,7 @@
         return new CpuStat(wId, currentRealTime, cpuUsage);
     }
 
-    private long[] getCurrentCpuTicks() {
+    private long[] getCurrentCpuTicksLinux() {
         int maxIndex = 0;
         long[] values = new long[1];
         try (BufferedReader reader = new BufferedReader(dataSource.getStatReader())) {
@@ -132,6 +137,12 @@
         return values;
     }
 
+    private long[] getCurrentCpuTicksWindows() {
+        long[] values = new long[1];
+        values[1] = clock.getMonotonicTimeNanos();
+        return values;
+    }
+
     public boolean isInitialized() {
         return initialized;
     }
--- a/host-cpu/agent/src/main/java/com/redhat/thermostat/host/cpu/agent/internal/HostCpuBackend.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/host-cpu/agent/src/main/java/com/redhat/thermostat/host/cpu/agent/internal/HostCpuBackend.java	Thu Dec 08 10:23:22 2016 -0500
@@ -38,7 +38,7 @@
 
 import java.util.concurrent.ScheduledExecutorService;
 
-import com.redhat.thermostat.agent.utils.ProcDataSource;
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
 import com.redhat.thermostat.agent.utils.SysConf;
 import com.redhat.thermostat.backend.HostPollingAction;
 import com.redhat.thermostat.backend.HostPollingBackend;
--- a/host-cpu/agent/src/test/java/com/redhat/thermostat/host/cpu/agent/internal/CpuStatBuilderTest.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/host-cpu/agent/src/test/java/com/redhat/thermostat/host/cpu/agent/internal/CpuStatBuilderTest.java	Thu Dec 08 10:23:22 2016 -0500
@@ -49,7 +49,7 @@
 
 import org.junit.Test;
 
-import com.redhat.thermostat.agent.utils.ProcDataSource;
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
 import com.redhat.thermostat.common.Clock;
 import com.redhat.thermostat.common.SystemClock;
 import com.redhat.thermostat.host.cpu.common.model.CpuStat;
--- a/host-memory/agent/src/main/java/com/redhat/thermostat/host/memory/agent/internal/HostMemoryBackend.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/host-memory/agent/src/main/java/com/redhat/thermostat/host/memory/agent/internal/HostMemoryBackend.java	Thu Dec 08 10:23:22 2016 -0500
@@ -38,7 +38,7 @@
 
 import java.util.concurrent.ScheduledExecutorService;
 
-import com.redhat.thermostat.agent.utils.ProcDataSource;
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
 import com.redhat.thermostat.backend.HostPollingAction;
 import com.redhat.thermostat.backend.HostPollingBackend;
 import com.redhat.thermostat.common.Version;
--- a/host-memory/agent/src/main/java/com/redhat/thermostat/host/memory/agent/internal/MemoryStatBuilder.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/host-memory/agent/src/main/java/com/redhat/thermostat/host/memory/agent/internal/MemoryStatBuilder.java	Thu Dec 08 10:23:22 2016 -0500
@@ -41,11 +41,13 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import com.redhat.thermostat.agent.utils.ProcDataSource;
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
+import com.redhat.thermostat.agent.utils.windows.WindowsHelperImpl;
 import com.redhat.thermostat.common.NotImplementedException;
 import com.redhat.thermostat.common.Size;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.host.memory.common.model.MemoryStat;
+import com.redhat.thermostat.shared.config.OS;
 import com.redhat.thermostat.storage.core.WriterID;
 
 /**
@@ -55,6 +57,8 @@
 
     private static final long UNAVAILABLE = -1;
 
+    private static final boolean IS_UNIX = OS.IS_UNIX;
+
     private static final String KEY_MEMORY_TOTAL = "MemTotal";
     private static final String KEY_MEMORY_FREE = "MemFree";
     private static final String KEY_BUFFERS = "Buffers";
@@ -71,9 +75,16 @@
     public MemoryStatBuilder(ProcDataSource dataSource, WriterID writerId) {
         this.dataSource = dataSource;
         this.writerId = writerId;
+        if (OS.IS_WINDOWS) {
+            logger.log(Level.WARNING, "Memory backend is not yet ported to Windows");
+        }
     }
 
     protected MemoryStat build() {
+        return IS_UNIX ? buildFromLinuxProc() : buildFromWindows();
+    }
+
+    private MemoryStat buildFromLinuxProc() {
         long timestamp = System.currentTimeMillis();
 
         long total = UNAVAILABLE;
@@ -115,6 +126,16 @@
         return new MemoryStat(wId, timestamp, total, free, buffers, cached, swapTotal, swapFree, commitLimit);
     }
 
+
+    private MemoryStat buildFromWindows() {
+        long timestamp = System.currentTimeMillis();
+
+        WindowsHelperImpl.MemoryStat memstat = new WindowsHelperImpl.MemoryStat();
+
+        String wId = writerId.getWriterID();
+        return new MemoryStat(wId, timestamp, memstat.getTotal(), memstat.getFree(), memstat.getBuffers(), memstat.getCached(), memstat.getSwapTotal(), memstat.getSwapFree(), memstat.getCommitLimit());
+    }
+
     private long getValue(String rawValue) {
         String[] parts = rawValue.split(" +");
         String value = rawValue;
--- a/host-memory/agent/src/test/java/com/redhat/thermostat/host/memory/agent/internal/MemoryStatBuilderTest.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/host-memory/agent/src/test/java/com/redhat/thermostat/host/memory/agent/internal/MemoryStatBuilderTest.java	Thu Dec 08 10:23:22 2016 -0500
@@ -49,7 +49,7 @@
 import org.junit.Before;
 import org.junit.Test;
 
-import com.redhat.thermostat.agent.utils.ProcDataSource;
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
 import com.redhat.thermostat.host.memory.common.model.MemoryStat;
 import com.redhat.thermostat.storage.core.WriterID;
 
--- a/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/Activator.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/Activator.java	Thu Dec 08 10:23:22 2016 -0500
@@ -36,6 +36,8 @@
 
 package com.redhat.thermostat.numa.agent.internal;
 
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.shared.config.OS;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
@@ -50,8 +52,13 @@
 import com.redhat.thermostat.numa.common.NumaDAO;
 import com.redhat.thermostat.storage.core.WriterID;
 
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
 public class Activator implements BundleActivator {
-    
+
+    private static final Logger logger = LoggingUtils.getLogger(Activator.class);
+
     private MultipleServiceTracker tracker;
     private NumaBackend backend;
     private ServiceRegistration<Backend> reg;
@@ -73,9 +80,12 @@
                 NumaDAO numaDAO = services.get(NumaDAO.class);
                 Version version = new Version(context.getBundle());
                 WriterID writerId = services.get(WriterID.class);
-                NumaCollector collector = new NumaCollector();
+                NumaCollector collector = OS.IS_LINUX ? new NumaLinuxCollectorImpl() : new NumaWindowsCollectorImpl();
                 backend = new NumaBackend(appService, numaDAO, collector, version, writerId);
                 reg = context.registerService(Backend.class, backend, null);
+                if (OS.IS_WINDOWS) {
+                    logger.log(Level.WARNING, "NUMA backend is not yet ported to Windows");
+                }
             }
 
             @Override
--- a/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaCollector.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaCollector.java	Thu Dec 08 10:23:22 2016 -0500
@@ -37,66 +37,13 @@
 
 package com.redhat.thermostat.numa.agent.internal;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FilenameFilter;
 import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
 
 import com.redhat.thermostat.numa.common.NumaNodeStat;
 
-class NumaCollector {
-
-    private static final String NUMA_BASE_DIR = "/sys/devices/system/node";
-
-    private static final String NODE_DIR_PREFIX = "node";
-
-    private static final String NUMA_STAT_FILE = "numastat";
-
-    private int numberOfNodes;
-
-    private File baseDir;
-
-    NumaCollector() {
-        this(NUMA_BASE_DIR);
-    }
+interface NumaCollector {
 
-    NumaCollector(String baseDirectory) {
-        baseDir = new File(baseDirectory);
-        FilenameFilter filter = new FilenameFilter() {
-            
-            @Override
-            public boolean accept(File dir, String name) {
-                return name.startsWith(NODE_DIR_PREFIX);
-            }
-        };
-        String[] nodeFiles = baseDir.list(filter);
-        numberOfNodes = nodeFiles.length;
-    }
-
-    NumaNodeStat[] collectData() throws IOException {
-        NumaNodeStat[] stat = new NumaNodeStat[numberOfNodes];
-        for (int i = 0; i < numberOfNodes; i++) {
-            File nodeDir = new File(baseDir, NODE_DIR_PREFIX + i);
-            File numaStatFile = new File(nodeDir, NUMA_STAT_FILE);
-            try (FileInputStream in = new FileInputStream(numaStatFile)) {
-                Reader reader = new InputStreamReader(in);
-                NumaStatBuilder builder = new NumaStatBuilder(reader);
-                stat[i] = builder.build();
-                stat[i].setNodeId(i);
-            }
-        }
-        return stat;
-    }
-
-    // This is here for testing.
-    String getBaseDir() {
-        return baseDir.getAbsolutePath();
-    }
-
-    public int getNumberOfNumaNodes() {
-        return numberOfNodes;
-    }
+    NumaNodeStat[] collectData() throws IOException;
+    int getNumberOfNumaNodes();
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaLinuxCollectorImpl.java	Thu Dec 08 10:23:22 2016 -0500
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2012-2016 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.numa.agent.internal;
+
+import com.redhat.thermostat.numa.common.NumaNodeStat;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+
+class NumaLinuxCollectorImpl implements NumaCollector {
+
+    private static final String NUMA_BASE_DIR = "/sys/devices/system/node";
+
+    private static final String NODE_DIR_PREFIX = "node";
+
+    private static final String NUMA_STAT_FILE = "numastat";
+
+    private int numberOfNodes;
+
+    private File baseDir;
+
+    NumaLinuxCollectorImpl() {
+        this(NUMA_BASE_DIR);
+    }
+
+    NumaLinuxCollectorImpl(String baseDirectory) {
+        baseDir = new File(baseDirectory);
+        FilenameFilter filter = new FilenameFilter() {
+            
+            @Override
+            public boolean accept(File dir, String name) {
+                return name.startsWith(NODE_DIR_PREFIX);
+            }
+        };
+        String[] nodeFiles = baseDir.list(filter);
+        numberOfNodes = nodeFiles.length;
+    }
+
+    public NumaNodeStat[] collectData() throws IOException {
+        NumaNodeStat[] stat = new NumaNodeStat[numberOfNodes];
+        for (int i = 0; i < numberOfNodes; i++) {
+            File nodeDir = new File(baseDir, NODE_DIR_PREFIX + i);
+            File numaStatFile = new File(nodeDir, NUMA_STAT_FILE);
+            try (FileInputStream in = new FileInputStream(numaStatFile)) {
+                Reader reader = new InputStreamReader(in);
+                NumaStatBuilder builder = new NumaStatBuilder(reader);
+                stat[i] = builder.build();
+                stat[i].setNodeId(i);
+            }
+        }
+        return stat;
+    }
+
+    // This is here for testing.
+    String getBaseDir() {
+        return baseDir.getAbsolutePath();
+    }
+
+    public int getNumberOfNumaNodes() {
+        return numberOfNodes;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaWindowsCollectorImpl.java	Thu Dec 08 10:23:22 2016 -0500
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2012-2016 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.numa.agent.internal;
+
+import com.redhat.thermostat.numa.common.NumaNodeStat;
+
+import java.io.IOException;
+
+public class NumaWindowsCollectorImpl implements NumaCollector {
+
+    @Override
+    public NumaNodeStat[] collectData() throws IOException {
+        final NumaNodeStat[] nsa = new NumaNodeStat[1];
+        final NumaNodeStat ns = new NumaNodeStat();
+        nsa[0] = ns;
+        return nsa;
+    }
+
+    @Override
+    public int getNumberOfNumaNodes() {
+        return 1;
+    }
+}
--- a/numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaCollectorTest.java	Wed Dec 07 10:55:51 2016 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,167 +0,0 @@
-/*
- * Copyright 2012-2016 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.numa.agent.internal;
-
-import static org.junit.Assert.assertEquals;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.file.FileVisitResult;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.SimpleFileVisitor;
-import java.nio.file.attribute.BasicFileAttributes;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.numa.common.NumaNodeStat;
-
-public class NumaCollectorTest {
-
-    private static final String TEST_STAT0 = "numa_hit 11\n" +
-            "numa_miss 12\n" +
-            "numa_foreign 13\n" +
-            "interleave_hit 14\n" +
-            "local_node 15\n" +
-            "other_node 16\n";
-
-    private static final String TEST_STAT1 = "numa_hit 21\n" +
-            "numa_miss 22\n" +
-            "numa_foreign 23\n" +
-            "interleave_hit 24\n" +
-            "local_node 25\n" +
-            "other_node 26\n";
-
-    private static final String TEST_STAT2 = "numa_hit 31\n" +
-            "numa_miss 32\n" +
-            "numa_foreign 33\n" +
-            "interleave_hit 34\n" +
-            "local_node 35\n" +
-            "other_node 36\n";
-
-    private File tmpDir;
-
-    @Before
-    public void setUp() throws IOException {
-        tmpDir = Files.createTempDirectory("numa-test").toFile();
-
-        File nodeDir0 = new File(tmpDir, "node0");
-        nodeDir0.mkdir();
-        File numaStatFile0 = new File(nodeDir0, "numastat");
-        FileOutputStream out0 = new FileOutputStream(numaStatFile0);
-        out0.write(TEST_STAT0.getBytes());
-        out0.close();
-
-        File nodeDir1 = new File(tmpDir, "node1");
-        nodeDir1.mkdir();
-        File numaStatFile1 = new File(nodeDir1, "numastat");
-        FileOutputStream out1 = new FileOutputStream(numaStatFile1);
-        out1.write(TEST_STAT1.getBytes());
-        out1.close();
-
-        File nodeDir2 = new File(tmpDir, "node2");
-        nodeDir2.mkdir();
-        File numaStatFile2 = new File(nodeDir2, "numastat");
-        FileOutputStream out2 = new FileOutputStream(numaStatFile2);
-        out2.write(TEST_STAT2.getBytes());
-        out2.close();
-
-        File fluff = new File(tmpDir, "fluff");
-        fluff.mkdir();
-
-    }
-
-    @After
-    public void tearDown() throws IOException {
-        Files.walkFileTree(tmpDir.toPath(), new SimpleFileVisitor<Path>() {
-            @Override
-            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
-                Files.delete(file);
-                return super.visitFile(file, attrs);
-            }
-            @Override
-            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
-                Files.delete(dir);
-                return super.postVisitDirectory(dir, exc);
-            }
-        });
-    }
-
-    @Test
-    public void testStats() throws IOException {
-        NumaCollector coll = new NumaCollector(tmpDir.getAbsolutePath());
-        NumaNodeStat[] stats = coll.collectData();
-
-        assertEquals(3, stats.length);
-
-        assertEquals(0, stats[0].getNodeId());
-        assertEquals(11, stats[0].getNumaHit());
-        assertEquals(12, stats[0].getNumaMiss());
-        assertEquals(13, stats[0].getNumaForeign());
-        assertEquals(14, stats[0].getInterleaveHit());
-        assertEquals(15, stats[0].getLocalNode());
-        assertEquals(16, stats[0].getOtherNode());
-
-        assertEquals(1, stats[1].getNodeId());
-        assertEquals(21, stats[1].getNumaHit());
-        assertEquals(22, stats[1].getNumaMiss());
-        assertEquals(23, stats[1].getNumaForeign());
-        assertEquals(24, stats[1].getInterleaveHit());
-        assertEquals(25, stats[1].getLocalNode());
-        assertEquals(26, stats[1].getOtherNode());
-
-        assertEquals(2, stats[2].getNodeId());
-        assertEquals(31, stats[2].getNumaHit());
-        assertEquals(32, stats[2].getNumaMiss());
-        assertEquals(33, stats[2].getNumaForeign());
-        assertEquals(34, stats[2].getInterleaveHit());
-        assertEquals(35, stats[2].getLocalNode());
-        assertEquals(36, stats[2].getOtherNode());
-
-    }
-
-    @Test
-    public void testDefaultDir() {
-        NumaCollector coll = new NumaCollector();
-        assertEquals("/sys/devices/system/node", coll.getBaseDir());
-    }
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaLinuxCollectorTest.java	Thu Dec 08 10:23:22 2016 -0500
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2012-2016 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.numa.agent.internal;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.numa.common.NumaNodeStat;
+
+public class NumaLinuxCollectorTest {
+
+    private static final String TEST_STAT0 = "numa_hit 11\n" +
+            "numa_miss 12\n" +
+            "numa_foreign 13\n" +
+            "interleave_hit 14\n" +
+            "local_node 15\n" +
+            "other_node 16\n";
+
+    private static final String TEST_STAT1 = "numa_hit 21\n" +
+            "numa_miss 22\n" +
+            "numa_foreign 23\n" +
+            "interleave_hit 24\n" +
+            "local_node 25\n" +
+            "other_node 26\n";
+
+    private static final String TEST_STAT2 = "numa_hit 31\n" +
+            "numa_miss 32\n" +
+            "numa_foreign 33\n" +
+            "interleave_hit 34\n" +
+            "local_node 35\n" +
+            "other_node 36\n";
+
+    private File tmpDir;
+
+    @Before
+    public void setUp() throws IOException {
+        tmpDir = Files.createTempDirectory("numa-test").toFile();
+
+        File nodeDir0 = new File(tmpDir, "node0");
+        nodeDir0.mkdir();
+        File numaStatFile0 = new File(nodeDir0, "numastat");
+        FileOutputStream out0 = new FileOutputStream(numaStatFile0);
+        out0.write(TEST_STAT0.getBytes());
+        out0.close();
+
+        File nodeDir1 = new File(tmpDir, "node1");
+        nodeDir1.mkdir();
+        File numaStatFile1 = new File(nodeDir1, "numastat");
+        FileOutputStream out1 = new FileOutputStream(numaStatFile1);
+        out1.write(TEST_STAT1.getBytes());
+        out1.close();
+
+        File nodeDir2 = new File(tmpDir, "node2");
+        nodeDir2.mkdir();
+        File numaStatFile2 = new File(nodeDir2, "numastat");
+        FileOutputStream out2 = new FileOutputStream(numaStatFile2);
+        out2.write(TEST_STAT2.getBytes());
+        out2.close();
+
+        File fluff = new File(tmpDir, "fluff");
+        fluff.mkdir();
+
+    }
+
+    @After
+    public void tearDown() throws IOException {
+        Files.walkFileTree(tmpDir.toPath(), new SimpleFileVisitor<Path>() {
+            @Override
+            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                Files.delete(file);
+                return super.visitFile(file, attrs);
+            }
+            @Override
+            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+                Files.delete(dir);
+                return super.postVisitDirectory(dir, exc);
+            }
+        });
+    }
+
+    @Test
+    public void testStats() throws IOException {
+        NumaCollector coll = new NumaLinuxCollectorImpl(tmpDir.getAbsolutePath());
+        NumaNodeStat[] stats = coll.collectData();
+
+        assertEquals(3, stats.length);
+
+        assertEquals(0, stats[0].getNodeId());
+        assertEquals(11, stats[0].getNumaHit());
+        assertEquals(12, stats[0].getNumaMiss());
+        assertEquals(13, stats[0].getNumaForeign());
+        assertEquals(14, stats[0].getInterleaveHit());
+        assertEquals(15, stats[0].getLocalNode());
+        assertEquals(16, stats[0].getOtherNode());
+
+        assertEquals(1, stats[1].getNodeId());
+        assertEquals(21, stats[1].getNumaHit());
+        assertEquals(22, stats[1].getNumaMiss());
+        assertEquals(23, stats[1].getNumaForeign());
+        assertEquals(24, stats[1].getInterleaveHit());
+        assertEquals(25, stats[1].getLocalNode());
+        assertEquals(26, stats[1].getOtherNode());
+
+        assertEquals(2, stats[2].getNodeId());
+        assertEquals(31, stats[2].getNumaHit());
+        assertEquals(32, stats[2].getNumaMiss());
+        assertEquals(33, stats[2].getNumaForeign());
+        assertEquals(34, stats[2].getInterleaveHit());
+        assertEquals(35, stats[2].getLocalNode());
+        assertEquals(36, stats[2].getOtherNode());
+
+    }
+
+    @Test
+    public void testDefaultDir() {
+        NumaLinuxCollectorImpl coll = new NumaLinuxCollectorImpl();
+        assertEquals("/sys/devices/system/node", coll.getBaseDir());
+    }
+}
+
--- a/system-backend/Makefile	Wed Dec 07 10:55:51 2016 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-CC         = gcc
-JAVAH      = javah
-MYCFLAGS   = -c -Wall -fPIC $(EXTRA_CFLAGS)
-MYLDFLAGS  = -fPIC -shared $(EXTRA_CFLAGS)
-COPY       = cp -a
-
-JNI_PLATFORM = linux
-CLASSPATH  = target/classes/
-TARGET_DIR = target
-SO_PREFIX  = lib
-SO_SUFFIX  = .so
-
-INCLUDE    = -I $(TARGET_DIR) -I "$(JAVA_HOME)/include/" -I "$(JAVA_HOME)/include/$(JNI_PLATFORM)"
-
-WINHELPER_SOURCES    = src/main/native/WindowsHelperImpl.c
-WINHELPER_TARGET     = $(TARGET_DIR)/WindowsHelperImpl.c
-WINHELPER_OBJECTS    = $(WINHELPER_TARGET:.c=.o)
-WINHELPER_EXECUTABLE = $(SO_PREFIX)WindowsHelperWrapper$(SO_SUFFIX)
-
-.PHONY:
-JNI_LIST = com.redhat.thermostat.backend.system.internal.windows.WindowsHelperImpl
-
-$(JNI_LIST):
-	$(JAVAH) -force -classpath $(CLASSPATH) -d $(TARGET_DIR) $(JNI_LIST)
-
-all: $(JNI_LIST) init $(WINHELPER_SOURCES) $(WINHELPER_EXECUTABLE)
-
-.PHONY:
-init:
-	$(COPY) $(WINHELPER_SOURCES) $(WINHELPER_TARGET)
-
-$(WINHELPER_EXECUTABLE): $(WINHELPER_OBJECTS)
-	$(CC) $(WINHELPER_OBJECTS) -o $(TARGET_DIR)/$@ $(MYLDFLAGS) $(LDFLAGS) $(PLATFORM_LIBS)
-	
-.c.o:
-	$(CC) $(MYCFLAGS) $(CFLAGS) $(INCLUDE) $< -o $@
-
-clean-lib:
-	rm -f $(TARGET_DIR)/$(WINHELPER_EXECUTABLE)
-
-clean-obj:
-	rm -f $(WINHELPER_OBJECTS) $(WINHELPER_TARGET)
-	
-clean: clean-obj clean-lib
-
-
--- a/system-backend/pom.xml	Wed Dec 07 10:55:51 2016 -0500
+++ b/system-backend/pom.xml	Thu Dec 08 10:23:22 2016 -0500
@@ -50,66 +50,6 @@
 
   <name>Thermostat System Backend</name>
 
-  <profiles>
-    <profile>
-      <id>default</id>
-      <activation>
-        <activeByDefault>true</activeByDefault>
-      </activation>
-    </profile>
-
-    <profile>
-      <id>linux</id>
-      <activation>
-        <os><family>Unix</family></os>
-      </activation>
-      <properties>
-        <platform.libs/>
-      </properties>
-    </profile>
-
-    <profile>
-      <id>windows</id>
-      <activation>
-        <os><family>Windows</family></os>
-      </activation>
-      <properties>
-        <platform.libs>-lws2_32</platform.libs>
-        <sharedlib.prefix/>
-        <sharedlib.suffix>.dll</sharedlib.suffix>
-      </properties>
-      <build>
-        <plugins>
-
-          <plugin>
-            <groupId>org.codehaus.mojo</groupId>
-            <artifactId>exec-maven-plugin</artifactId>
-            <executions>
-              <execution>
-                <phase>compile</phase>
-                <goals>
-                  <goal>exec</goal>
-                </goals>
-              </execution>
-            </executions>
-            <configuration>
-              <executable>make</executable>
-              <arguments>
-                <argument>all</argument>
-                <argument>CC=${c.compiler}</argument>
-                <argument>SO_PREFIX=${sharedlib.prefix}</argument>
-                <argument>SO_SUFFIX=${sharedlib.suffix}</argument>
-                <argument>EXTRA_CFLAGS=${cflags}</argument>
-                <argument>JNI_PLATFORM=${jni.platform}</argument>
-                <argument>PLATFORM_LIBS=${platform.libs}</argument>
-              </arguments>
-            </configuration>
-          </plugin>
-        </plugins>
-      </build>
-    </profile>
-  </profiles>
-
   <dependencies>
     <dependency>
       <groupId>junit</groupId>
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/NetworkInfoBuilder.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/NetworkInfoBuilder.java	Thu Dec 08 10:23:22 2016 -0500
@@ -61,23 +61,35 @@
     public NetworkInfoBuilder(WriterID writerId) {
         this.writerId = writerId;
     }
-    
-    public List<NetworkInterfaceInfo> build() {
-        List<NetworkInterfaceInfo> infos = new ArrayList<NetworkInterfaceInfo>();
-        String wId = writerId.getWriterID();
-        try {
-            Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
-            for (NetworkInterface iface : Collections.list(ifaces)) {
-                NetworkInterfaceInfo info = new NetworkInterfaceInfo(wId, iface.getName());
-                for (InetAddress addr : Collections.list(iface.getInetAddresses())) {
-                    if (addr instanceof Inet4Address) {
-                        info.setIp4Addr(addr.getHostAddress());
-                    } else if (addr instanceof Inet6Address) {
-                        info.setIp6Addr(addr.getHostAddress());
-                    }
+
+    private void addInterfaces(final String wId, List<NetworkInterfaceInfo> infos, List<NetworkInterface> ifaceList, boolean addAll, boolean addUnconnected) {
+        for (NetworkInterface iface : ifaceList) {
+            NetworkInterfaceInfo info = new NetworkInterfaceInfo(wId, iface.getName());
+            List<InetAddress> addrList = Collections.list(iface.getInetAddresses());
+            final boolean want = addAll || (addrList.isEmpty() == addUnconnected);
+            for (InetAddress addr : addrList) {
+                if (addr instanceof Inet4Address) {
+                    info.setIp4Addr(addr.getHostAddress());
+                } else if (addr instanceof Inet6Address) {
+                    info.setIp6Addr(addr.getHostAddress());
                 }
+            }
+            if (want) {
                 infos.add(info);
             }
+        }
+    }
+
+    public List<NetworkInterfaceInfo> build() {
+        final List<NetworkInterfaceInfo> infos = new ArrayList<NetworkInterfaceInfo>();
+        final String wId = writerId.getWriterID();
+        try {
+            final Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
+            final List<NetworkInterface> ifaceList = Collections.list(ifaces);
+            // list connected interfaces first (there is a lot of noise on windows)
+            addInterfaces(wId, infos, ifaceList, false, false);
+            addInterfaces(wId, infos, ifaceList, false, true);
+
         } catch (SocketException e) {
             logger.log(Level.WARNING, "error enumerating network interfaces");
         }
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/linux/HostInfoBuilderImpl.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/linux/HostInfoBuilderImpl.java	Thu Dec 08 10:23:22 2016 -0500
@@ -43,7 +43,7 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import com.redhat.thermostat.agent.utils.ProcDataSource;
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
 import com.redhat.thermostat.agent.utils.hostname.HostName;
 import com.redhat.thermostat.backend.system.internal.models.HostInfoBuilder;
 import com.redhat.thermostat.common.Size;
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/linux/LinuxInfoBuilderFactory.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/linux/LinuxInfoBuilderFactory.java	Thu Dec 08 10:23:22 2016 -0500
@@ -36,7 +36,7 @@
 
 package com.redhat.thermostat.backend.system.internal.linux;
 
-import com.redhat.thermostat.agent.utils.ProcDataSource;
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
 import com.redhat.thermostat.agent.utils.username.UserNameUtil;
 import com.redhat.thermostat.backend.system.internal.models.HostInfoBuilder;
 import com.redhat.thermostat.backend.system.internal.models.InfoBuilderFactory;
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/linux/ProcessEnvironmentBuilderImpl.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/linux/ProcessEnvironmentBuilderImpl.java	Thu Dec 08 10:23:22 2016 -0500
@@ -46,7 +46,7 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import com.redhat.thermostat.agent.utils.ProcDataSource;
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
 import com.redhat.thermostat.backend.system.internal.models.ProcessEnvironmentBuilder;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/linux/ProcessUserInfoBuilderImpl.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/linux/ProcessUserInfoBuilderImpl.java	Thu Dec 08 10:23:22 2016 -0500
@@ -42,7 +42,7 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import com.redhat.thermostat.agent.utils.ProcDataSource;
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
 import com.redhat.thermostat.agent.utils.username.UserNameLookupException;
 import com.redhat.thermostat.agent.utils.username.UserNameUtil;
 import com.redhat.thermostat.backend.system.internal.models.ProcessUserInfo;
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/windows/WindowsHelperImpl.java	Wed Dec 07 10:55:51 2016 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,133 +0,0 @@
-/*
- * Copyright 2012-2016 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.windows;
-
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.shared.config.NativeLibraryResolver;
-import com.redhat.thermostat.shared.config.OS;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.logging.Logger;
-
-/**
- * Utility class to access Windows native code
- */
-class WindowsHelperImpl {
-
-    private static final Logger logger = LoggingUtils.getLogger(WindowsHelperImpl.class);
-
-    static {
-        if (OS.IS_WINDOWS) {
-            try {
-                String lib = NativeLibraryResolver.getAbsoluteLibraryPath("WindowsHelperImpl");
-                System.load(lib);
-                INSTANCE = new WindowsHelperImpl();
-            } catch (UnsatisfiedLinkError e) {
-                logger.severe("Could not load WindowsHelperImpl DLL");
-                INSTANCE = null;
-                // do not throw here, because you'll get a NoClassDefFound thrown when running other tests that Mock this class
-            }
-        } else {
-            INSTANCE = null;
-        }
-    }
-
-    public static WindowsHelperImpl INSTANCE;
-
-    private WindowsHelperImpl() {
-    }
-    // local host-wide information
-
-    String getHostName() {
-        return getHostName0();
-    }
-
-    String getOSName() {
-        return System.getProperty("os.name");
-    }
-
-    String getOSVersion() {
-        return "(stub OS version)";
-    }
-
-    String getCPUModel() {
-        return "(stub CPU model)";
-    }
-
-    int getCPUCount() {
-        return 88;
-    }
-
-    long getTotalMemory() {
-        return 999;
-    }
-
-    // local process-specific information
-    String getUserName(int pid) {
-        return getUserName0(pid);
-    }
-
-    int getUid(int pid) {
-        return getUid0(pid);
-    }
-
-    Map<String, String> getEnvironment(int pid) {
-        // the environment is returned as a 1D array of alternating env names and values
-        final String[] envArray = getEnvironment0(pid);
-        if (envArray == null) {
-            return Collections.emptyMap();
-        }
-
-        if (envArray.length % 2 != 0) {
-            throw new AssertionError("environment array length not even");
-        }
-
-        Map<String, String> env = new HashMap<>(envArray.length/2);
-        for (int i = 0; i < envArray.length / 2; i++) {
-            env.put(envArray[i * 2], envArray[i * 2 + 1]);
-        }
-        return env;
-    }
-
-    private static native String getHostName0();
-    private static native int getUid0(int pid);
-    private static native String getUserName0(int pid);
-    private static native String[] getEnvironment0(int pid);
-}
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/windows/WindowsHostInfoBuilderImpl.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/windows/WindowsHostInfoBuilderImpl.java	Thu Dec 08 10:23:22 2016 -0500
@@ -36,6 +36,7 @@
 
 package com.redhat.thermostat.backend.system.internal.windows;
 
+import com.redhat.thermostat.agent.utils.windows.WindowsHelperImpl;
 import com.redhat.thermostat.backend.system.internal.models.HostInfoBuilder;
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.model.HostInfo;
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/windows/WindowsProcessEnvironmentBuilderImpl.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/windows/WindowsProcessEnvironmentBuilderImpl.java	Thu Dec 08 10:23:22 2016 -0500
@@ -36,6 +36,7 @@
 
 package com.redhat.thermostat.backend.system.internal.windows;
 
+import com.redhat.thermostat.agent.utils.windows.WindowsHelperImpl;
 import com.redhat.thermostat.backend.system.internal.models.ProcessEnvironmentBuilder;
 
 import java.util.Map;
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/windows/WindowsUserInfoBuilderImpl.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/windows/WindowsUserInfoBuilderImpl.java	Thu Dec 08 10:23:22 2016 -0500
@@ -36,6 +36,7 @@
 
 package com.redhat.thermostat.backend.system.internal.windows;
 
+import com.redhat.thermostat.agent.utils.windows.WindowsHelperImpl;
 import com.redhat.thermostat.backend.system.internal.models.ProcessUserInfo;
 import com.redhat.thermostat.backend.system.internal.models.ProcessUserInfoBuilder;
 import com.redhat.thermostat.common.utils.LoggingUtils;
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/linux/HostInfoBuilderTest.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/linux/HostInfoBuilderTest.java	Thu Dec 08 10:23:22 2016 -0500
@@ -51,7 +51,7 @@
 import org.junit.Before;
 import org.junit.Test;
 
-import com.redhat.thermostat.agent.utils.ProcDataSource;
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
 import com.redhat.thermostat.backend.system.internal.linux.HostInfoBuilderImpl.HostCpuInfo;
 import com.redhat.thermostat.backend.system.internal.linux.HostInfoBuilderImpl.HostMemoryInfo;
 import com.redhat.thermostat.backend.system.internal.linux.HostInfoBuilderImpl.HostOsInfo;
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/linux/ProcessEnvironmentBuilderTest.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/linux/ProcessEnvironmentBuilderTest.java	Thu Dec 08 10:23:22 2016 -0500
@@ -57,7 +57,7 @@
 import org.junit.Assume;
 import org.junit.Test;
 
-import com.redhat.thermostat.agent.utils.ProcDataSource;
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
 import com.redhat.thermostat.testutils.TestUtils;
 
 public class ProcessEnvironmentBuilderTest {
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/linux/ProcessUserInfoBuilderTest.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/linux/ProcessUserInfoBuilderTest.java	Thu Dec 08 10:23:22 2016 -0500
@@ -46,7 +46,7 @@
 
 import org.junit.Test;
 
-import com.redhat.thermostat.agent.utils.ProcDataSource;
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
 import com.redhat.thermostat.agent.utils.username.UserNameLookupException;
 import com.redhat.thermostat.agent.utils.username.UserNameUtil;
 import com.redhat.thermostat.backend.system.internal.models.ProcessUserInfo;
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/windows/WindowsHelperImplTest.java	Wed Dec 07 10:55:51 2016 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,98 +0,0 @@
-/*
- * Copyright 2012-2016 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.windows;
-
-import com.redhat.thermostat.shared.config.OS;
-
-import org.junit.Assume;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import java.util.Map;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-/**
- * These tests are disabled until we get the DLL path issues sorted out
- * TODO - These tests currently fail on Windows because the helper DLL isn't on the execution path
- */
-
-@Ignore
-public class WindowsHelperImplTest {
-
-    @Test
-    public void loadNativeLib() {
-        Assume.assumeTrue(OS.IS_WINDOWS);
-        final WindowsHelperImpl impl = WindowsHelperImpl.INSTANCE;
-        assertNotNull(impl);
-    }
-
-    @Test
-    public void testGetHostInfo() {
-        Assume.assumeTrue(OS.IS_WINDOWS);
-        final WindowsHelperImpl impl = WindowsHelperImpl.INSTANCE;
-        assertNotNull(impl);
-        assertContainsData(impl.getHostName());
-        assertContainsData(impl.getOSName());
-        assertTrue(impl.getOSName().toLowerCase().contains("win"));
-        assertContainsData(impl.getOSVersion());
-        assertContainsData(impl.getCPUModel());
-        assertTrue(impl.getCPUCount() > 0);
-        assertTrue(impl.getTotalMemory() > 0);
-    }
-
-    @Test
-    @Ignore
-    public void testGetProcessInfo() {
-        Assume.assumeTrue(OS.IS_WINDOWS);
-        final WindowsHelperImpl impl = WindowsHelperImpl.INSTANCE;
-        assertNotNull(impl);
-        int pid = /*TODO: retrieve current process identifier*/0;
-        assertContainsData(impl.getUserName(pid));
-        assertTrue(impl.getUid(pid) >= 0);
-        Map<String,String> envMap = impl.getEnvironment(pid);
-        assertNotNull(envMap);
-        assertFalse(envMap.isEmpty());
-    }
-
-    private static void assertContainsData( final String s ) {
-        assertNotNull(s);
-        assertFalse(s.isEmpty());
-    }
-}
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/windows/WindowsHostInfoBuilderTest.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/windows/WindowsHostInfoBuilderTest.java	Thu Dec 08 10:23:22 2016 -0500
@@ -36,6 +36,7 @@
 
 package com.redhat.thermostat.backend.system.internal.windows;
 
+import com.redhat.thermostat.agent.utils.windows.WindowsHelperImpl;
 import com.redhat.thermostat.backend.system.internal.models.HostInfoBuilder;
 import com.redhat.thermostat.shared.config.OS;
 import com.redhat.thermostat.storage.core.WriterID;
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/windows/WindowsProcessEnvironmentBuilderTest.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/windows/WindowsProcessEnvironmentBuilderTest.java	Thu Dec 08 10:23:22 2016 -0500
@@ -36,6 +36,7 @@
 
 package com.redhat.thermostat.backend.system.internal.windows;
 
+import com.redhat.thermostat.agent.utils.windows.WindowsHelperImpl;
 import com.redhat.thermostat.backend.system.internal.models.ProcessEnvironmentBuilder;
 import com.redhat.thermostat.shared.config.OS;
 
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/windows/WindowsProcessUserInfoBuilderTest.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/windows/WindowsProcessUserInfoBuilderTest.java	Thu Dec 08 10:23:22 2016 -0500
@@ -36,6 +36,7 @@
 
 package com.redhat.thermostat.backend.system.internal.windows;
 
+import com.redhat.thermostat.agent.utils.windows.WindowsHelperImpl;
 import com.redhat.thermostat.backend.system.internal.models.ProcessUserInfo;
 import com.redhat.thermostat.backend.system.internal.models.ProcessUserInfoBuilder;
 import com.redhat.thermostat.shared.config.OS;
--- a/vm-byteman/agent/src/main/java/com/redhat/thermostat/vm/byteman/agent/internal/BytemanRequestReceiver.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/vm-byteman/agent/src/main/java/com/redhat/thermostat/vm/byteman/agent/internal/BytemanRequestReceiver.java	Thu Dec 08 10:23:22 2016 -0500
@@ -53,7 +53,7 @@
 
 import com.redhat.thermostat.agent.command.RequestReceiver;
 import com.redhat.thermostat.agent.ipc.server.AgentIPCService;
-import com.redhat.thermostat.agent.utils.ProcDataSource;
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
 import com.redhat.thermostat.agent.utils.username.UserNameUtil;
 import com.redhat.thermostat.common.command.Request;
 import com.redhat.thermostat.common.command.Response;
--- a/vm-byteman/agent/src/main/java/com/redhat/thermostat/vm/byteman/agent/internal/ProcessUserInfoBuilder.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/vm-byteman/agent/src/main/java/com/redhat/thermostat/vm/byteman/agent/internal/ProcessUserInfoBuilder.java	Thu Dec 08 10:23:22 2016 -0500
@@ -42,7 +42,7 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import com.redhat.thermostat.agent.utils.ProcDataSource;
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
 import com.redhat.thermostat.agent.utils.username.UserNameLookupException;
 import com.redhat.thermostat.agent.utils.username.UserNameUtil;
 import com.redhat.thermostat.common.utils.LoggingUtils;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/LinuxProcessStatusInfoBuilderImpl.java	Thu Dec 08 10:23:22 2016 -0500
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2012-2016 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.vm.cpu.agent.internal;
+
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Scanner;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Extract status information about the process from /proc/. This is what tools
+ * like {@code ps} and {@code top} use.
+ *
+ * @see {@code proc(5)}
+ */
+public class LinuxProcessStatusInfoBuilderImpl implements ProcessStatusInfoBuilder{
+
+    private static final Logger logger = LoggingUtils.getLogger(LinuxProcessStatusInfoBuilderImpl.class);
+
+    private final ProcDataSource dataSource;
+
+    public LinuxProcessStatusInfoBuilderImpl(ProcDataSource dataSource) {
+        this.dataSource = dataSource;
+    }
+
+    public ProcessStatusInfo build(int pid) {
+        try (BufferedReader reader = new BufferedReader(dataSource.getStatReader(pid))) {
+            return build(reader);
+        } catch (IOException e) {
+            logger.log(Level.FINE, "Unable to read stat info for: " + pid);
+        }
+
+        return null;
+    }
+
+    private ProcessStatusInfo build(Reader r) throws IOException {
+
+        int pid = -1;
+        long utime = -1;
+        long stime = -1;
+
+        Scanner scanner = null;
+
+        /* TODO map these (effectively c) data types to java types more sanely */
+
+        try (BufferedReader reader = new BufferedReader(r)) {
+            String statusLine = reader.readLine();
+
+            /* be prepared for process names like '1 ) 2 3 4 foo 5' */
+
+            scanner = new Scanner(statusLine);
+            pid = scanner.nextInt();
+            scanner.close();
+
+            int execEndNamePos = statusLine.lastIndexOf(')');
+
+            String cleanStatusLine = statusLine.substring(execEndNamePos + 1);
+
+            scanner = new Scanner(cleanStatusLine);
+            /* state = */scanner.next();
+            /* ppid = */scanner.nextInt();
+            /* pgrp = */scanner.nextInt();
+            /* session = */scanner.nextInt();
+            /* tty_nr = */scanner.nextInt();
+            /* tpgid = */scanner.nextInt();
+            /* flags = */scanner.nextInt();
+            /* minflt = */scanner.nextLong();
+            /* cminflt = */scanner.nextLong();
+            /* majflt = */scanner.nextLong();
+            /* cmajflt = */scanner.nextLong();
+            utime = scanner.nextLong();
+            stime = scanner.nextLong();
+            scanner.close();
+        }
+
+        return new ProcessStatusInfo(pid, utime, stime);
+
+    }
+
+}
+
--- a/vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/ProcessStatusInfoBuilder.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/ProcessStatusInfoBuilder.java	Thu Dec 08 10:23:22 2016 -0500
@@ -36,85 +36,14 @@
 
 package com.redhat.thermostat.vm.cpu.agent.internal;
 
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.Reader;
-import java.util.Scanner;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.redhat.thermostat.agent.utils.ProcDataSource;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-
 /**
  * Extract status information about the process from /proc/. This is what tools
  * like {@code ps} and {@code top} use.
  *
  * @see {@code proc(5)}
  */
-public class ProcessStatusInfoBuilder {
-
-    private static final Logger logger = LoggingUtils.getLogger(ProcessStatusInfoBuilder.class);
-
-    private final ProcDataSource dataSource;
-
-    public ProcessStatusInfoBuilder(ProcDataSource dataSource) {
-        this.dataSource = dataSource;
-    }
-
-    public ProcessStatusInfo build(int pid) {
-        try (BufferedReader reader = new BufferedReader(dataSource.getStatReader(pid))) {
-            return build(reader);
-        } catch (IOException e) {
-            logger.log(Level.FINE, "Unable to read stat info for: " + pid);
-        }
-
-        return null;
-    }
-
-    private ProcessStatusInfo build(Reader r) throws IOException {
-
-        int pid = -1;
-        long utime = -1;
-        long stime = -1;
-
-        Scanner scanner = null;
-
-        /* TODO map these (effectively c) data types to java types more sanely */
+public interface ProcessStatusInfoBuilder {
 
-        try (BufferedReader reader = new BufferedReader(r)) {
-            String statusLine = reader.readLine();
-
-            /* be prepared for process names like '1 ) 2 3 4 foo 5' */
-
-            scanner = new Scanner(statusLine);
-            pid = scanner.nextInt();
-            scanner.close();
-
-            int execEndNamePos = statusLine.lastIndexOf(')');
-
-            String cleanStatusLine = statusLine.substring(execEndNamePos + 1);
-
-            scanner = new Scanner(cleanStatusLine);
-            /* state = */scanner.next();
-            /* ppid = */scanner.nextInt();
-            /* pgrp = */scanner.nextInt();
-            /* session = */scanner.nextInt();
-            /* tty_nr = */scanner.nextInt();
-            /* tpgid = */scanner.nextInt();
-            /* flags = */scanner.nextInt();
-            /* minflt = */scanner.nextLong();
-            /* cminflt = */scanner.nextLong();
-            /* majflt = */scanner.nextLong();
-            /* cmajflt = */scanner.nextLong();
-            utime = scanner.nextLong();
-            stime = scanner.nextLong();
-            scanner.close();
-        }
-
-        return new ProcessStatusInfo(pid, utime, stime);
-
-    }
-
+    ProcessStatusInfo build(int pid);
 }
 
--- a/vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/VmCpuBackend.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/VmCpuBackend.java	Thu Dec 08 10:23:22 2016 -0500
@@ -43,14 +43,16 @@
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
-import com.redhat.thermostat.agent.utils.ProcDataSource;
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
 import com.redhat.thermostat.agent.utils.SysConf;
+import com.redhat.thermostat.agent.utils.windows.WindowsHelperImpl;
 import com.redhat.thermostat.backend.VmPollingAction;
 import com.redhat.thermostat.backend.VmPollingBackend;
 import com.redhat.thermostat.common.Clock;
 import com.redhat.thermostat.common.SystemClock;
 import com.redhat.thermostat.common.Version;
 import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.shared.config.OS;
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO;
 import com.redhat.thermostat.vm.cpu.common.model.VmCpuStat;
@@ -87,9 +89,12 @@
             long ticksPerSecond = SysConf.getClockTicksPerSecond();
             ProcDataSource source = new ProcDataSource();
             int numCpus = getCpuCount(source);
-            ProcessStatusInfoBuilder PSIBuilder = new ProcessStatusInfoBuilder(source);
+            ProcessStatusInfoBuilder PSIBuilder = OS.IS_LINUX ? new LinuxProcessStatusInfoBuilderImpl(source) : new WindowsProcessStatusInfoBuilderImpl();
             builder = new VmCpuStatBuilder(clock, numCpus, ticksPerSecond, PSIBuilder, id);
             this.dao = dao;
+            if (OS.IS_WINDOWS) {
+                LOGGER.log(Level.WARNING, "VmCpu backend is not yet ported to Windows");
+            }
         }
 
         @Override
@@ -105,6 +110,14 @@
         }
 
         private int getCpuCount(ProcDataSource dataSource) {
+            return OS.IS_WINDOWS ? getWindowsCpuCount() : getLinuxCpuCount(dataSource);
+        }
+
+        private int getWindowsCpuCount() {
+            return WindowsHelperImpl.INSTANCE.getCPUCount();
+        }
+
+        private int getLinuxCpuCount(ProcDataSource dataSource) {
             final String KEY_PROCESSOR_ID = "processor";
             int cpuCount = 0;
             try (BufferedReader bufferedReader = new BufferedReader(dataSource.getCpuInfoReader())) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/WindowsProcessStatusInfoBuilderImpl.java	Thu Dec 08 10:23:22 2016 -0500
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2012-2016 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.vm.cpu.agent.internal;
+
+import com.redhat.thermostat.agent.utils.windows.WindowsHelperImpl;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+
+import java.util.logging.Logger;
+
+/**
+ * Extract status information about the process
+ */
+public class WindowsProcessStatusInfoBuilderImpl implements ProcessStatusInfoBuilder {
+
+    //private static final Logger logger = LoggingUtils.getLogger(WindowsProcessStatusInfoBuilderImpl.class);
+
+    WindowsProcessStatusInfoBuilderImpl() {
+    }
+
+    public ProcessStatusInfo build(int pid) {
+
+        final long[] info =  WindowsHelperImpl.INSTANCE.getProcessCPUInfo(pid);
+
+        final long utime = info[1];
+        final long stime = info[2];
+
+        return new ProcessStatusInfo(pid, utime, stime);
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-cpu/agent/src/test/java/com/redhat/thermostat/vm/cpu/agent/internal/LinuxProcessStatusInfoBuilderTest.java	Thu Dec 08 10:23:22 2016 -0500
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2012-2016 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.vm.cpu.agent.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.io.StringReader;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
+
+public class LinuxProcessStatusInfoBuilderTest {
+
+    @Test
+    public void testSimpleProcessStatus() {
+        ProcDataSource dataSource = new ProcDataSource();
+        ProcessStatusInfo stat = new LinuxProcessStatusInfoBuilderImpl(dataSource).build(1);
+        assertNotNull(stat);
+    }
+
+    @Test
+    public void testKnownProcessStatus() throws IOException {
+        final int PID = 10363;
+        String PROCESS_NAME = "(bash)";
+        String STATE = "S";
+        String PPID = "1737";
+        String PROCESS_GROUP_ID = "10363";
+        String SESSION_ID = "10363";
+        String TTY_NUMBER = "34817";
+        String TTY_PROCESS_GROUP_ID = "11404";
+        String FLAGS_WORD = "4202496";
+        String MINOR_FAULTS = "8093";
+        String MINOR_FAULTS_CHILDREN = "607263";
+        String MAJOR_FAULTS = "1";
+        String MAJOR_FAULTS_CHILDREN = "251";
+        final long USER_TIME_TICKS = 21;
+        final long KERNEL_TIME_TICKS = 7;
+        final long USER_TIME_CHILDREN = 10;
+        String KERNEL_TIME_CHILDREN = "1000";
+        String PRIORITY = "20";
+        String statString = "" +
+                PID + " " + PROCESS_NAME + " " + STATE + " " + PPID + " "
+                + PROCESS_GROUP_ID + " " + SESSION_ID + " " + TTY_NUMBER + " "
+                + TTY_PROCESS_GROUP_ID + " " + FLAGS_WORD + " " + MINOR_FAULTS + " "
+                + MINOR_FAULTS_CHILDREN + " " + MAJOR_FAULTS + " " + MAJOR_FAULTS_CHILDREN + " " +
+                USER_TIME_TICKS + " " + KERNEL_TIME_TICKS + " " + USER_TIME_CHILDREN + " " +
+                KERNEL_TIME_CHILDREN + " " + PRIORITY;
+
+        ProcDataSource dataSource = mock(ProcDataSource.class);
+        when(dataSource.getStatReader(any(Integer.class))).thenReturn(new StringReader(statString));
+        ProcessStatusInfoBuilder builder = new LinuxProcessStatusInfoBuilderImpl(dataSource);
+        ProcessStatusInfo stat = builder.build(PID);
+
+        verify(dataSource).getStatReader(PID);
+        assertNotNull(stat);
+        assertEquals(PID, stat.getPid());
+        assertEquals(USER_TIME_TICKS, stat.getUserTime());
+        assertEquals(KERNEL_TIME_TICKS, stat.getKernelTime());
+    }
+
+    @Test
+    public void testBadProcessName() throws IOException {
+        final int PID = 10363;
+        String PROCESS_NAME = "(secretly-bad process sleep 10 20 ) 6)";
+        String STATE = "S";
+        String PPID = "1737";
+        String PROCESS_GROUP_ID = "10363";
+        String SESSION_ID = "10363";
+        String TTY_NUMBER = "34817";
+        String TTY_PROCESS_GROUP_ID = "11404";
+        String FLAGS_WORD = "4202496";
+        String MINOR_FAULTS = "8093";
+        String MINOR_FAULTS_CHILDREN = "607263";
+        String MAJOR_FAULTS = "1";
+        String MAJOR_FAULTS_CHILDREN = "251";
+        final long USER_TIME_TICKS = 21;
+        final long KERNEL_TIME_TICKS = 7;
+        final long USER_TIME_CHILDREN = 10;
+        String KERNEL_TIME_CHILDREN = "1000";
+        String PRIORITY = "20";
+        String statString = "" +
+                PID + " " + PROCESS_NAME + " " + STATE + " " + PPID + " "
+                + PROCESS_GROUP_ID + " " + SESSION_ID + " " + TTY_NUMBER + " "
+                + TTY_PROCESS_GROUP_ID + " " + FLAGS_WORD + " " + MINOR_FAULTS + " "
+                + MINOR_FAULTS_CHILDREN + " " + MAJOR_FAULTS + " " + MAJOR_FAULTS_CHILDREN + " " +
+                USER_TIME_TICKS + " " + KERNEL_TIME_TICKS + " " + USER_TIME_CHILDREN + " " +
+                KERNEL_TIME_CHILDREN + " " + PRIORITY;
+
+        ProcDataSource dataSource = mock(ProcDataSource.class);
+        when(dataSource.getStatReader(any(Integer.class))).thenReturn(new StringReader(statString));
+        ProcessStatusInfoBuilder builder = new LinuxProcessStatusInfoBuilderImpl(dataSource);
+        ProcessStatusInfo stat = builder.build(PID);
+
+        verify(dataSource).getStatReader(PID);
+        assertNotNull(stat);
+        assertEquals(PID, stat.getPid());
+        assertEquals(USER_TIME_TICKS, stat.getUserTime());
+        assertEquals(KERNEL_TIME_TICKS, stat.getKernelTime());
+    }
+
+}
+
--- a/vm-cpu/agent/src/test/java/com/redhat/thermostat/vm/cpu/agent/internal/ProcessStatusInfoBuilderTest.java	Wed Dec 07 10:55:51 2016 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,145 +0,0 @@
-/*
- * Copyright 2012-2016 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.vm.cpu.agent.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.io.IOException;
-import java.io.StringReader;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.agent.utils.ProcDataSource;
-import com.redhat.thermostat.vm.cpu.agent.internal.ProcessStatusInfo;
-import com.redhat.thermostat.vm.cpu.agent.internal.ProcessStatusInfoBuilder;
-
-public class ProcessStatusInfoBuilderTest {
-
-    @Test
-    public void testSimpleProcessStatus() {
-        ProcDataSource dataSource = new ProcDataSource();
-        ProcessStatusInfo stat = new ProcessStatusInfoBuilder(dataSource).build(1);
-        assertNotNull(stat);
-    }
-
-    @Test
-    public void testKnownProcessStatus() throws IOException {
-        final int PID = 10363;
-        String PROCESS_NAME = "(bash)";
-        String STATE = "S";
-        String PPID = "1737";
-        String PROCESS_GROUP_ID = "10363";
-        String SESSION_ID = "10363";
-        String TTY_NUMBER = "34817";
-        String TTY_PROCESS_GROUP_ID = "11404";
-        String FLAGS_WORD = "4202496";
-        String MINOR_FAULTS = "8093";
-        String MINOR_FAULTS_CHILDREN = "607263";
-        String MAJOR_FAULTS = "1";
-        String MAJOR_FAULTS_CHILDREN = "251";
-        final long USER_TIME_TICKS = 21;
-        final long KERNEL_TIME_TICKS = 7;
-        final long USER_TIME_CHILDREN = 10;
-        String KERNEL_TIME_CHILDREN = "1000";
-        String PRIORITY = "20";
-        String statString = "" +
-                PID + " " + PROCESS_NAME + " " + STATE + " " + PPID + " "
-                + PROCESS_GROUP_ID + " " + SESSION_ID + " " + TTY_NUMBER + " "
-                + TTY_PROCESS_GROUP_ID + " " + FLAGS_WORD + " " + MINOR_FAULTS + " "
-                + MINOR_FAULTS_CHILDREN + " " + MAJOR_FAULTS + " " + MAJOR_FAULTS_CHILDREN + " " +
-                USER_TIME_TICKS + " " + KERNEL_TIME_TICKS + " " + USER_TIME_CHILDREN + " " +
-                KERNEL_TIME_CHILDREN + " " + PRIORITY;
-
-        ProcDataSource dataSource = mock(ProcDataSource.class);
-        when(dataSource.getStatReader(any(Integer.class))).thenReturn(new StringReader(statString));
-        ProcessStatusInfoBuilder builder = new ProcessStatusInfoBuilder(dataSource);
-        ProcessStatusInfo stat = builder.build(PID);
-
-        verify(dataSource).getStatReader(PID);
-        assertNotNull(stat);
-        assertEquals(PID, stat.getPid());
-        assertEquals(USER_TIME_TICKS, stat.getUserTime());
-        assertEquals(KERNEL_TIME_TICKS, stat.getKernelTime());
-    }
-
-    @Test
-    public void testBadProcessName() throws IOException {
-        final int PID = 10363;
-        String PROCESS_NAME = "(secretly-bad process sleep 10 20 ) 6)";
-        String STATE = "S";
-        String PPID = "1737";
-        String PROCESS_GROUP_ID = "10363";
-        String SESSION_ID = "10363";
-        String TTY_NUMBER = "34817";
-        String TTY_PROCESS_GROUP_ID = "11404";
-        String FLAGS_WORD = "4202496";
-        String MINOR_FAULTS = "8093";
-        String MINOR_FAULTS_CHILDREN = "607263";
-        String MAJOR_FAULTS = "1";
-        String MAJOR_FAULTS_CHILDREN = "251";
-        final long USER_TIME_TICKS = 21;
-        final long KERNEL_TIME_TICKS = 7;
-        final long USER_TIME_CHILDREN = 10;
-        String KERNEL_TIME_CHILDREN = "1000";
-        String PRIORITY = "20";
-        String statString = "" +
-                PID + " " + PROCESS_NAME + " " + STATE + " " + PPID + " "
-                + PROCESS_GROUP_ID + " " + SESSION_ID + " " + TTY_NUMBER + " "
-                + TTY_PROCESS_GROUP_ID + " " + FLAGS_WORD + " " + MINOR_FAULTS + " "
-                + MINOR_FAULTS_CHILDREN + " " + MAJOR_FAULTS + " " + MAJOR_FAULTS_CHILDREN + " " +
-                USER_TIME_TICKS + " " + KERNEL_TIME_TICKS + " " + USER_TIME_CHILDREN + " " +
-                KERNEL_TIME_CHILDREN + " " + PRIORITY;
-
-        ProcDataSource dataSource = mock(ProcDataSource.class);
-        when(dataSource.getStatReader(any(Integer.class))).thenReturn(new StringReader(statString));
-        ProcessStatusInfoBuilder builder = new ProcessStatusInfoBuilder(dataSource);
-        ProcessStatusInfo stat = builder.build(PID);
-
-        verify(dataSource).getStatReader(PID);
-        assertNotNull(stat);
-        assertEquals(PID, stat.getPid());
-        assertEquals(USER_TIME_TICKS, stat.getUserTime());
-        assertEquals(KERNEL_TIME_TICKS, stat.getKernelTime());
-    }
-
-}
-
--- a/vm-io/agent/src/main/java/com/redhat/thermostat/vm/io/agent/internal/ProcIoDataReader.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/vm-io/agent/src/main/java/com/redhat/thermostat/vm/io/agent/internal/ProcIoDataReader.java	Thu Dec 08 10:23:22 2016 -0500
@@ -41,7 +41,7 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import com.redhat.thermostat.agent.utils.ProcDataSource;
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 
 /**
--- a/vm-io/agent/src/main/java/com/redhat/thermostat/vm/io/agent/internal/VmIoBackend.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/vm-io/agent/src/main/java/com/redhat/thermostat/vm/io/agent/internal/VmIoBackend.java	Thu Dec 08 10:23:22 2016 -0500
@@ -37,7 +37,7 @@
 package com.redhat.thermostat.vm.io.agent.internal;
 
 import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
-import com.redhat.thermostat.agent.utils.ProcDataSource;
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
 import com.redhat.thermostat.backend.VmListenerBackend;
 import com.redhat.thermostat.backend.VmUpdate;
 import com.redhat.thermostat.backend.VmUpdateListener;
--- a/vm-io/agent/src/test/java/com/redhat/thermostat/vm/io/agent/internal/ProcIoDataReaderTest.java	Wed Dec 07 10:55:51 2016 -0500
+++ b/vm-io/agent/src/test/java/com/redhat/thermostat/vm/io/agent/internal/ProcIoDataReaderTest.java	Thu Dec 08 10:23:22 2016 -0500
@@ -44,7 +44,7 @@
 
 import org.junit.Test;
 
-import com.redhat.thermostat.agent.utils.ProcDataSource;
+import com.redhat.thermostat.agent.utils.linux.ProcDataSource;
 
 public class ProcIoDataReaderTest {