changeset 2462:965485a1d071

Changes for basic windows (cygwin+mingw64) build This build can run "thermostat setup" under Cygwin, but not much more. Unit tests do not run and there is no provision for running without Cygwin (No thermostat Windows *.cmd files have been written) The environment is cygwin64 + mingw64 (installed via cygwin) and Windows 10.
author Simon Tooke <stooke@redhat.com>
date Wed, 21 Sep 2016 11:41:25 -0400
parents 3b9a85bfeff8
children efcb03b5a923
files agent/core/Makefile agent/core/pom.xml agent/core/src/main/native/HostName.c agent/core/src/main/native/UserNameUtilImpl.c annotations/src/main/java/com/redhat/thermostat/annotations/internal/AnnotationProcessor.java common/core/src/main/java/com/redhat/thermostat/common/internal/test/TestCommandContextFactory.java distribution/assembly/core-assembly-windows.xml distribution/config/thermostatrc distribution/pom.xml distribution/scripts/thermostat distribution/scripts/thermostat-agent-proxy distribution/scripts/thermostat-command-channel distribution/scripts/thermostat-common distribution/scripts/thermostat-webservice distribution/tools/verify-bash-completion.cmd distribution/tools/verify-bash-completion.sh laf-utils/Makefile laf-utils/pom.xml launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParser.java pom.xml setup/command/src/main/java/com/redhat/thermostat/setup/command/internal/model/CredentialsFileCreator.java storage/cli/src/main/java/com/redhat/thermostat/storage/cli/internal/MongoOSUtilFactory.java storage/cli/src/main/java/com/redhat/thermostat/storage/cli/internal/MongoOSUtilInterface.java storage/cli/src/main/java/com/redhat/thermostat/storage/cli/internal/MongoProcessRunner.java storage/cli/src/main/java/com/redhat/thermostat/storage/cli/internal/MongoUnixUtil.java storage/cli/src/main/java/com/redhat/thermostat/storage/cli/internal/MongoWindowsUtil.java storage/cli/src/test/java/com/redhat/thermostat/storage/cli/internal/MongoOSUtilFactoryTest.java storage/cli/src/test/java/com/redhat/thermostat/storage/cli/internal/MongoProcessRunnerTest.java storage/cli/src/test/java/com/redhat/thermostat/storage/cli/internal/MongoUnixUtilTest.java storage/cli/src/test/java/com/redhat/thermostat/storage/cli/internal/MongoWindowsUtilTest.java storage/core/src/main/java/com/redhat/thermostat/storage/config/FileStorageCredentials.java storage/core/src/test/java/com/redhat/thermostat/storage/config/FileStorageCredentialsTest.java unix-process-handler/src/main/java/com/redhat/thermostat/service/internal/UnixProcessUtilities.java unix-process-handler/src/test/java/com/redhat/thermostat/service/internal/UnixProcessUtilitiesTest.java web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/JettyContainerLauncher.java
diffstat 35 files changed, 1140 insertions(+), 187 deletions(-) [+]
line wrap: on
line diff
--- a/agent/core/Makefile	Tue Sep 20 13:57:38 2016 -0400
+++ b/agent/core/Makefile	Wed Sep 21 11:41:25 2016 -0400
@@ -1,24 +1,25 @@
 CC         = gcc
 JAVAH      = javah
-MYCFLAGS   = -c -Wall -fPIC
-MYLDFLAGS  = -fPIC -shared
+MYCFLAGS   = -c -Wall -fPIC $(EXTRA_CFLAGS)
+MYLDFLAGS  = -fPIC -shared $(EXTRA_CFLAGS)
 COPY       = cp -a
 
 CLASSPATH  = target/classes/
 TARGET_DIR = target
+SO_PREFIX  = lib
+SO_SUFFIX  = .so
 
-INCLUDE    = -I $(TARGET_DIR) -I $(JAVA_HOME)/include/ -I $(JAVA_HOME)/include/linux
+INCLUDE    = -I $(TARGET_DIR) -I "$(JAVA_HOME)/include/" -I "$(JAVA_HOME)/include/$(JNI_PLATFORM)"
+
 HOSTNAME_SOURCES    = src/main/native/HostName.c
 HOSTNAME_TARGET     = $(TARGET_DIR)/HostName.c
 HOSTNAME_OBJECTS    = $(HOSTNAME_TARGET:.c=.o)
-
-HOSTNAME_EXECUTABLE = libHostNameWrapper.so
+HOSTNAME_EXECUTABLE = $(SO_PREFIX)HostNameWrapper$(SO_SUFFIX)
 
 USERNAME_SOURCES    = src/main/native/UserNameUtilImpl.c
 USERNAME_TARGET     = $(TARGET_DIR)/UserNameUtilImpl.c
 USERNAME_OBJECTS    = $(USERNAME_TARGET:.c=.o)
-
-USERNAME_EXECUTABLE = libUserNameUtilWrapper.so
+USERNAME_EXECUTABLE = $(SO_PREFIX)UserNameUtilWrapper$(SO_SUFFIX)
 
 .PHONY:
 JNI_LIST = com.redhat.thermostat.agent.utils.hostname.HostName\
@@ -27,7 +28,8 @@
 $(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) $(HOSTNAME_EXECUTABLE) \
+  $(USERNAME_SOURCES) $(USERNAME_EXECUTABLE)
 
 .PHONY:
 init:
@@ -35,10 +37,10 @@
 	$(COPY) $(USERNAME_SOURCES) $(USERNAME_TARGET)
 
 $(HOSTNAME_EXECUTABLE): $(HOSTNAME_OBJECTS)
-	$(CC) $(HOSTNAME_OBJECTS) -o $(TARGET_DIR)/$@ $(MYLDFLAGS) $(LDFLAGS)
+	$(CC) $(HOSTNAME_OBJECTS) -o $(TARGET_DIR)/$@ $(MYLDFLAGS) $(LDFLAGS) $(PLATFORM_LIBS)
 	
 $(USERNAME_EXECUTABLE): $(USERNAME_OBJECTS)
-	$(CC) $(USERNAME_OBJECTS) -o $(TARGET_DIR)/$@ $(MYLDFLAGS) $(LDFLAGS)
+	$(CC) $(USERNAME_OBJECTS) -o $(TARGET_DIR)/$@ $(MYLDFLAGS) $(LDFLAGS) $(PLATFORM_LIBS)
 
 .c.o:
 	$(CC) $(MYCFLAGS) $(CFLAGS) $(INCLUDE) $< -o $@
--- a/agent/core/pom.xml	Tue Sep 20 13:57:38 2016 -0400
+++ b/agent/core/pom.xml	Wed Sep 21 11:41:25 2016 -0400
@@ -50,6 +50,37 @@
 
   <name>Thermostat Agent Core</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></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.prefix>
+        <sharedlib.suffix>.dll</sharedlib.suffix>
+      </properties>
+    </profile>
+  </profiles>
+
   <dependencies>
     <dependency>
       <groupId>junit</groupId>
@@ -159,6 +190,12 @@
           <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>
           <systemProperties>
             <systemProperty>
--- a/agent/core/src/main/native/HostName.c	Tue Sep 20 13:57:38 2016 -0400
+++ b/agent/core/src/main/native/HostName.c	Wed Sep 21 11:41:25 2016 -0400
@@ -40,7 +40,11 @@
 #include <unistd.h>
 #include <string.h>
 
-#include <netdb.h>
+#if !defined(_WIN32)
+# include <netdb.h>
+#else // windows
+# include <winsock2.h>
+#endif
 
 #ifndef NI_MAXHOST
 #define NI_MAXHOST 1025
--- a/agent/core/src/main/native/UserNameUtilImpl.c	Tue Sep 20 13:57:38 2016 -0400
+++ b/agent/core/src/main/native/UserNameUtilImpl.c	Wed Sep 21 11:41:25 2016 -0400
@@ -37,12 +37,16 @@
 #include "com_redhat_thermostat_utils_username_internal_UserNameUtilImpl.h"
 
 #include <jni.h>
-#include <pwd.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
 
+#if !defined(_WIN32)
+# include <pwd.h>
+#else // windows
+#endif
+
 static jint throw_IOException(JNIEnv *env, const char *message) {
     const char *class_name = "java/io/IOException";
     jclass class = (*env)->FindClass(env, class_name);
@@ -52,6 +56,8 @@
     return (*env)->ThrowNew(env, class, message);
 }
 
+#if !defined(_WIN32)
+
 JNIEXPORT jstring JNICALL
 Java_com_redhat_thermostat_utils_username_internal_UserNameUtilImpl_getUserName0
     (JNIEnv *env, jclass ProcessUserInfoBuilderClass, jlong uid) {
@@ -91,3 +97,16 @@
     return name;
 }
 
+#else // Windows
+JNIEXPORT jstring JNICALL
+Java_com_redhat_thermostat_utils_username_internal_UserNameUtilImpl_getUserName0
+    (JNIEnv *env, jclass ProcessUserInfoBuilderClass, jlong uid) {
+
+    // TODO
+    throw_IOException(env, "UserNameUtilImpl.getUserName() no yet implemented on Windows");
+    jstring name = (*env)->NewStringUTF(env, "xxxuserxxx");
+    return name;
+}
+#endif
+
+
--- a/annotations/src/main/java/com/redhat/thermostat/annotations/internal/AnnotationProcessor.java	Tue Sep 20 13:57:38 2016 -0400
+++ b/annotations/src/main/java/com/redhat/thermostat/annotations/internal/AnnotationProcessor.java	Wed Sep 21 11:41:25 2016 -0400
@@ -109,7 +109,7 @@
             try {
                 FileObject filer = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT,
                         "",
-                        "META-INF" + File.separator + "thermostat" + File.separator + "plugin-docs.xml",
+                        "META-INF" + "/" + "thermostat" + "/" + "plugin-docs.xml",
                         sourceElements);
                 try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(filer.openOutputStream(), "UTF-8"))) {
                     writeXml(writer, points);
--- a/common/core/src/main/java/com/redhat/thermostat/common/internal/test/TestCommandContextFactory.java	Tue Sep 20 13:57:38 2016 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/internal/test/TestCommandContextFactory.java	Wed Sep 21 11:41:25 2016 -0400
@@ -134,7 +134,8 @@
         } catch (IOException e) {
             // ignore
         }
-        return new String(out.toByteArray(), consoleEncoding);
+        // get rid of <CR> in case we're on Windows
+        return new String(out.toByteArray(), consoleEncoding).replace("\r","");
     }
 
     /**
@@ -152,8 +153,9 @@
         }
     }
 
+    // get rid of <CR> in case we're on Windows
     public String getError() {
-        return new String(err.toByteArray(), consoleEncoding);
+        return new String(err.toByteArray(), consoleEncoding).replace("\r","");
     }
 
     public void reset() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/distribution/assembly/core-assembly-windows.xml	Wed Sep 21 11:41:25 2016 -0400
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+  <id>core-assembly</id>
+  <formats>
+    <format>dir</format>
+  </formats>
+  <includeBaseDirectory>false</includeBaseDirectory>
+
+  <dependencySets>
+    <dependencySet>
+      <useProjectArtifact>true</useProjectArtifact>
+      <unpack>false</unpack>
+      <includes>
+        <include>com.redhat.thermostat:thermostat-main</include>
+        <include>com.redhat.thermostat:thermostat-launcher</include>
+        <include>com.redhat.thermostat:thermostat-client-swing</include>
+        <include>com.redhat.thermostat:thermostat-swing-components</include>
+        <include>com.redhat.thermostat:thermostat-client-command</include>
+        <include>com.redhat.thermostat:thermostat-client-cli</include>
+        <include>com.redhat.thermostat:thermostat-osgi-living-vm-filter-swing</include>
+        <include>com.redhat.thermostat:thermostat-agent-core</include>
+        <include>com.redhat.thermostat:thermostat-agent-cli</include>
+        <include>com.redhat.thermostat:thermostat-agent-command</include>
+        <include>com.redhat.thermostat:thermostat-agent-command-server</include>
+        <include>com.redhat.thermostat:thermostat-agent-proxy-server</include>
+        <include>com.redhat.thermostat:thermostat-agent-ipc-unixsocket-server</include>
+        <include>com.redhat.thermostat:thermostat-agent-ipc-unixsocket-client</include>
+        <!--include>com.redhat.thermostat:thermostat-agent-ipc-tcpsocket-server</include>
+        <include>com.redhat.thermostat:thermostat-agent-ipc-tcpsocket-client</include-->
+        <include>com.redhat.thermostat:thermostat-common-core</include>
+        <include>com.redhat.thermostat:thermostat-common-command</include>
+        <include>com.redhat.thermostat:thermostat-osgi-process-handler</include>
+        <include>com.redhat.thermostat:thermostat-storage-cli</include>
+        <include>com.redhat.thermostat:thermostat-storage-mongodb</include>
+        <!--include>com.redhat.thermostat:thermostat-keyring</include-->
+        <include>com.redhat.thermostat:thermostat-web-client</include>
+        <include>com.redhat.thermostat:thermostat-system-backend</include>
+        <include>com.redhat.thermostat:thermostat-laf-utils</include>
+        <include>org.osgi:org.osgi.compendium</include>
+        <include>org.apache:org.apache.felix.scr</include>
+        <!-- Remove once upstream has OSGi metadata -->
+        <include>com.redhat.thermostat:jnr-x86asm</include>
+      </includes>
+      <excludes>
+        <exclude>org.osgi:org.osgi.core</exclude>
+        <!-- Exclude upstream jnr-x86asm jar in favour of our wrapped bundle -->
+        <exclude>com.github.jnr:jnr-x86asm</exclude>
+      </excludes>
+      <useTransitiveDependencies>true</useTransitiveDependencies>
+      <useTransitiveFiltering>true</useTransitiveFiltering>
+    </dependencySet>
+  </dependencySets>
+</assembly>
+
--- a/distribution/config/thermostatrc	Tue Sep 20 13:57:38 2016 -0400
+++ b/distribution/config/thermostatrc	Wed Sep 21 11:41:25 2016 -0400
@@ -48,11 +48,24 @@
 #
 #JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk
 
+if [ "$(expr substr $(uname -s) 1 6)" == "CYGWIN" ]; then
+  ##echo "Running under Cygwin"
+  export CYGWIN_MODE=1
+else
+  ##echo "Running under Linux"
+  export CYGWIN_MODE=0
+fi
+
 #
 # Extra jar files which need to be on the classpath when
 # Thermostat boots.
-# 
-THERMOSTAT_EXT_BOOT_CLASSPATH="${JAVA_HOME}/lib/tools.jar"
+#
+if [ $CYGWIN_MODE -eq 1 ]; then
+  THERMOSTAT_EXT_BOOT_CLASSPATH="`cygpath -u ${JAVA_HOME}/lib/tools.jar`"
+else
+  THERMOSTAT_EXT_BOOT_CLASSPATH="${JAVA_HOME}/lib/tools.jar"
+fi
+
 # FIXME: Remove once jfreechart is a real OSGi bundle upstream
 THERMOSTAT_EXT_BOOT_CLASSPATH="${THERMOSTAT_EXT_BOOT_CLASSPATH}:${THERMOSTAT_HOME}/libs/jfreechart-@jfreechart.version@.jar"
 THERMOSTAT_EXT_BOOT_CLASSPATH="${THERMOSTAT_EXT_BOOT_CLASSPATH}:${THERMOSTAT_HOME}/libs/jcommon-@jcommon.version@.jar"
--- a/distribution/pom.xml	Tue Sep 20 13:57:38 2016 -0400
+++ b/distribution/pom.xml	Wed Sep 21 11:41:25 2016 -0400
@@ -59,6 +59,132 @@
     <main.basedir>${project.basedir}/..</main.basedir>
   </properties>
   
+  <profiles>
+    <profile>
+      <id>default</id>
+      <activation>
+        <activeByDefault>true</activeByDefault>
+      </activation>
+      <properties>
+        <assemblyfile.suffix></assemblyfile.suffix>
+      </properties>
+    </profile>
+
+    <profile>
+      <id>linux</id>
+      <activation>
+        <os><family>Unix</family></os>
+      </activation>
+      <properties>
+        <assemblyfile.suffix></assemblyfile.suffix>
+      </properties>
+      <dependencies>
+        <dependency>
+          <groupId>com.redhat.thermostat</groupId>
+          <artifactId>thermostat-keyring</artifactId>
+          <version>${project.version}</version>
+        </dependency>
+      </dependencies>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-antrun-plugin</artifactId>
+            <executions>
+              <!--linux only files -->
+              <execution>
+                <id>directory-structure-linux</id>
+                <phase>prepare-package</phase>
+                <configuration>
+                  <target>
+                    <copy file="${main.basedir}/keyring/target/libGnomeKeyringWrapper.so"
+                          todir="${project.build.directory}/image/libs/native" />
+                    <copy file="${main.basedir}/agent/core/target/libHostNameWrapper.so"
+                          todir="${project.build.directory}/image/libs/native" />
+                    <copy file="${main.basedir}/agent/core/target/libUserNameUtilWrapper.so"
+                          todir="${project.build.directory}/image/libs/native" />
+                    <copy file="${main.basedir}/laf-utils/target/libGTKThemeUtils.so"
+                          todir="${project.build.directory}/image/libs/native" />
+                  </target>
+                </configuration>
+                <goals>
+                  <goal>run</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>exec-maven-plugin</artifactId>
+            <executions>
+              <execution>
+                <phase>integration-test</phase>
+                <goals>
+                  <goal>exec</goal>
+                </goals>
+              </execution>
+            </executions>
+            <configuration>
+              <executable>${project.basedir}/tools/verify-bash-completion.sh</executable>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+
+    <profile>
+      <id>windows</id>
+      <activation>
+        <os><family>Windows</family></os>
+      </activation>
+      <properties>
+        <assemblyfile.suffix>-windows</assemblyfile.suffix>
+      </properties>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-antrun-plugin</artifactId>
+            <executions>
+              <!-- windows-only files-->
+              <execution>
+                <id>directory-structure-windows</id>
+                <phase>prepare-package</phase>
+                <configuration>
+                  <target>
+                    <!--  copy and rename the native libraries -->
+                    <copy file="${main.basedir}/agent/core/target/HostNameWrapper.dll"
+                          todir="${project.build.directory}/image/libs/native" />
+                    <copy file="${main.basedir}/agent/core/target/UserNameUtilWrapper.dll"
+                          todir="${project.build.directory}/image/libs/native" />
+                  </target>
+                </configuration>
+                <goals>
+                  <goal>run</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>exec-maven-plugin</artifactId>
+            <executions>
+              <execution>
+                <phase>integration-test</phase>
+                <goals>
+                  <goal>exec</goal>
+                </goals>
+              </execution>
+            </executions>
+            <configuration>
+              <executable>${project.basedir}/tools/verify-bash-completion.cmd</executable>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+    
   <build>
     <plugins>
       <!-- skip unit test run-->
@@ -106,7 +232,7 @@
             <id>assemble-core</id>
             <configuration>
               <descriptors>
-                <descriptor>assembly/core-assembly.xml</descriptor>
+                <descriptor>assembly/core-assembly${assemblyfile.suffix}.xml</descriptor>
               </descriptors>
               <finalName>image/libs</finalName>
               <attach>false</attach>
@@ -286,19 +412,10 @@
             </goals>
           </execution>
           <execution>
-            <id>directory-structure</id>
+            <id>directory-structure-common</id>
             <phase>prepare-package</phase>
             <configuration>
               <target>
-                <!--  copy the native libraries -->
-                <copy file="${main.basedir}/keyring/target/libGnomeKeyringWrapper.so"
-                      todir="${project.build.directory}/image/libs/native" />
-                <copy file="${main.basedir}/agent/core/target/libHostNameWrapper.so"
-                      todir="${project.build.directory}/image/libs/native" />
-                <copy file="${main.basedir}/agent/core/target/libUserNameUtilWrapper.so"
-                      todir="${project.build.directory}/image/libs/native" />
-                <copy file="${main.basedir}/laf-utils/target/libGTKThemeUtils.so"
-                      todir="${project.build.directory}/image/libs/native" />
                 <copy file="${main.basedir}/platform/swing/core/target/generated-sources/annotations/template.json"
                       todir="${project.build.directory}/image/etc/plugins.d/platform" />
                 <copy file="${main.basedir}/thermostat-gui/core/target/generated-sources/annotations/gui.json"
@@ -311,22 +428,6 @@
           </execution>
         </executions>
       </plugin>
-      <!-- test bash completions -->
-      <plugin>
-        <groupId>org.codehaus.mojo</groupId>
-        <artifactId>exec-maven-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>integration-test</phase>
-            <goals>
-              <goal>exec</goal>
-            </goals>
-          </execution>
-        </executions>
-        <configuration>
-          <executable>${project.basedir}/tools/verify-bash-completion.sh</executable>
-        </configuration>
-      </plugin>
     </plugins>
   </build>
 
@@ -440,11 +541,6 @@
     </dependency>
     <dependency>
         <groupId>com.redhat.thermostat</groupId>
-        <artifactId>thermostat-keyring</artifactId>
-        <version>${project.version}</version>
-    </dependency>
-    <dependency>
-        <groupId>com.redhat.thermostat</groupId>
         <artifactId>thermostat-laf-utils</artifactId>
         <version>${project.version}</version>
     </dependency>
--- a/distribution/scripts/thermostat	Tue Sep 20 13:57:38 2016 -0400
+++ b/distribution/scripts/thermostat	Wed Sep 21 11:41:25 2016 -0400
@@ -54,7 +54,7 @@
 BOOT_CLASSPATH="${BOOT_CLASSPATH}:${THERMOSTAT_LIBS}/thermostat-shared-config-@project.version@.jar"
 
 # Append extra class path entries coming from the profiles
-if [ ! -z ${THERMOSTAT_EXT_BOOT_CLASSPATH} ]; then
+if [ ! -z "${THERMOSTAT_EXT_BOOT_CLASSPATH}" ]; then
   BOOT_CLASSPATH="${BOOT_CLASSPATH}:${THERMOSTAT_EXT_BOOT_CLASSPATH}"
 fi
 
@@ -96,22 +96,38 @@
     esac
 done
 
+# if running on cygwin, modify THERMOSTAT_HOME and BOOT_CLASSPATH to windows for the JDK
+if [ $CYGWIN_MODE -eq 1 ]; then
+  export THERMOSTAT_HOME="`cygpath -w $THERMOSTAT_HOME`"
+  export USER_THERMOSTAT_HOME="`cygpath -w $USER_THERMOSTAT_HOME`"
+  BOOT_CLASSPATH=$(cygpath -w -p "$BOOT_CLASSPATH")
+  ##env
+  # in a VM, jline can cause 100% CPU usage on Windows without this
+  THERMOSTAT_EXT_JAVA_OPTS="$THERMOSTAT_EXT_JAVA_OPTS -Djline.terminal=jline.UnsupportedTerminal"
+  # in cygwin, the openJDK uses c:\home\user as java.home. which is unhelpful.
+  # pass the cygwin home directory instead
+  THERMOSTAT_EXT_JAVA_OPTS="$THERMOSTAT_EXT_JAVA_OPTS -Duser.home=`cygpath -w $HOME`"
+else
+  export THERMOSTAT_HOME
+  export USER_THERMOSTAT_HOME
+fi
+
 # Finally run thermostat (optionally in the background)
 if [ ${RUN_IN_BG} -eq 1 ]; then
     # The thermostat-agent-sysd script uses this.
     if [ x"${PID_FILE}" = "x" ]; then
         usage 
     else
-        ${JAVA} ${THERMOSTAT_EXT_JAVA_OPTS} ${LOGGING_ARGS} "${JAVA_ARGS[@]}" \
-                -cp ${BOOT_CLASSPATH} \
+        "${JAVA}" ${THERMOSTAT_EXT_JAVA_OPTS} ${LOGGING_ARGS} "${JAVA_ARGS[@]}" \
+                -cp "${BOOT_CLASSPATH}" \
                 ${THERMOSTAT_MAIN} ${THERMOSTAT_EXT_OPTS} "${ARGS[@]}" &
         retval=$?
         echo $! > ${PID_FILE}
         retval=$(( ${retval} + $? ))
     fi
 else
-    ${JAVA} ${THERMOSTAT_EXT_JAVA_OPTS} ${LOGGING_ARGS} "${JAVA_ARGS[@]}" \
-            -cp ${BOOT_CLASSPATH} \
+    "${JAVA}" ${THERMOSTAT_EXT_JAVA_OPTS} ${LOGGING_ARGS} "${JAVA_ARGS[@]}" \
+            -cp "${BOOT_CLASSPATH}" \
             ${THERMOSTAT_MAIN} ${THERMOSTAT_EXT_OPTS} "${ARGS[@]}"
     retval=$?
 fi
--- a/distribution/scripts/thermostat-agent-proxy	Tue Sep 20 13:57:38 2016 -0400
+++ b/distribution/scripts/thermostat-agent-proxy	Wed Sep 21 11:41:25 2016 -0400
@@ -72,10 +72,20 @@
 fi
 
 # Start server
-CONFIG_FILE_ARG="-DipcConfigFile=${CONFIG_FILE}"
-# Drop permissions, if root
-if [ "$(id -u)" -eq 0 ]; then
-  /bin/su -s /bin/bash -c "${JAVA} -cp ${IPC_CLASSPATH} ${CONFIG_FILE_ARG} ${LOGGING_ARGS} ${DEBUG_OPTS} ${AGENT_PROXY_CLASS} ${TARGET_PID}" "${TARGET_USER}"
+if [ $CYGWIN_MODE -eq 1 ]; then
+  CONFIG_FILE_ARG="-DipcConfigFile=`cygpath -w ${CONFIG_FILE}`"
+  # Drop permissions, if root
+  if [ "$(id -u)" -eq 0 ]; then
+    /bin/su -s /bin/bash -c "${JAVA} -cp `cygpath -w -p ${IPC_CLASSPATH}` ${CONFIG_FILE_ARG} ${LOGGING_ARGS} ${DEBUG_OPTS} ${AGENT_PROXY_CLASS} ${TARGET_PID}" "${TARGET_USER}"
+  else
+    ${JAVA} -cp `cygpath -w -p ${IPC_CLASSPATH}` "${CONFIG_FILE_ARG}" ${DEBUG_OPTS} ${LOGGING_ARGS} ${AGENT_PROXY_CLASS} "${TARGET_PID}"
+  fi
 else
-  ${JAVA} -cp ${IPC_CLASSPATH} "${CONFIG_FILE_ARG}" ${DEBUG_OPTS} ${LOGGING_ARGS} ${AGENT_PROXY_CLASS} "${TARGET_PID}"
+  CONFIG_FILE_ARG="-DipcConfigFile=${CONFIG_FILE}"
+  # Drop permissions, if root
+  if [ "$(id -u)" -eq 0 ]; then
+    /bin/su -s /bin/bash -c "${JAVA} -cp ${IPC_CLASSPATH} ${CONFIG_FILE_ARG} ${LOGGING_ARGS} ${DEBUG_OPTS} ${AGENT_PROXY_CLASS} ${TARGET_PID}" "${TARGET_USER}"
+  else
+    ${JAVA} -cp ${IPC_CLASSPATH} "${CONFIG_FILE_ARG}" ${DEBUG_OPTS} ${LOGGING_ARGS} ${AGENT_PROXY_CLASS} "${TARGET_PID}"
+  fi
 fi
--- a/distribution/scripts/thermostat-command-channel	Tue Sep 20 13:57:38 2016 -0400
+++ b/distribution/scripts/thermostat-command-channel	Wed Sep 21 11:41:25 2016 -0400
@@ -81,10 +81,20 @@
 SCRIPT_OWNER=$(stat -c '%U' "${THIS_SCRIPT}")
 
 # Start server
-CONFIG_FILE_ARG="-DipcConfigFile=${CONFIG_FILE}"
-# Drop permissions, if root
-if [ "$(id -u)" -eq 0 ]; then
-  exec /bin/su -s /bin/bash -c "${JAVA} ${CONFIG_FILE_ARG} ${LOGGING_ARGS} -cp ${IPC_CLASSPATH} ${DEBUG_OPTS} ${CMD_CHANNEL_CLASS} ${HOSTNAME} ${PORT}" "${SCRIPT_OWNER}" 
+if [ $CYGWIN_MODE -eq 1 ]; then
+	CONFIG_FILE_ARG="-DipcConfigFile=`cygpath -w ${CONFIG_FILE}`"
+	# Drop permissions, if root
+	if [ "$(id -u)" -eq 0 ]; then
+	  exec /bin/su -s /bin/bash -c "${JAVA} ${CONFIG_FILE_ARG} ${LOGGING_ARGS} -cp `cygpath -w -p ${IPC_CLASSPATH}` ${DEBUG_OPTS} ${CMD_CHANNEL_CLASS} ${HOSTNAME} ${PORT}" "${SCRIPT_OWNER}" 
+	else
+	  exec ${JAVA} "${CONFIG_FILE_ARG}" ${LOGGING_ARGS} -cp "`cygpath -w -p ${IPC_CLASSPATH}`" ${DEBUG_OPTS} "${CMD_CHANNEL_CLASS}" "${HOSTNAME}" "${PORT}"
+	fi
 else
-  exec ${JAVA} "${CONFIG_FILE_ARG}" ${LOGGING_ARGS} -cp "${IPC_CLASSPATH}" ${DEBUG_OPTS} "${CMD_CHANNEL_CLASS}" "${HOSTNAME}" "${PORT}"
+	CONFIG_FILE_ARG="-DipcConfigFile=${CONFIG_FILE}"
+	# Drop permissions, if root
+	if [ "$(id -u)" -eq 0 ]; then
+	  exec /bin/su -s /bin/bash -c "${JAVA} ${CONFIG_FILE_ARG} ${LOGGING_ARGS} -cp ${IPC_CLASSPATH} ${DEBUG_OPTS} ${CMD_CHANNEL_CLASS} ${HOSTNAME} ${PORT}" "${SCRIPT_OWNER}" 
+	else
+	  exec ${JAVA} "${CONFIG_FILE_ARG}" ${LOGGING_ARGS} -cp ${IPC_CLASSPATH} ${DEBUG_OPTS} "${CMD_CHANNEL_CLASS}" "${HOSTNAME}" "${PORT}"
+	fi
 fi
--- a/distribution/scripts/thermostat-common	Tue Sep 20 13:57:38 2016 -0400
+++ b/distribution/scripts/thermostat-common	Wed Sep 21 11:41:25 2016 -0400
@@ -50,11 +50,29 @@
   echo "$DIR"
 }
 
+# set global variable for Cygwin testing
+# between all shell files, we pass cygwin-compatible paths, 
+#    and let each script decide when to convert them.
+# an exception is command line args for java programs, which
+#    need to be converted to windows format at creation time
+if [ "$(expr substr $(uname -s) 1 6)" == "CYGWIN" ]; then
+  ##echo "Running under Cygwin"
+  export CYGWIN_MODE=1
+else
+  ##echo "Running under Linux"
+  export CYGWIN_MODE=0
+fi
+
 # Thermostat home
 if [[ "${THERMOSTAT_HOME}" = "" ]]; then
   THERMOSTAT_HOME="$(_find_thermostat_home)"
 fi
-export THERMOSTAT_HOME
+
+# on cygwin, convert to Unix format
+if [ $CYGWIN_MODE -eq 1 ]; then
+  THERMOSTAT_HOME="`cygpath -u $THERMOSTAT_HOME`"
+  export THERMOSTAT_HOME
+fi
 
 # Thermostat user home
 if [[ "${USER_THERMOSTAT_HOME}" = "" ]]; then
@@ -69,7 +87,11 @@
 THERMOSTAT_MAIN="com.redhat.thermostat.main.Thermostat"
 
 if [[ "${JAVA_HOME}" = "" ]]; then
-  jdk_home_candidate="@thermostat.jdk.home@"
+  if [[ "${JDK_HOME}" != "" ]]; then
+    jdk_home_candidate="${JDK_HOME}"
+  else
+    jdk_home_candidate="@thermostat.jdk.home@"
+  fi
   if [[ -e "${jdk_home_candidate}/bin/javac" ]]; then
     JAVA_HOME="${jdk_home_candidate}"
   else
@@ -96,14 +118,23 @@
 
 JAVA="${JAVA_HOME}/bin/java"
 
+# on Cygwin, pass the windows path in all Java options
 SYSTEM_LOG_CONFIG_FILE="${THERMOSTAT_HOME}/etc/logging.properties"
 if [ -f "${SYSTEM_LOG_CONFIG_FILE}" ] ; then
-  LOGGING_ARGS="-Djava.util.logging.config.file=${SYSTEM_LOG_CONFIG_FILE}"
+  if [ $CYGWIN_MODE -eq 1 ]; then
+    LOGGING_ARGS="-Djava.util.logging.config.file=`cygpath -w ${SYSTEM_LOG_CONFIG_FILE}`"
+  else
+    LOGGING_ARGS="-Djava.util.logging.config.file=${SYSTEM_LOG_CONFIG_FILE}"
+  fi
 fi
 
 USER_LOG_CONFIG_FILE="${USER_THERMOSTAT_HOME}/etc/logging.properties"
 if [ -f "${USER_LOG_CONFIG_FILE}" ] ; then
-  LOGGING_ARGS="-Djava.util.logging.config.file=${USER_LOG_CONFIG_FILE}"
+  if [ $CYGWIN_MODE -eq 1 ]; then
+    LOGGING_ARGS="-Djava.util.logging.config.file=`cygpath -w ${USER_LOG_CONFIG_FILE}`"
+  else
+    LOGGING_ARGS="-Djava.util.logging.config.file=${USER_LOG_CONFIG_FILE}"
+  fi
 fi
 
 LOGGING_ARGS="${LOGGING_ARGS} -Djline.log.jul=true"
--- a/distribution/scripts/thermostat-webservice	Tue Sep 20 13:57:38 2016 -0400
+++ b/distribution/scripts/thermostat-webservice	Wed Sep 21 11:41:25 2016 -0400
@@ -171,7 +171,11 @@
 do_start() {
   rm -rf webapps/thermostat
   cp -r "$TH/web/war/target/thermostat-web-war-@project.version@" webapps/thermostat
-  JAVA_OPTS="-Djava.security.auth.login.config=${TH}/distribution/target/image/etc/thermostat_jaas.conf" ./bin/startup.sh
+  if [ $CYGWIN_MODE -eq 1 ]; then
+    JAVA_OPTS="-Djava.security.auth.login.config=`cygpath -w ${TH}/distribution/target/image/etc/thermostat_jaas.conf`" ./bin/startup.sh
+  else
+    JAVA_OPTS="-Djava.security.auth.login.config=${TH}/distribution/target/image/etc/thermostat_jaas.conf" ./bin/startup.sh
+  fi
 }
 
 do_stop() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/distribution/tools/verify-bash-completion.cmd	Wed Sep 21 11:41:25 2016 -0400
@@ -0,0 +1,12 @@
+@echo off
+
+set CMD_DIR=%~dp0
+set CYGWIN_DIR=c:\cygwin64
+set PATH=%PATH%;%CYGWIN_DIR%\bin
+
+for /f "delims=" %%a in ('%CYGWIN_DIR%\bin\cygpath -u %CMD_DIR%') do @set CMD_DIR=%%a
+
+%CYGWIN_DIR%\bin\bash -c %CMD_DIR%verify-bash-completion.sh
+
+rem echo XXX ERRR = %errorlevel%
+exit /b %errorlevel%
--- a/distribution/tools/verify-bash-completion.sh	Tue Sep 20 13:57:38 2016 -0400
+++ b/distribution/tools/verify-bash-completion.sh	Wed Sep 21 11:41:25 2016 -0400
@@ -98,6 +98,8 @@
     input=$1
     expected=$2
     expected_pretty=$(echo $expected | __prettify)
+    # clean up (cygwin doesn't seem to delete redirect files if no output)
+    rm -f ${TARGET}/completion.actual
     # save completions and any other output separately and check both
     __find_completion $input >${TARGET}/completion.actual 2>${TARGET}/completion.output
     actual=$(<${TARGET}/completion.actual)
--- a/laf-utils/Makefile	Tue Sep 20 13:57:38 2016 -0400
+++ b/laf-utils/Makefile	Wed Sep 21 11:41:25 2016 -0400
@@ -1,18 +1,20 @@
 CC         = gcc
 JAVAH      = javah
-MYCFLAGS   = -c -Wall -fPIC
-MYLDFLAGS  = -fPIC -shared
+MYCFLAGS   = -c -Wall -fPIC $(EXTRA_CFLAGS)
+MYLDFLAGS  = -fPIC -shared $(EXTRA_CFLAGS)
 COPY       = cp -a
 
 CLASSPATH  = target/classes/
 TARGET_DIR = target
+SO_PREFIX  = lib
+SO_SUFFIX  = .so
 
-INCLUDE    = -I $(TARGET_DIR) -I $(JAVA_HOME)/include/ -I $(JAVA_HOME)/include/linux
+INCLUDE    = -I $(TARGET_DIR) -I "$(JAVA_HOME)/include/" -I "$(JAVA_HOME)/include/$(JNI_PLATFORM)"
 SOURCES    = src/main/native/GTKThemeUtils.c
 TARGET     = $(TARGET_DIR)/GTKThemeUtils.c
 OBJECTS    = $(TARGET:.c=.o)
 
-EXECUTABLE = libGTKThemeUtils.so
+EXECUTABLE = $(SO_PREFIX)GTKThemeUtils$(SO_SUFFIX)
 
 MYCFLAGS   += `pkg-config --cflags gtk+-2.0`
 MYCFLAGS   += `pkg-config gthread-2.0 --cflags`
--- a/laf-utils/pom.xml	Tue Sep 20 13:57:38 2016 -0400
+++ b/laf-utils/pom.xml	Wed Sep 21 11:41:25 2016 -0400
@@ -48,6 +48,51 @@
   <packaging>bundle</packaging>
   <name>Thermostat Look And Feel Utils</name>
 
+  <!-- only build the native code on Linux et. al. -->
+  <profiles>
+    <profile>
+      <id>linux</id>
+      <activation>
+        <os><family>unix</family></os>
+      </activation>
+      <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>
+              <systemProperties>
+                <systemProperty>
+                  <key>JAVA_HOME</key>
+                  <value>${java.home}</value>
+                </systemProperty>
+              </systemProperties>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+
+  </profiles>
+
   <build>
     <plugins>
       <plugin>
@@ -69,31 +114,6 @@
           </instructions>
         </configuration>
       </plugin>
-    
-      <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>
-          </arguments>
-          <systemProperties>
-            <systemProperty>
-              <key>JAVA_HOME</key>
-              <value>${java.home}</value>
-            </systemProperty>
-          </systemProperties>
-        </configuration>
-      </plugin>
      
     </plugins>
     
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParser.java	Tue Sep 20 13:57:38 2016 -0400
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParser.java	Wed Sep 21 11:41:25 2016 -0400
@@ -440,7 +440,7 @@
 
     private String parseDescription(Node descriptionNode) {
         String text = descriptionNode.getTextContent().trim();
-        String[] lines = text.split("(" + System.lineSeparator() + ")+");
+        String[] lines = text.split("(\r\n|\r|\n)+");
         StringBuilder result = new StringBuilder();
         for (String line : lines) {
             result.append(line.trim());
--- a/pom.xml	Tue Sep 20 13:57:38 2016 -0400
+++ b/pom.xml	Wed Sep 21 11:41:25 2016 -0400
@@ -57,6 +57,42 @@
         <license.skip>false</license.skip>
       </properties>
     </profile>
+
+    <profile>
+      <id>linux</id>
+      <activation>
+        <os><family>Unix</family></os>
+      </activation>
+      <properties>
+        <script.extension>.sh</script.extension>
+        <c.compiler>gcc</c.compiler>
+        <cflags></cflags>
+        <jni.platform>linux</jni.platform>
+        <sharedlib.prefix>lib</sharedlib.prefix>
+        <sharedlib.suffix>.so</sharedlib.suffix>
+      </properties>
+      <modules>
+        <module>keyring</module>
+      </modules>
+    </profile>
+
+    <profile>
+      <id>windows</id>
+      <activation>
+        <os><family>Windows</family></os>
+      </activation>
+      <properties>
+        <script.extension>.cmd</script.extension>
+        <c.compiler>x86_64-w64-mingw32-gcc -std=c99</c.compiler>
+        <cflags>-std=c99</cflags>
+        <cygwin.dir>c:/cygwin64</cygwin.dir>
+        <jni.platform>win32</jni.platform>
+        <sharedlib.prefix></sharedlib.prefix>
+        <sharedlib.suffix>.dll</sharedlib.suffix>
+      </properties>
+    </profile>
+
+
     <profile>
       <!-- Some thermostat code uses sun.jvmstat and com.sun.tools.attach.
            These are only available via tools.jar prior to JDK 9 -->
@@ -312,7 +348,6 @@
     <module>agent</module>
     <module>client</module>
     <module>unix-process-handler</module>
-    <module>keyring</module>
     <module>thread</module>
     <module>killvm</module>
     <module>web</module>
--- a/setup/command/src/main/java/com/redhat/thermostat/setup/command/internal/model/CredentialsFileCreator.java	Tue Sep 20 13:57:38 2016 -0400
+++ b/setup/command/src/main/java/com/redhat/thermostat/setup/command/internal/model/CredentialsFileCreator.java	Wed Sep 21 11:41:25 2016 -0400
@@ -45,7 +45,9 @@
 import java.util.Set;
 
 class CredentialsFileCreator {
-    
+
+    private static final boolean IS_UNIX = !System.getProperty("os.name").contains("Windows");
+
     private static final Set<PosixFilePermission> CREDS_FILE_PERMISSIONS = EnumSet.of(
             PosixFilePermission.OWNER_READ,
             PosixFilePermission.OWNER_WRITE
@@ -53,8 +55,15 @@
 
     void create(File file) throws IOException {
         if (!file.exists()) {
-            //create file and set file permissions to 600
-            Files.createFile(file.toPath(), PosixFilePermissions.asFileAttribute(CREDS_FILE_PERMISSIONS));
+            // create file and set file permissions to 600
+            if ( IS_UNIX )
+                Files.createFile(file.toPath(), PosixFilePermissions.asFileAttribute(CREDS_FILE_PERMISSIONS));
+            else {
+                // on windows, credentials may be globally visible.
+                // PosixFilePermissions don't work on windows (throws exception even!)
+                // the code below doesn't enforce this (but should)
+                final boolean success = file.createNewFile() && file.setReadable(true, true) && file.setWritable(true, true);
+            }
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage/cli/src/main/java/com/redhat/thermostat/storage/cli/internal/MongoOSUtilFactory.java	Wed Sep 21 11:41:25 2016 -0400
@@ -0,0 +1,53 @@
+/*
+ * 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.storage.cli.internal;
+
+/**
+ * factory class to create OS-specific implementations of MongoOSUtil
+ */
+class MongoOSUtilFactory {
+
+    private static final boolean IS_UNIX = !System.getProperty("os.name").contains("Windows");
+
+    private static final MongoOSUtilFactory theInstance = new MongoOSUtilFactory();
+
+    static MongoOSUtilFactory instance() { return theInstance; }
+
+    MongoOSUtilInterface createMongoOSUtil() {
+        return IS_UNIX ? new MongoUnixUtil() : new MongoWindowsUtil();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage/cli/src/main/java/com/redhat/thermostat/storage/cli/internal/MongoOSUtilInterface.java	Wed Sep 21 11:41:25 2016 -0400
@@ -0,0 +1,45 @@
+/*
+ * 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.storage.cli.internal;
+
+/**
+ * abstract out all the OS-specific chunks from MongoProcessRunner
+ */
+interface MongoOSUtilInterface {
+    String[] getMongoStartCmd();
+    String[] getMongoStopCmd();
+}
--- a/storage/cli/src/main/java/com/redhat/thermostat/storage/cli/internal/MongoProcessRunner.java	Tue Sep 20 13:57:38 2016 -0400
+++ b/storage/cli/src/main/java/com/redhat/thermostat/storage/cli/internal/MongoProcessRunner.java	Wed Sep 21 11:41:25 2016 -0400
@@ -63,7 +63,7 @@
     
     private static final boolean profile;
     private static final int profileLevel;
-    
+
     static {
         profile = Boolean.getBoolean("thermostat.storage.mongo.profile");
         profileLevel = Integer.getInteger("thermostat.storage.mongo.profile.slowms", 100);
@@ -74,14 +74,6 @@
 
     private static final String MONGO_PROCESS = "mongod";
 
-    private static final String [] MONGO_BASIC_ARGS = {
-        "mongod", "--quiet", "--fork", "--auth", "--nohttpinterface", "--bind_ip"
-    };
-
-    private static final String [] MONGO_SHUTDOWN_ARGS = {
-        "kill", "-s", "TERM"
-    };
-
     private static final String EMPTY_STRING = "";
 
     private static final String NO_JOURNAL_ARGUMENT = "--nojournal";
@@ -93,7 +85,9 @@
     private Integer pid;
     private final boolean isQuiet;
     private final boolean permitLocalhostExpn;
-    
+
+    private final static MongoOSUtilInterface util = MongoOSUtilFactory.instance().createMongoOSUtil();
+
     public MongoProcessRunner(UNIXProcessHandler processHandler, DBStartupConfiguration configuration, boolean quiet, boolean permitLocalhostException) {
         this.processHandler = processHandler;
         this.configuration = configuration;
@@ -226,7 +220,7 @@
             LocalizedString message = translator.localize(LocaleResources.STORAGE_NOT_RUNNING);
             throw new StorageNotRunningException(message.getContents());
         }
-        List<String> commands = new ArrayList<>(Arrays.asList(MONGO_SHUTDOWN_ARGS));
+        List<String> commands = new ArrayList<>(Arrays.asList(util.getMongoStopCmd()));
         commands.add(String.valueOf(pid));
 
         LoggedExternalProcess process = new LoggedExternalProcess(commands);
@@ -263,12 +257,12 @@
     }
     
     List<String> getStartupCommand(String dbVersion) throws IOException, InvalidConfigurationException {
-        List<String> commands = new ArrayList<>(Arrays.asList(MONGO_BASIC_ARGS));
+        List<String> commands = new ArrayList<>(Arrays.asList(util.getMongoStartCmd()));
         
         commands.add(configuration.getBindIP());
 
         if (dbVersion.compareTo(NO_JOURNAL_FIRST_VERSION) >= 0) {
-            commands.add(1, NO_JOURNAL_ARGUMENT);
+            commands.add(NO_JOURNAL_ARGUMENT);
         }
 
         commands.add("--dbpath");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage/cli/src/main/java/com/redhat/thermostat/storage/cli/internal/MongoUnixUtil.java	Wed Sep 21 11:41:25 2016 -0400
@@ -0,0 +1,60 @@
+/*
+ * 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.storage.cli.internal;
+
+/**
+ * unix-specific code for Mondo runner
+ */
+class MongoUnixUtil implements MongoOSUtilInterface {
+
+    private static final String[] UNIX_MONGO_START_CMD = {
+            "mongod", "--quiet", "--fork", "--auth", "--nohttpinterface", "--bind_ip"
+    };
+    private static final String[] UNIX_MONGO_STOP_CMD = {
+            "kill", "-s", "TERM"
+    };
+
+    @Override
+    public String[] getMongoStartCmd() {
+        return UNIX_MONGO_START_CMD;
+    }
+
+    @Override
+    public String[] getMongoStopCmd() {
+        return UNIX_MONGO_STOP_CMD;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage/cli/src/main/java/com/redhat/thermostat/storage/cli/internal/MongoWindowsUtil.java	Wed Sep 21 11:41:25 2016 -0400
@@ -0,0 +1,60 @@
+/*
+ * 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.storage.cli.internal;
+
+/**
+ * Windows-specific code for Mondo runner
+ */
+class MongoWindowsUtil implements MongoOSUtilInterface {
+
+    private static final String[] WIN_MONGO_START_CMD = {
+            "cmd", "/c", "start", "/b", "mongod", "--quiet", "--auth", "--nohttpinterface", "--bind_ip"
+    };
+    private static final String[] WIN_MONGO_STOP_CMD = {
+            "cmd", "/c", "taskkill", "/F", "/PID"
+    };
+
+    @Override
+    public String[] getMongoStartCmd() {
+        return WIN_MONGO_START_CMD;
+    }
+
+    @Override
+    public String[] getMongoStopCmd() {
+        return WIN_MONGO_STOP_CMD;
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage/cli/src/test/java/com/redhat/thermostat/storage/cli/internal/MongoOSUtilFactoryTest.java	Wed Sep 21 11:41:25 2016 -0400
@@ -0,0 +1,66 @@
+/*
+ * 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.storage.cli.internal;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class MongoOSUtilFactoryTest {
+
+    private static final boolean IS_UNIX = !System.getProperty("os.name").contains("Windows");
+
+    @Test
+    public void instanceIsntNullTest() {
+        assertNotNull(MongoOSUtilFactory.instance());
+    }
+
+    @Test
+    public void testCorrectOs() {
+        assertNotNull(MongoOSUtilFactory.instance());
+
+        MongoOSUtilInterface thing = MongoOSUtilFactory.instance().createMongoOSUtil();
+        assertNotNull(thing);
+
+        if (IS_UNIX)
+            assertTrue("createMongoOSUtil() must return an instance of MongoUnixUtil on unix", thing instanceof MongoUnixUtil);
+        else
+            assertTrue("createMongoOSUtil() must return an instance of MongoWindowsUtil on Windows", thing instanceof MongoWindowsUtil);
+    }
+}
--- a/storage/cli/src/test/java/com/redhat/thermostat/storage/cli/internal/MongoProcessRunnerTest.java	Tue Sep 20 13:57:38 2016 -0400
+++ b/storage/cli/src/test/java/com/redhat/thermostat/storage/cli/internal/MongoProcessRunnerTest.java	Wed Sep 21 11:41:25 2016 -0400
@@ -111,9 +111,9 @@
 
     @Test
     public void testCommandArgumentsWithLatestMongodbVersion() throws Exception {
-        String[] expected = { "mongod", "--nojournal", "--quiet", "--fork",
+        String[] expected = { "mongod", "--quiet", "--fork",
                 "--auth", "--nohttpinterface", "--bind_ip", config.getBindIP(),
-                "--dbpath", config.getDBPath().getCanonicalPath(), "--logpath",
+                "--nojournal", "--dbpath", config.getDBPath().getCanonicalPath(), "--logpath",
                 config.getLogFile().getCanonicalPath(), "--pidfilepath",
                 config.getPidFile().getCanonicalPath(), "--port",
                 Long.toString(config.getPort()), "--setParameter", "enableLocalhostAuthBypass=0"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage/cli/src/test/java/com/redhat/thermostat/storage/cli/internal/MongoUnixUtilTest.java	Wed Sep 21 11:41:25 2016 -0400
@@ -0,0 +1,70 @@
+/*
+ * 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.storage.cli.internal;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+public class MongoUnixUtilTest {
+
+    @Test
+    public void testGetStartCmd() {
+        String[] cmd = new MongoUnixUtil().getMongoStartCmd();
+        assertNotNull(cmd);
+        testContains(cmd, "mongod");
+        testContains(cmd, "--fork");
+    }
+
+    @Test
+    public void testGetStopCmd() {
+        String[] cmd = new MongoUnixUtil().getMongoStopCmd();
+        assertNotNull(cmd);
+        testContains(cmd, "kill");
+        testContains(cmd, "TERM");
+    }
+
+    private static void testContains(final String[] list, final String item) {
+        boolean hasItem = false;
+        for (final String a : list) {
+            if ( item.equals(a) )
+                return;
+        }
+        fail("array doesn't contain '"+item+"'");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage/cli/src/test/java/com/redhat/thermostat/storage/cli/internal/MongoWindowsUtilTest.java	Wed Sep 21 11:41:25 2016 -0400
@@ -0,0 +1,75 @@
+/*
+ * 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.storage.cli.internal;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+public class MongoWindowsUtilTest {
+
+    @Test
+    public void testGetStartCmd() {
+        String[] cmd = new MongoWindowsUtil().getMongoStartCmd();
+        assertNotNull(cmd);
+        testContains(cmd, "cmd");
+        testContains(cmd, "mongod");
+        testContains(cmd, "start");
+    }
+
+    @Test
+    public void testGetStopCmd() {
+        String[] cmd = new MongoWindowsUtil().getMongoStopCmd();
+        assertNotNull(cmd);
+        testContains(cmd, "cmd");
+        testContains(cmd, "taskkill");
+        testContains(cmd, "/pid");
+    }
+
+    private static void testContains(final String[] list, final String item) {
+        boolean hasItem = false;
+        for (final String a : list) {
+            if ( item.equalsIgnoreCase(a) )
+                return;
+        }
+        fail("array doesn't contain '"+item+"'");
+    }
+}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/config/FileStorageCredentials.java	Tue Sep 20 13:57:38 2016 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/config/FileStorageCredentials.java	Wed Sep 21 11:41:25 2016 -0400
@@ -57,8 +57,6 @@
     private static final char[] user = {'u', 's', 'e', 'r', 'n', 'a', 'm', 'e'};
     private static final char comment = '#';
 
-    private final String newLine;
-
     private final File authFile;
     private final Reader testingAuthReader;
     private final int authDataLength;
@@ -70,7 +68,6 @@
         }
         this.testingAuthReader = null;
         this.authFile = authFile;
-        newLine = System.lineSeparator();
         long length = this.authFile.length();
         if (length > Integer.MAX_VALUE || length < 0L) {
             // Unlikely issue with authFile, try to get path to share with user via exception message
@@ -89,12 +86,11 @@
     }
 
     // Testing constructor
-    FileStorageCredentials(Reader authReader, String lineSeparator) {
+    FileStorageCredentials(Reader authReader) {
         if (authReader == null) {
             throw new IllegalArgumentException("authReader must not be null");
         }
         this.testingAuthReader = authReader;
-        newLine = lineSeparator;
         long length = -1;
         try {
             length = testingAuthReader.skip(Long.MAX_VALUE);
@@ -110,11 +106,6 @@
         initUsername();
     }
 
-    // Testing constructor
-    FileStorageCredentials(Reader agentAuthReader) {
-        this(agentAuthReader, System.lineSeparator());
-    }
-
     @Override
     public String getUsername() {
         return username;
@@ -252,20 +243,34 @@
 
     private int nextLine(char[] data, int current) {
         int nextNewLine = getPositionOfNextNewline(data, current);
-        return nextNewLine + newLine.length();
+
+        int nlLength = 1;
+        if ((nextNewLine+1) < data.length) {
+            final char n0 = data[nextNewLine];
+            final char n1 = data[nextNewLine+1];
+            if (n0 == '\r' && n1 == '\n') {
+                nlLength = 2;
+            }
+            else if (n0 == '\n' && n1 == '\r') {
+                nlLength = 2;
+            }
+        }
+        return nextNewLine + nlLength;
     }
 
+    // a newline is defined as '\n', optionally preceded with a '\r' (for windows compatiblity)
+    // using System.lineSeparator() means a file editted on one platform may be unreadable on another.
     private int getPositionOfNextNewline(char[] data, int current) {
         assert( current <= data.length );
         int next = current;
         while (next < data.length) {
+            final char c = data[next];
             boolean newLineFound = false;
-            for (int i = 0; i < newLine.length(); i++) {
-                if (data[next + i] == newLine.charAt(i)) {
-                    newLineFound = true;
-                } else {
-                    newLineFound = false;
-                }
+
+            if (c == '\n' || c == '\r') {
+                newLineFound = true;
+            } else {
+                newLineFound = false;
             }
             if (newLineFound) {
                 break;
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/config/FileStorageCredentialsTest.java	Tue Sep 20 13:57:38 2016 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/config/FileStorageCredentialsTest.java	Wed Sep 21 11:41:25 2016 -0400
@@ -57,6 +57,33 @@
     }
 
     @Test
+    public void testAuthConfigCanReadWindows() {
+        Reader reader = new StringReader("username=user\r\npassword=pass");
+        FileStorageCredentials creds = new FileStorageCredentials(reader);
+        Assert.assertEquals("user", creds.getUsername());
+        Assert.assertEquals(4, creds.getPassword().length);
+        Assert.assertEquals("pass", new String(creds.getPassword()));
+    }
+
+    @Test
+    public void testAuthConfigCanReadReversed() {
+        Reader reader = new StringReader("username=user\n\rpassword=pass\n");
+        FileStorageCredentials creds = new FileStorageCredentials(reader);
+        Assert.assertEquals("user", creds.getUsername());
+        Assert.assertEquals(4, creds.getPassword().length);
+        Assert.assertEquals("pass", new String(creds.getPassword()));
+    }
+
+    @Test
+    public void testAuthConfigCanReadOldschoolMac() {
+        Reader reader = new StringReader("username=user\r\rpassword=pass\r");
+        FileStorageCredentials creds = new FileStorageCredentials(reader);
+        Assert.assertEquals("user", creds.getUsername());
+        Assert.assertEquals(4, creds.getPassword().length);
+        Assert.assertEquals("pass", new String(creds.getPassword()));
+    }
+
+    @Test
     public void testAuthConfig() {
         Reader reader = new StringReader("username=user\npassword=pass\n");
         FileStorageCredentials creds = new FileStorageCredentials(reader);
@@ -123,7 +150,7 @@
     @Test
     public void testAlternateNewLine() {
         Reader reader = new StringReader("username=user\r\npassword=pass\r\n");
-        FileStorageCredentials creds = new FileStorageCredentials(reader, "\r\n");
+        FileStorageCredentials creds = new FileStorageCredentials(reader);
         Assert.assertEquals("user", creds.getUsername());
         Assert.assertEquals("pass", new String(creds.getPassword()));
     }
--- a/unix-process-handler/src/main/java/com/redhat/thermostat/service/internal/UnixProcessUtilities.java	Tue Sep 20 13:57:38 2016 -0400
+++ b/unix-process-handler/src/main/java/com/redhat/thermostat/service/internal/UnixProcessUtilities.java	Wed Sep 21 11:41:25 2016 -0400
@@ -54,14 +54,39 @@
 class UnixProcessUtilities implements UNIXProcessHandler {
 
     private static final Logger logger = LoggingUtils.getLogger(UnixProcessUtilities.class);
-    
-    private static final UNIXProcessHandler instance = new UnixProcessUtilities();
+
+    private static final boolean IS_UNIX = !System.getProperty("os.name").contains("Windows");
+
+    private static final UNIXProcessHandler instance = IS_UNIX ? new UnixProcessUtilities() : new WindowsProcessUtilities();
     public static UNIXProcessHandler getInstance() {
         return instance;
     }
     
     UnixProcessUtilities() {}
-    
+
+    static class WindowsProcessUtilities extends UnixProcessUtilities {
+        public WindowsProcessUtilities() {}
+
+        List<String> buildCommandLine(Integer pid) {
+            final List<String> commandLine = new ArrayList<>();
+            commandLine.add("tasklist");
+            commandLine.add("/FO");
+            commandLine.add("csv");
+            commandLine.add("/FI");
+            commandLine.add("\"PID eq " + String.valueOf(pid) + "\"");
+            return commandLine;
+        }
+
+        String processStdout(final String outStr) {
+            final String [] output = outStr.split(",");
+            String result = output[0];
+            if (result.length() >= 2 && result.charAt(0) == '"')
+                result = result.replace("\"","");
+            result = result.replace(".exe","");
+            return result;
+        }
+    }
+
     @Override
     public void sendSignal(Integer pid, UNIXSignal signal) {
         exec("kill -s " + signal.signalName() + " " + pid);
@@ -75,29 +100,38 @@
             logger.log(Level.WARNING, "can't run kill!", e);
         }
     }
-    
+
+    List<String> buildCommandLine(Integer pid) {
+        final List<String> commandLine = new ArrayList<>();
+        commandLine.add("ps");
+        commandLine.add("--no-heading");
+        commandLine.add("-p");
+        commandLine.add(String.valueOf(pid));
+        return commandLine;
+    }
+
+    String processStdout(final String outStr) {
+        final String [] output = outStr.split(" ");
+        return output[output.length - 1];
+    }
+
     @Override
     public String getProcessName(Integer pid) {
         
         String result = null;
         
-        List<String> commandLine = new ArrayList<>();
-        commandLine.add("ps");
-        commandLine.add("--no-heading");
-        commandLine.add("-p");
-        commandLine.add(String.valueOf(pid));
+        final List<String> commandLine = buildCommandLine(pid);
         
         try {
             Process process = createAndRunProcess(commandLine);
             BufferedReader reader = getProcessOutput(process);
+            if (!IS_UNIX) reader.readLine(); // skip header line
             result = reader.readLine();
-            if (result != null) {
-                String [] output = result.split(" ");
-                result = output[output.length - 1];
-            }
+            if (result != null)
+                result = processStdout(result);
             
         } catch (IOException | ApplicationException e) {
-            logger.log(Level.WARNING, "can't run ps!", e);
+            logger.log(Level.WARNING, "can't run '" + commandLine.get(0) + "'!", e);
         }
         
         return result;
--- a/unix-process-handler/src/test/java/com/redhat/thermostat/service/internal/UnixProcessUtilitiesTest.java	Tue Sep 20 13:57:38 2016 -0400
+++ b/unix-process-handler/src/test/java/com/redhat/thermostat/service/internal/UnixProcessUtilitiesTest.java	Wed Sep 21 11:41:25 2016 -0400
@@ -42,6 +42,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import com.redhat.thermostat.service.process.UNIXProcessHandler;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -51,37 +52,60 @@
 
 public class UnixProcessUtilitiesTest {
 
+    private static final boolean IS_UNIX = !System.getProperty("os.name").contains("Windows");
+
     private BufferedReader reader;
     private BufferedReader emptyReader;
     
     private List<String> processArguments = new ArrayList<>();
-    private UnixProcessUtilities process;
+    private UNIXProcessHandler process;
     
     @Before
     public void setUp() {
-        
-        String data = "123 fluff";
+
+        String data = IS_UNIX ? "123 fluff" : "headerline\r\n\"fluff.exe\",\"1868\",\"Console\",\"1\",\"25,952 K\"";
         reader = new BufferedReader(new StringReader(data));
         emptyReader = new BufferedReader(new StringReader(""));
-        
+
         processArguments.clear();
-        process = new UnixProcessUtilities() {
-            @Override
-            public Process createAndRunProcess(List<String> args)
-                    throws IOException {
-                processArguments.addAll(args);
-                return null;
-            }
-            
-            @Override
-            void exec(String command) {
-                processArguments.add(command);
-            }
-            
-            public java.io.BufferedReader getProcessOutput(Process process) {
-                return reader;
+
+        if (IS_UNIX) {
+            process = new UnixProcessUtilities() {
+                @Override
+                public Process createAndRunProcess(List<String> args)
+                        throws IOException {
+                    processArguments.addAll(args);
+                    return null;
+                }
+
+                @Override
+                void exec(String command) {
+                    processArguments.add(command);
+                }
+
+                public java.io.BufferedReader getProcessOutput(Process process) {
+                    return reader;
+                }
             };
-        };
+        } else {
+            process = new UnixProcessUtilities.WindowsProcessUtilities() {
+                @Override
+                public Process createAndRunProcess(List<String> args)
+                        throws IOException {
+                    processArguments.addAll(args);
+                    return null;
+                }
+
+                @Override
+                void exec(String command) {
+                    processArguments.add(command);
+                }
+
+                public java.io.BufferedReader getProcessOutput(Process process) {
+                    return reader;
+                }
+            };
+        }
     }
     
     @Test
@@ -107,29 +131,52 @@
 
         String result = process.getProcessName(12345);
         Assert.assertEquals("fluff", result);
-        Assert.assertTrue(processArguments.contains("12345"));
-        
-        Assert.assertTrue(processArguments.contains("ps"));
-        Assert.assertTrue(processArguments.contains("--no-heading"));
-        Assert.assertTrue(processArguments.contains("-p"));
+
+        if (IS_UNIX) {
+            Assert.assertTrue(processArguments.contains("12345"));
+            Assert.assertTrue(processArguments.contains("ps"));
+            Assert.assertTrue(processArguments.contains("--no-heading"));
+            Assert.assertTrue(processArguments.contains("-p"));
+        }
+        else {
+            Assert.assertTrue(processArguments.contains("\"PID eq 12345\""));
+            Assert.assertTrue(processArguments.contains("tasklist"));
+        }
     }
     
     @Test
     public void getProcessNameNoOutput() {
 
         // redefine, since we need an empty reader
-        UnixProcessUtilities process = new UnixProcessUtilities() {
-            @Override
-            public Process createAndRunProcess(List<String> args)
-                    throws IOException {
-                processArguments.addAll(args);
-                return null;
-            }
-            
-            public java.io.BufferedReader getProcessOutput(Process process) {
-                return emptyReader;
+        final UNIXProcessHandler process;
+        if (IS_UNIX) {
+            process = new UnixProcessUtilities() {
+                @Override
+                public Process createAndRunProcess(List<String> args)
+                        throws IOException {
+                    processArguments.addAll(args);
+                    return null;
+                }
+
+                public java.io.BufferedReader getProcessOutput(Process process) {
+                    return emptyReader;
+                }
             };
-        };
+        }
+        else {
+            process = new UnixProcessUtilities.WindowsProcessUtilities() {
+                @Override
+                public Process createAndRunProcess(List<String> args)
+                        throws IOException {
+                    processArguments.addAll(args);
+                    return null;
+                }
+
+                public java.io.BufferedReader getProcessOutput(Process process) {
+                    return emptyReader;
+                }
+            };
+        }
         
         String result = process.getProcessName(12345);
         Assert.assertNull(result);
--- a/web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/JettyContainerLauncher.java	Tue Sep 20 13:57:38 2016 -0400
+++ b/web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/JettyContainerLauncher.java	Wed Sep 21 11:41:25 2016 -0400
@@ -192,7 +192,8 @@
         tempWebDefaults.deleteOnExit();
         
         writeWebDefaults(tempWebDefaults, uri);
-        ctx.setDefaultsDescriptor(tempWebDefaults.getAbsolutePath());
+        // Jetty/OpenJDK requires this string to be a forward-slash separated path, even on windows
+        ctx.setDefaultsDescriptor("file://"+tempWebDefaults.getAbsolutePath().replace('\\','/'));
         
         // Make server startup fail if context cannot be deployed.
         // Please don't change this.