You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by zh...@apache.org on 2017/08/11 17:26:51 UTC

[21/23] geode git commit: GEODE-3413: overhaul launcher and process classes and tests

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java b/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java
index 158e7bf..ae64691 100755
--- a/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java
@@ -12,12 +12,45 @@
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
-
 package org.apache.geode.distributed;
 
+import static org.apache.commons.lang.StringUtils.EMPTY;
+import static org.apache.commons.lang.StringUtils.defaultIfBlank;
+import static org.apache.commons.lang.StringUtils.isBlank;
+import static org.apache.commons.lang.StringUtils.isNotBlank;
+import static org.apache.commons.lang.StringUtils.lowerCase;
 import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
 import static org.apache.geode.distributed.ConfigurationProperties.NAME;
 import static org.apache.geode.distributed.ConfigurationProperties.SERVER_BIND_ADDRESS;
+import static org.apache.geode.internal.lang.ObjectUtils.defaultIfNull;
+import static org.apache.geode.internal.lang.StringUtils.wrap;
+import static org.apache.geode.internal.lang.SystemUtils.CURRENT_DIRECTORY;
+import static org.apache.geode.internal.util.IOUtils.tryGetCanonicalPathElseGetAbsolutePath;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.ServiceLoader;
+import java.util.TreeMap;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import joptsimple.OptionException;
+import joptsimple.OptionParser;
+import joptsimple.OptionSet;
 
 import org.apache.geode.SystemFailure;
 import org.apache.geode.cache.Cache;
@@ -36,10 +69,7 @@ import org.apache.geode.internal.cache.PartitionedRegion;
 import org.apache.geode.internal.cache.tier.sockets.CacheServerHelper;
 import org.apache.geode.internal.i18n.LocalizedStrings;
 import org.apache.geode.internal.lang.ObjectUtils;
-import org.apache.geode.internal.lang.StringUtils;
-import org.apache.geode.internal.lang.SystemUtils;
 import org.apache.geode.internal.net.SocketCreator;
-import org.apache.geode.internal.process.ClusterConfigurationNotAvailableException;
 import org.apache.geode.internal.process.ConnectionFailedException;
 import org.apache.geode.internal.process.ControlNotificationHandler;
 import org.apache.geode.internal.process.ControllableProcess;
@@ -53,7 +83,6 @@ import org.apache.geode.internal.process.ProcessLauncherContext;
 import org.apache.geode.internal.process.ProcessType;
 import org.apache.geode.internal.process.StartupStatusListener;
 import org.apache.geode.internal.process.UnableToControlProcessException;
-import org.apache.geode.internal.util.IOUtils;
 import org.apache.geode.lang.AttachAPINotFoundException;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.cli.json.GfJsonArray;
@@ -63,30 +92,6 @@ import org.apache.geode.pdx.PdxSerializer;
 import org.apache.geode.security.AuthenticationRequiredException;
 import org.apache.geode.security.GemFireSecurityException;
 
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.lang.management.ManagementFactory;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.ServiceLoader;
-import java.util.TreeMap;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-import joptsimple.OptionException;
-import joptsimple.OptionParser;
-import joptsimple.OptionSet;
-
 /**
  * The ServerLauncher class is a launcher class with main method to start a GemFire Server (implying
  * a GemFire Cache Server process).
@@ -114,6 +119,8 @@ public class ServerLauncher extends AbstractLauncher<String> {
     helpMap.put("assign-buckets",
         LocalizedStrings.ServerLauncher_SERVER_ASSIGN_BUCKETS_HELP.toLocalizedString());
     helpMap.put("debug", LocalizedStrings.ServerLauncher_SERVER_DEBUG_HELP.toLocalizedString());
+    helpMap.put("delete-pid-file-on-stop",
+        "Specifies that this Server's PID file should be deleted on stop.  The default is to not delete this Server's PID file until JVM exit if --delete-pid-file-on-stop is not specified.");
     helpMap.put("dir", LocalizedStrings.ServerLauncher_SERVER_DIR_HELP.toLocalizedString());
     helpMap.put("disable-default-server",
         LocalizedStrings.ServerLauncher_SERVER_DISABLE_DEFAULT_SERVER_HELP.toLocalizedString());
@@ -163,6 +170,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
   private final AtomicBoolean starting = new AtomicBoolean(false);
 
   private final boolean assignBuckets;
+  private final boolean deletePidFileOnStop;
   private final boolean disableDefaultServer;
   private final boolean force;
   private final boolean help;
@@ -215,8 +223,8 @@ public class ServerLauncher extends AbstractLauncher<String> {
   public static void main(final String... args) {
     try {
       new Builder(args).build().run();
-    } catch (AttachAPINotFoundException e) {
-      System.err.println(e.getMessage());
+    } catch (AttachAPINotFoundException handled) {
+      System.err.println(handled.getMessage());
     }
   }
 
@@ -243,7 +251,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
    * @return the ServerState for this process or null.
    */
   public static ServerState getServerState() {
-    return (getInstance() != null ? getInstance().status() : null);
+    return getInstance() != null ? getInstance().status() : null;
   }
 
   /**
@@ -262,6 +270,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
     this.command = builder.getCommand();
     this.assignBuckets = Boolean.TRUE.equals(builder.getAssignBuckets());
     setDebug(Boolean.TRUE.equals(builder.getDebug()));
+    this.deletePidFileOnStop = Boolean.TRUE.equals(builder.getDeletePidFileOnStop());
     this.disableDefaultServer = Boolean.TRUE.equals(builder.getDisableDefaultServer());
     CacheServerLauncher.setDisableDefaultServer(this.disableDefaultServer);
     this.distributedSystemProperties = builder.getDistributedSystemProperties();
@@ -351,7 +360,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
     final StringBuilder buffer = new StringBuilder(ServerState.getServerBindAddressAsString(this));
     final String serverPort = ServerState.getServerPortAsString(this);
 
-    if (StringUtils.isNotBlank(serverPort)) {
+    if (isNotBlank(serverPort)) {
       buffer.append("[").append(serverPort).append("]");
     }
 
@@ -436,9 +445,9 @@ public class ServerLauncher extends AbstractLauncher<String> {
    * 
    * @return a String value indicating the name of this Server's log file.
    */
+  @Override
   public String getLogFileName() {
-    return StringUtils.defaultIfBlank(getMemberName(), DEFAULT_SERVER_LOG_NAME)
-        .concat(DEFAULT_SERVER_LOG_EXT);
+    return defaultIfBlank(getMemberName(), DEFAULT_SERVER_LOG_NAME).concat(DEFAULT_SERVER_LOG_EXT);
   }
 
   /**
@@ -450,7 +459,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
    */
   @Override
   public String getMemberName() {
-    return StringUtils.defaultIfBlank(this.memberName, super.getMemberName());
+    return defaultIfBlank(this.memberName, super.getMemberName());
   }
 
   /**
@@ -511,11 +520,9 @@ public class ServerLauncher extends AbstractLauncher<String> {
       final InetAddress localhost = SocketCreator.getLocalHost();
 
       return localhost.getCanonicalHostName();
-    } catch (UnknownHostException ignore) {
-      // TODO determine a better value for the host on which the Server is running to return here...
+    } catch (UnknownHostException handled) {
       // NOTE returning localhost/127.0.0.1 implies the serverBindAddress was null and no IP address
-      // for localhost
-      // could be found
+      // for localhost could be found
       return "localhost/127.0.0.1";
     }
   }
@@ -542,7 +549,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
    * @see #getServerPort()
    */
   public String getServerPortAsString() {
-    return ObjectUtils.defaultIfNull(getServerPort(), getDefaultServerPort()).toString();
+    return defaultIfNull(getServerPort(), getDefaultServerPort()).toString();
   }
 
   /**
@@ -550,6 +557,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
    * 
    * @return a String indicating the name for a GemFire Server.
    */
+  @Override
   public String getServiceName() {
     return SERVER_SERVICE_NAME;
   }
@@ -575,7 +583,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
    *         configuration meta-data.
    */
   public boolean isSpringXmlLocationSpecified() {
-    return StringUtils.isNotBlank(this.springXmlLocation);
+    return isNotBlank(this.springXmlLocation);
   }
 
   /**
@@ -639,14 +647,13 @@ public class ServerLauncher extends AbstractLauncher<String> {
     if (Command.isUnspecified(command)) {
       usage();
     } else {
-      info(StringUtils.wrap(helpMap.get(command.getName()), 80, ""));
+      info(wrap(helpMap.get(command.getName()), 80, ""));
       info("\n\nusage: \n\n");
-      info(StringUtils.wrap("> java ... " + getClass().getName() + ' ' + usageMap.get(command), 80,
-          "\t\t"));
+      info(wrap("> java ... " + getClass().getName() + ' ' + usageMap.get(command), 80, "\t\t"));
       info("\n\noptions: \n\n");
 
       for (final String option : command.getOptions()) {
-        info(StringUtils.wrap("--" + option + ": " + helpMap.get(option) + '\n', 80, "\t"));
+        info(wrap("--" + option + ": " + helpMap.get(option) + '\n', 80, "\t"));
       }
 
       info("\n\n");
@@ -660,7 +667,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
    * @see #help(org.apache.geode.distributed.ServerLauncher.Command)
    */
   public void usage() {
-    info(StringUtils.wrap(helpMap.get("launcher"), 80, "\t"));
+    info(wrap(helpMap.get("launcher"), 80, "\t"));
     info("\n\nSTART\n\n");
     help(Command.START);
     info("STATUS\n\n");
@@ -719,7 +726,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
    * @see #start()
    */
   private boolean isStartable() {
-    return (!isRunning() && this.starting.compareAndSet(false, true));
+    return !isRunning() && this.starting.compareAndSet(false, true);
   }
 
   /**
@@ -810,18 +817,12 @@ public class ServerLauncher extends AbstractLauncher<String> {
             LocalizedStrings.Launcher_Command_START_PID_UNAVAILABLE_ERROR_MESSAGE.toLocalizedString(
                 getServiceName(), getId(), getWorkingDirectory(), e.getMessage()),
             e);
-      } catch (ClusterConfigurationNotAvailableException e) {
-        failOnStart(e);
-        throw e;
-      } catch (RuntimeException e) {
+      } catch (RuntimeException | Error e) {
         failOnStart(e);
         throw e;
       } catch (Exception e) {
         failOnStart(e);
         throw new RuntimeException(e);
-      } catch (Error e) {
-        failOnStart(e);
-        throw e;
       } finally {
         this.starting.set(false);
       }
@@ -857,7 +858,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
       this.cache = null;
     }
     if (this.process != null) {
-      this.process.stop();
+      this.process.stop(this.deletePidFileOnStop);
       this.process = null;
     }
 
@@ -886,7 +887,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
    */
   boolean isWaiting(final Cache cache) {
     // return (isRunning() && !getCache().isClosed());
-    return (isRunning() && (cache.getDistributedSystem().isConnected() || cache.isReconnecting()));
+    return isRunning() && (cache.getDistributedSystem().isConnected() || cache.isReconnecting());
   }
 
   /**
@@ -901,9 +902,10 @@ public class ServerLauncher extends AbstractLauncher<String> {
         while (isWaiting(getCache())) {
           try {
             synchronized (this) {
-              wait(500l);
+              wait(500L);
             }
-          } catch (InterruptedException ignore) {
+          } catch (InterruptedException handled) {
+            // loop back around
           }
         }
       } catch (RuntimeException e) {
@@ -926,7 +928,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
    * @see #isDisableDefaultServer()
    */
   protected boolean isDefaultServerEnabled(final Cache cache) {
-    return (cache.getCacheServers().isEmpty() && !isDisableDefaultServer());
+    return cache.getCacheServers().isEmpty() && !isDisableDefaultServer();
   }
 
   /**
@@ -940,7 +942,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
   void startCacheServer(final Cache cache) throws IOException {
     if (isDefaultServerEnabled(cache)) {
       final String serverBindAddress =
-          (getServerBindAddress() == null ? null : getServerBindAddress().getHostAddress());
+          getServerBindAddress() == null ? null : getServerBindAddress().getHostAddress();
       final Integer serverPort = getServerPort();
       CacheServerLauncher.setServerBindAddress(serverBindAddress);
       CacheServerLauncher.setServerPort(serverPort);
@@ -1024,7 +1026,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
    * @return a boolean indicating if the Server is starting or is already running.
    */
   protected boolean isStartingOrRunning() {
-    return (this.starting.get() || isRunning());
+    return this.starting.get() || isRunning();
   }
 
   /**
@@ -1037,7 +1039,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
     if (isStartingOrRunning()) {
       debug(
           "Getting status from the ServerLauncher instance that actually launched the GemFire Cache Server.%n");
-      return new ServerState(this, (isRunning() ? Status.ONLINE : Status.STARTING));
+      return new ServerState(this, isRunning() ? Status.ONLINE : Status.STARTING);
     } else if (isPidInProcess() && launcher != null) {
       return launcher.statusInProcess();
     } else if (getPid() != null) {
@@ -1061,7 +1063,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
     if (isStartingOrRunning()) {
       debug(
           "Getting status from the ServerLauncher instance that actually launched the GemFire Cache Server.%n");
-      return new ServerState(this, (isRunning() ? Status.ONLINE : Status.STARTING));
+      return new ServerState(this, isRunning() ? Status.ONLINE : Status.STARTING);
     } else {
       return new ServerState(this, Status.NOT_RESPONDING);
     }
@@ -1074,50 +1076,13 @@ public class ServerLauncher extends AbstractLauncher<String> {
       controller.checkPidSupport();
       final String statusJson = controller.status();
       return ServerState.fromJson(statusJson);
-    }
-    // catch (NoClassDefFoundError error) {
-    // if (isAttachAPINotFound(error)) {
-    // throw new
-    // AttachAPINotFoundException(LocalizedStrings.Launcher_ATTACH_API_NOT_FOUND_ERROR_MESSAGE
-    // .toLocalizedString(), error);
-    // }
-    //
-    // throw error;
-    // }
-    catch (ConnectionFailedException e) {
+    } catch (ConnectionFailedException handled) {
       // failed to attach to server JVM
-      return createNoResponseState(e, "Failed to connect to server with process id " + getPid());
-    } catch (IOException e) {
-      // failed to open or read file or dir
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + getPid());
-    }
-    // catch (MalformedObjectNameException e) { // impossible
-    // // JMX object name is bad
-    // return createNoResponseState(e, "Failed to communicate with server with process id " +
-    // getPid());
-    // }
-    catch (MBeanInvocationFailedException e) {
-      // MBean either doesn't exist or method or attribute don't exist
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + getPid());
-    }
-    // catch (PidUnavailableException e) {
-    // // couldn't determine pid from within server JVM
-    // return createNoResponseState(e, "Failed to communicate with server with process id " +
-    // getPid());
-    // }
-    catch (UnableToControlProcessException e) {
-      // TODO comment me
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + getPid());
-    } catch (InterruptedException e) {
-      // TODO comment me
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + getPid());
-    } catch (TimeoutException e) {
-      // TODO comment me
-      return createNoResponseState(e,
+      return createNoResponseState(handled,
+          "Failed to connect to server with process id " + getPid());
+    } catch (IOException | MBeanInvocationFailedException | UnableToControlProcessException
+        | InterruptedException | TimeoutException handled) {
+      return createNoResponseState(handled,
           "Failed to communicate with server with process id " + getPid());
     }
   }
@@ -1125,9 +1090,9 @@ public class ServerLauncher extends AbstractLauncher<String> {
   private ServerState statusWithWorkingDirectory() {
     int parsedPid = 0;
     try {
-      final ProcessController controller = new ProcessControllerFactory().createProcessController(
-          this.controllerParameters, new File(getWorkingDirectory()),
-          ProcessType.SERVER.getPidFileName(), READ_PID_FILE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+      final ProcessController controller =
+          new ProcessControllerFactory().createProcessController(this.controllerParameters,
+              new File(getWorkingDirectory()), ProcessType.SERVER.getPidFileName());
       parsedPid = controller.getProcessId();
 
       // note: in-process request will go infinite loop unless we do the following
@@ -1140,35 +1105,26 @@ public class ServerLauncher extends AbstractLauncher<String> {
 
       final String statusJson = controller.status();
       return ServerState.fromJson(statusJson);
-    } catch (ConnectionFailedException e) {
+    } catch (ConnectionFailedException handled) {
       // failed to attach to server JVM
-      return createNoResponseState(e, "Failed to connect to server with process id " + parsedPid);
-    } catch (FileNotFoundException e) {
+      return createNoResponseState(handled,
+          "Failed to connect to server with process id " + parsedPid);
+    } catch (FileNotFoundException handled) {
       // could not find pid file
-      return createNoResponseState(e, "Failed to find process file "
+      return createNoResponseState(handled, "Failed to find process file "
           + ProcessType.SERVER.getPidFileName() + " in " + getWorkingDirectory());
-    } catch (IOException e) {
-      // failed to open or read file or dir
-      return createNoResponseState(e,
+    } catch (IOException | MBeanInvocationFailedException | UnableToControlProcessException
+        | TimeoutException handled) {
+      return createNoResponseState(handled,
           "Failed to communicate with server with process id " + parsedPid);
-    } catch (InterruptedException e) {
+    } catch (InterruptedException handled) {
       Thread.currentThread().interrupt();
-      return createNoResponseState(e,
+      return createNoResponseState(handled,
           "Interrupted while trying to communicate with server with process id " + parsedPid);
-    } catch (MBeanInvocationFailedException e) {
-      // MBean either doesn't exist or method or attribute don't exist
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + parsedPid);
-    } catch (PidUnavailableException e) {
+    } catch (PidUnavailableException handled) {
       // couldn't determine pid from within server JVM
-      return createNoResponseState(e, "Failed to find usable process id within file "
+      return createNoResponseState(handled, "Failed to find usable process id within file "
           + ProcessType.SERVER.getPidFileName() + " in " + getWorkingDirectory());
-    } catch (UnableToControlProcessException e) {
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + parsedPid);
-    } catch (TimeoutException e) {
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + parsedPid);
     }
   }
 
@@ -1205,7 +1161,6 @@ public class ServerLauncher extends AbstractLauncher<String> {
       return stopWithWorkingDirectory();
     }
 
-    // TODO give user detailed error message?
     return new ServerState(this, Status.NOT_RESPONDING);
   }
 
@@ -1217,7 +1172,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
       this.cache.close();
       this.cache = null;
       if (this.process != null) {
-        this.process.stop();
+        this.process.stop(this.deletePidFileOnStop);
         this.process = null;
       }
       INSTANCE.compareAndSet(this, null); // note: other thread may return Status.NOT_RESPONDING now
@@ -1235,42 +1190,13 @@ public class ServerLauncher extends AbstractLauncher<String> {
       controller.checkPidSupport();
       controller.stop();
       return new ServerState(this, Status.STOPPED);
-    }
-    // catch (NoClassDefFoundError error) {
-    // if (isAttachAPINotFound(error)) {
-    // throw new
-    // AttachAPINotFoundException(LocalizedStrings.Launcher_ATTACH_API_NOT_FOUND_ERROR_MESSAGE
-    // .toLocalizedString(), error);
-    // }
-    //
-    // throw error;
-    // }
-    catch (ConnectionFailedException e) {
+    } catch (ConnectionFailedException handled) {
       // failed to attach to server JVM
-      return createNoResponseState(e, "Failed to connect to server with process id " + getPid());
-    } catch (IOException e) {
-      // failed to open or read file or dir
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + getPid());
-    }
-    // catch (MalformedObjectNameException e) { // impossible
-    // // JMX object name is bad
-    // return createNoResponseState(e, "Failed to communicate with server with process id " +
-    // getPid());
-    // }
-    catch (MBeanInvocationFailedException e) {
-      // MBean either doesn't exist or method or attribute don't exist
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + getPid());
-    }
-    // catch (PidUnavailableException e) {
-    // // couldn't determine pid from within server JVM
-    // return createNoResponseState(e, "Failed to communicate with server with process id " +
-    // getPid());
-    // }
-    catch (UnableToControlProcessException e) {
-      // TODO comment me
-      return createNoResponseState(e,
+      return createNoResponseState(handled,
+          "Failed to connect to server with process id " + getPid());
+    } catch (IOException | MBeanInvocationFailedException
+        | UnableToControlProcessException handled) {
+      return createNoResponseState(handled,
           "Failed to communicate with server with process id " + getPid());
     }
   }
@@ -1278,9 +1204,9 @@ public class ServerLauncher extends AbstractLauncher<String> {
   private ServerState stopWithWorkingDirectory() {
     int parsedPid = 0;
     try {
-      final ProcessController controller = new ProcessControllerFactory().createProcessController(
-          this.controllerParameters, new File(getWorkingDirectory()),
-          ProcessType.SERVER.getPidFileName(), READ_PID_FILE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+      final ProcessController controller =
+          new ProcessControllerFactory().createProcessController(this.controllerParameters,
+              new File(getWorkingDirectory()), ProcessType.SERVER.getPidFileName());
       parsedPid = controller.getProcessId();
 
       // NOTE in-process request will go infinite loop unless we do the following
@@ -1293,35 +1219,30 @@ public class ServerLauncher extends AbstractLauncher<String> {
 
       controller.stop();
       return new ServerState(this, Status.STOPPED);
-    } catch (ConnectionFailedException e) {
+    } catch (ConnectionFailedException handled) {
       // failed to attach to server JVM
-      return createNoResponseState(e, "Failed to connect to server with process id " + parsedPid);
-    } catch (FileNotFoundException e) {
+      return createNoResponseState(handled,
+          "Failed to connect to server with process id " + parsedPid);
+    } catch (FileNotFoundException handled) {
       // could not find pid file
-      return createNoResponseState(e, "Failed to find process file "
+      return createNoResponseState(handled, "Failed to find process file "
           + ProcessType.SERVER.getPidFileName() + " in " + getWorkingDirectory());
-    } catch (IOException e) {
-      // failed to open or read file or dir
-      return createNoResponseState(e,
+    } catch (IOException | MBeanInvocationFailedException
+        | UnableToControlProcessException handled) {
+      return createNoResponseState(handled,
           "Failed to communicate with server with process id " + parsedPid);
-    } catch (InterruptedException e) {
+    } catch (InterruptedException handled) {
       Thread.currentThread().interrupt();
-      return createNoResponseState(e,
+      return createNoResponseState(handled,
           "Interrupted while trying to communicate with server with process id " + parsedPid);
-    } catch (MBeanInvocationFailedException e) {
-      // MBean either doesn't exist or method or attribute don't exist
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + parsedPid);
-    } catch (PidUnavailableException e) {
+    } catch (PidUnavailableException handled) {
       // couldn't determine pid from within server JVM
-      return createNoResponseState(e, "Failed to find usable process id within file "
-          + ProcessType.SERVER.getPidFileName() + " in " + getWorkingDirectory());
-    } catch (TimeoutException e) {
-      return createNoResponseState(e, "Timed out trying to find usable process id within file "
+      return createNoResponseState(handled, "Failed to find usable process id within file "
           + ProcessType.SERVER.getPidFileName() + " in " + getWorkingDirectory());
-    } catch (UnableToControlProcessException e) {
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + parsedPid);
+    } catch (TimeoutException handled) {
+      return createNoResponseState(handled,
+          "Timed out trying to find usable process id within file "
+              + ProcessType.SERVER.getPidFileName() + " in " + getWorkingDirectory());
     }
   }
 
@@ -1330,17 +1251,16 @@ public class ServerLauncher extends AbstractLauncher<String> {
     this.running.set(true);
   }
 
-
   private ServerState createNoResponseState(final Exception cause, final String errorMessage) {
     debug(cause);
     return new ServerState(this, Status.NOT_RESPONDING, errorMessage);
   }
 
-  private Properties getOverriddenDefaults() {
+  private Properties getOverriddenDefaults() throws IOException {
     final Properties overriddenDefaults = new Properties();
 
     overriddenDefaults.put(ProcessLauncherContext.OVERRIDDEN_DEFAULTS_PREFIX.concat(LOG_FILE),
-        getLogFileName());
+        getLogFile().getCanonicalPath());
 
     for (String key : System.getProperties().stringPropertyNames()) {
       if (key.startsWith(ProcessLauncherContext.OVERRIDDEN_DEFAULTS_PREFIX)) {
@@ -1358,7 +1278,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
     }
 
     @Override
-    public File getWorkingDirectory() {
+    public File getDirectory() {
       return new File(ServerLauncher.this.getWorkingDirectory());
     }
 
@@ -1376,7 +1296,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
     public ObjectName getNamePattern() {
       try {
         return ObjectName.getInstance("GemFire:type=Member,*");
-      } catch (MalformedObjectNameException | NullPointerException ignore) {
+      } catch (MalformedObjectNameException | NullPointerException handled) {
         return null;
       }
     }
@@ -1421,6 +1341,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
 
     private Boolean assignBuckets;
     private Boolean debug;
+    private Boolean deletePidFileOnStop;
     private Boolean disableDefaultServer;
     private Boolean force;
     private Boolean help;
@@ -1540,6 +1461,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
 
         setAssignBuckets(options.has("assign-buckets"));
         setDebug(options.has("debug"));
+        setDeletePidFileOnStop(options.has("delete-pid-file-on-stop"));
         setDisableDefaultServer(options.has("disable-default-server"));
         setForce(options.has("force"));
         setHelp(options.has("help"));
@@ -1617,7 +1539,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
           }
         }
 
-        // TODO why are these option not inside the 'if (!isHelping())' conditional block!?
+        // why are these option not inside the 'if (!isHelping())' conditional block?
 
         if (options.hasArgument(CliStrings.START_SERVER__CRITICAL__HEAP__PERCENTAGE)) {
           setCriticalHeapPercentage(Float.parseFloat(ObjectUtils
@@ -1726,7 +1648,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
      * @see org.apache.geode.distributed.ServerLauncher.Command
      */
     public Command getCommand() {
-      return ObjectUtils.defaultIfNull(this.command, DEFAULT_COMMAND);
+      return defaultIfNull(this.command, DEFAULT_COMMAND);
     }
 
     /**
@@ -1801,7 +1723,33 @@ public class ServerLauncher extends AbstractLauncher<String> {
     }
 
     /**
-     * Determines whether a default cache server will be added when the GemFire Server comes online.
+     * Determines whether the Geode Server should delete the pid file when its service stops or when
+     * the JVM exits.
+     *
+     * @return a boolean value indicating if the pid file should be deleted when this service stops
+     *         or when the JVM exits.
+     * @see #setDeletePidFileOnStop(Boolean)
+     */
+    public Boolean getDeletePidFileOnStop() {
+      return this.deletePidFileOnStop;
+    }
+
+    /**
+     * Sets whether the Geode Server should delete the pid file when its service stops or when the
+     * JVM exits.
+     *
+     * @param deletePidFileOnStop a boolean value indicating if the pid file should be deleted when
+     *        this service stops or when the JVM exits.
+     * @return this Builder instance.
+     * @see #getDeletePidFileOnStop()
+     */
+    public Builder setDeletePidFileOnStop(final Boolean deletePidFileOnStop) {
+      this.deletePidFileOnStop = deletePidFileOnStop;
+      return this;
+    }
+
+    /**
+     * Determines whether a default cache server will be added when the Geode Server comes online.
      * 
      * @return a boolean value indicating whether to add a default cache server.
      * @see #setDisableDefaultServer(Boolean)
@@ -1840,11 +1788,10 @@ public class ServerLauncher extends AbstractLauncher<String> {
      * 
      * @return the boolean value specifying whether or not to overwrite the PID file if it already
      *         exists.
-     * @see org.apache.geode.internal.process.LocalProcessLauncher
      * @see #setForce(Boolean)
      */
     public Boolean getForce() {
-      return ObjectUtils.defaultIfNull(this.force, DEFAULT_FORCE);
+      return defaultIfNull(this.force, DEFAULT_FORCE);
     }
 
     /**
@@ -1854,7 +1801,6 @@ public class ServerLauncher extends AbstractLauncher<String> {
      * @param force a boolean value indicating whether to overwrite the PID file when it already
      *        exists.
      * @return this Builder instance.
-     * @see org.apache.geode.internal.process.LocalProcessLauncher
      * @see #getForce()
      */
     public Builder setForce(final Boolean force) {
@@ -1941,7 +1887,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
      * @see #getMemberName()
      */
     public Builder setMemberName(final String memberName) {
-      if (StringUtils.isBlank(memberName)) {
+      if (isBlank(memberName)) {
         throw new IllegalArgumentException(
             LocalizedStrings.Launcher_Builder_MEMBER_NAME_ERROR_MESSAGE
                 .toLocalizedString("Server"));
@@ -1983,11 +1929,11 @@ public class ServerLauncher extends AbstractLauncher<String> {
     }
 
     /**
-     * Determines whether the new instance of LocatorLauncher will redirect output to system logs
-     * when starting a Locator.
+     * Determines whether the new instance of ServerLauncher will redirect output to system logs
+     * when starting a Server.
      * 
      * @return a boolean value indicating if output will be redirected to system logs when starting
-     *         a Locator
+     *         a Server
      * 
      * @see #setRedirectOutput(Boolean)
      */
@@ -2005,11 +1951,11 @@ public class ServerLauncher extends AbstractLauncher<String> {
     }
 
     /**
-     * Sets whether the new instance of LocatorLauncher will redirect output to system logs when
-     * starting a Locator.
+     * Sets whether the new instance of ServerLauncher will redirect output to system logs when
+     * starting a Server.
      * 
      * @param redirectOutput a boolean value indicating if output will be redirected to system logs
-     *        when starting a Locator.
+     *        when starting a Server.
      * @return this Builder instance.
      * @see #getRedirectOutput()
      */
@@ -2047,7 +1993,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
      * @see #getServerBindAddress()
      */
     public Builder setServerBindAddress(final String serverBindAddress) {
-      if (StringUtils.isBlank(serverBindAddress)) {
+      if (isBlank(serverBindAddress)) {
         this.serverBindAddress = null;
         return this;
       }
@@ -2081,7 +2027,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
      * @see #setServerPort(Integer)
      */
     public Integer getServerPort() {
-      return ObjectUtils.defaultIfNull(this.serverPort, getDefaultServerPort());
+      return defaultIfNull(this.serverPort, getDefaultServerPort());
     }
 
     boolean isServerPortSetByUser() {
@@ -2144,8 +2090,8 @@ public class ServerLauncher extends AbstractLauncher<String> {
      * @see #setWorkingDirectory(String)
      */
     public String getWorkingDirectory() {
-      return IOUtils.tryGetCanonicalPathElseGetAbsolutePath(
-          new File(StringUtils.defaultIfBlank(this.workingDirectory, DEFAULT_WORKING_DIRECTORY)));
+      return tryGetCanonicalPathElseGetAbsolutePath(
+          new File(defaultIfBlank(this.workingDirectory, DEFAULT_WORKING_DIRECTORY)));
     }
 
     /**
@@ -2162,8 +2108,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
      * @see java.io.FileNotFoundException
      */
     public Builder setWorkingDirectory(final String workingDirectory) {
-      if (!(new File(StringUtils.defaultIfBlank(workingDirectory, DEFAULT_WORKING_DIRECTORY))
-          .isDirectory())) {
+      if (!new File(defaultIfBlank(workingDirectory, DEFAULT_WORKING_DIRECTORY)).isDirectory()) {
         throw new IllegalArgumentException(
             LocalizedStrings.Launcher_Builder_WORKING_DIRECTORY_NOT_FOUND_ERROR_MESSAGE
                 .toLocalizedString("Server"),
@@ -2242,6 +2187,10 @@ public class ServerLauncher extends AbstractLauncher<String> {
     }
 
     public Builder setHostNameForClients(String hostNameForClients) {
+      if (isBlank(hostNameForClients)) {
+        throw new IllegalArgumentException(
+            "The hostname used by clients to connect to the Server must have an argument if the --hostname-for-clients command-line option is specified!");
+      }
       this.hostNameForClients = hostNameForClients;
       return this;
     }
@@ -2412,7 +2361,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
      */
     void validateOnStart() {
       if (Command.START == getCommand()) {
-        if (StringUtils.isBlank(getMemberName())
+        if (isBlank(getMemberName())
             && !isSet(System.getProperties(), DistributionConfig.GEMFIRE_PREFIX + NAME)
             && !isSet(getDistributedSystemProperties(), NAME)
             && !isSet(loadGemFireProperties(DistributedSystem.getPropertyFileURL()), NAME)) {
@@ -2421,7 +2370,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
                   .toLocalizedString("Server"));
         }
 
-        if (!SystemUtils.CURRENT_DIRECTORY.equals(getWorkingDirectory())) {
+        if (!CURRENT_DIRECTORY.equals(getWorkingDirectory())) {
           throw new IllegalStateException(
               LocalizedStrings.Launcher_Builder_WORKING_DIRECTORY_OPTION_NOT_VALID_ERROR_MESSAGE
                   .toLocalizedString("Server"));
@@ -2481,10 +2430,10 @@ public class ServerLauncher extends AbstractLauncher<String> {
     private final String name;
 
     Command(final String name, final String... options) {
-      assert StringUtils.isNotBlank(name) : "The name of the command must be specified!";
+      assert isNotBlank(name) : "The name of the command must be specified!";
       this.name = name;
-      this.options = (options != null ? Collections.unmodifiableList(Arrays.asList(options))
-          : Collections.<String>emptyList());
+      this.options = options != null ? Collections.unmodifiableList(Arrays.asList(options))
+          : Collections.<String>emptyList();
     }
 
     /**
@@ -2496,7 +2445,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
      *         valid.
      */
     public static boolean isCommand(final String name) {
-      return (valueOfName(name) != null);
+      return valueOfName(name) != null;
     }
 
     /**
@@ -2508,7 +2457,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
      * @see Command#UNSPECIFIED
      */
     public static boolean isUnspecified(final Command command) {
-      return (command == null || command.isUnspecified());
+      return command == null || command.isUnspecified();
     }
 
     /**
@@ -2539,7 +2488,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
     }
 
     /**
-     * Gets a set of valid options that can be used with the Locator launcher command when used from
+     * Gets a set of valid options that can be used with the Server launcher command when used from
      * the command-line.
      * 
      * @return a Set of Strings indicating the names of the options available to the Server launcher
@@ -2550,14 +2499,14 @@ public class ServerLauncher extends AbstractLauncher<String> {
     }
 
     /**
-     * Determines whether this Locator launcher command has the specified command-line option.
+     * Determines whether this Server launcher command has the specified command-line option.
      * 
      * @param option a String indicating the name of the command-line option to this command.
      * @return a boolean value indicating whether this command has the specified named command-line
      *         option.
      */
     public boolean hasOption(final String option) {
-      return getOptions().contains(StringUtils.lowerCase(option));
+      return getOptions().contains(lowerCase(option));
     }
 
     /**
@@ -2567,7 +2516,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
      * @see #UNSPECIFIED
      */
     public boolean isUnspecified() {
-      return (this == UNSPECIFIED);
+      return this == UNSPECIFIED;
     }
 
     /**
@@ -2582,8 +2531,8 @@ public class ServerLauncher extends AbstractLauncher<String> {
   }
 
   /**
-   * The ServerState is an immutable type representing the state of the specified Locator at any
-   * given moment in time. The state of the Locator is assessed at the exact moment an instance of
+   * The ServerState is an immutable type representing the state of the specified Server at any
+   * given moment in time. The state of the Server is assessed at the exact moment an instance of
    * this class is constructed.
    * 
    * @see org.apache.geode.distributed.AbstractLauncher.ServiceState
@@ -2612,7 +2561,6 @@ public class ServerLauncher extends AbstractLauncher<String> {
             gfJsonObject.getString(JSON_HOST), gfJsonObject.getString(JSON_PORT),
             gfJsonObject.getString(JSON_MEMBERNAME));
       } catch (GfJsonException e) {
-        // TODO: or should we return OFFLINE?
         throw new IllegalArgumentException("Unable to create ServerStatus from JSON: " + json, e);
       }
     }
@@ -2673,9 +2621,8 @@ public class ServerLauncher extends AbstractLauncher<String> {
       if (system != null) {
         final File logFile = system.getConfig().getLogFile();
         if (logFile != null && logFile.isFile()) {
-          final String logFileCanonicalPath =
-              IOUtils.tryGetCanonicalPathElseGetAbsolutePath(logFile);
-          if (StringUtils.isNotBlank(logFileCanonicalPath)) {
+          final String logFileCanonicalPath = tryGetCanonicalPathElseGetAbsolutePath(logFile);
+          if (isNotBlank(logFileCanonicalPath)) {
             return logFileCanonicalPath;
           }
         }
@@ -2693,7 +2640,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
         if (csList != null && !csList.isEmpty()) {
           final CacheServer cs = csList.get(0);
           final String serverBindAddressAsString = cs.getBindAddress();
-          if (StringUtils.isNotBlank(serverBindAddressAsString)) {
+          if (isNotBlank(serverBindAddressAsString)) {
             return serverBindAddressAsString;
           }
         }
@@ -2711,14 +2658,13 @@ public class ServerLauncher extends AbstractLauncher<String> {
         if (csList != null && !csList.isEmpty()) {
           final CacheServer cs = csList.get(0);
           final String portAsString = String.valueOf(cs.getPort());
-          if (StringUtils.isNotBlank(portAsString)) {
+          if (isNotBlank(portAsString)) {
             return portAsString;
           }
         }
       }
 
-      return (launcher.isDisableDefaultServer() ? StringUtils.EMPTY
-          : launcher.getServerPortAsString());
+      return launcher.isDisableDefaultServer() ? EMPTY : launcher.getServerPortAsString();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java
index ffe3be4..4725518 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java
@@ -69,7 +69,6 @@ import org.apache.geode.internal.logging.LogService;
 import org.apache.geode.internal.logging.LogWriterFactory;
 import org.apache.geode.internal.logging.LoggingThreadGroup;
 import org.apache.geode.internal.logging.log4j.LocalizedMessage;
-import org.apache.geode.internal.logging.log4j.LogMarker;
 import org.apache.geode.internal.logging.log4j.LogWriterAppenders;
 import org.apache.geode.internal.net.SocketCreator;
 import org.apache.geode.internal.net.SocketCreatorFactory;
@@ -525,6 +524,10 @@ public class InternalLocator extends Locator implements ConnectListener {
     return this.config;
   }
 
+  public InternalCache getCache() {
+    return myCache;
+  }
+
   /**
    * Start peer location in this locator. If you plan on starting a distributed system later, this
    * method should be called first so that the distributed system can use this locator.

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java b/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java
index 1c4104e..2bbe009 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java
@@ -17,8 +17,25 @@ package org.apache.geode.internal.cache;
 import static java.util.stream.Collectors.joining;
 import static java.util.stream.Collectors.toList;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.Set;
+import java.util.stream.Stream;
+
 import org.apache.commons.lang.ArrayUtils;
 import org.apache.commons.lang.StringUtils;
+import org.apache.logging.log4j.Logger;
+
 import org.apache.geode.UnmodifiableException;
 import org.apache.geode.cache.Cache;
 import org.apache.geode.distributed.internal.ClusterConfigurationService;
@@ -29,28 +46,12 @@ import org.apache.geode.internal.ConfigSource;
 import org.apache.geode.internal.DeployedJar;
 import org.apache.geode.internal.JarDeployer;
 import org.apache.geode.internal.admin.remote.DistributionLocatorId;
+import org.apache.geode.internal.config.ClusterConfigurationNotAvailableException;
 import org.apache.geode.internal.i18n.LocalizedStrings;
 import org.apache.geode.internal.logging.LogService;
-import org.apache.geode.internal.process.ClusterConfigurationNotAvailableException;
 import org.apache.geode.management.internal.configuration.domain.Configuration;
 import org.apache.geode.management.internal.configuration.messages.ConfigurationRequest;
 import org.apache.geode.management.internal.configuration.messages.ConfigurationResponse;
-import org.apache.logging.log4j.Logger;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Properties;
-import java.util.Set;
-import java.util.stream.Stream;
 
 public class ClusterConfigurationLoader {
 

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java b/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
index f176d22..67c8add 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
@@ -76,12 +76,9 @@ import javax.transaction.TransactionManager;
 
 import com.sun.jna.Native;
 import com.sun.jna.Platform;
-
 import org.apache.commons.lang.StringUtils;
 import org.apache.logging.log4j.Logger;
-import org.apache.geode.internal.cache.event.EventTracker;
-import org.apache.geode.internal.cache.event.EventTrackerExpiryTask;
-import org.apache.geode.internal.security.SecurityServiceFactory;
+
 import org.apache.geode.CancelCriterion;
 import org.apache.geode.CancelException;
 import org.apache.geode.ForcedDisconnectException;
@@ -177,6 +174,7 @@ import org.apache.geode.internal.SystemTimer;
 import org.apache.geode.internal.cache.control.InternalResourceManager;
 import org.apache.geode.internal.cache.control.InternalResourceManager.ResourceType;
 import org.apache.geode.internal.cache.control.ResourceAdvisor;
+import org.apache.geode.internal.cache.event.EventTrackerExpiryTask;
 import org.apache.geode.internal.cache.execute.util.FindRestEnabledServersFunction;
 import org.apache.geode.internal.cache.extension.Extensible;
 import org.apache.geode.internal.cache.extension.ExtensionPoint;
@@ -204,6 +202,7 @@ import org.apache.geode.internal.cache.xmlcache.CacheXmlParser;
 import org.apache.geode.internal.cache.xmlcache.CacheXmlPropertyResolver;
 import org.apache.geode.internal.cache.xmlcache.PropertyResolver;
 import org.apache.geode.internal.concurrent.ConcurrentHashSet;
+import org.apache.geode.internal.config.ClusterConfigurationNotAvailableException;
 import org.apache.geode.internal.i18n.LocalizedStrings;
 import org.apache.geode.internal.jndi.JNDIInvoker;
 import org.apache.geode.internal.jta.TransactionManagerImpl;
@@ -213,8 +212,8 @@ import org.apache.geode.internal.logging.LoggingThreadGroup;
 import org.apache.geode.internal.logging.log4j.LocalizedMessage;
 import org.apache.geode.internal.net.SocketCreator;
 import org.apache.geode.internal.offheap.MemoryAllocator;
-import org.apache.geode.internal.process.ClusterConfigurationNotAvailableException;
 import org.apache.geode.internal.security.SecurityService;
+import org.apache.geode.internal.security.SecurityServiceFactory;
 import org.apache.geode.internal.sequencelog.SequenceLoggerImpl;
 import org.apache.geode.internal.tcp.ConnectionTable;
 import org.apache.geode.internal.util.concurrent.FutureResult;

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/config/ClusterConfigurationNotAvailableException.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/config/ClusterConfigurationNotAvailableException.java b/geode-core/src/main/java/org/apache/geode/internal/config/ClusterConfigurationNotAvailableException.java
new file mode 100644
index 0000000..b22f13f
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/config/ClusterConfigurationNotAvailableException.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.config;
+
+/**
+ * Exception thrown during server startup when it requests the locators for shared configuration and
+ * does not receive it.
+ */
+public class ClusterConfigurationNotAvailableException
+    extends org.apache.geode.internal.process.ClusterConfigurationNotAvailableException {
+
+  private static final long serialVersionUID = 771319836094239284L;
+
+  public ClusterConfigurationNotAvailableException(final String message) {
+    super(message);
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/io/TeePrintStream.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/io/TeePrintStream.java b/geode-core/src/main/java/org/apache/geode/internal/io/TeePrintStream.java
index 3f36244..4b35ce5 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/io/TeePrintStream.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/io/TeePrintStream.java
@@ -34,7 +34,7 @@ public class TeePrintStream extends PrintStream {
 
   @Override
   public String toString() {
-    final StringBuilder sb = new StringBuilder(getClass().getSimpleName());
+    StringBuilder sb = new StringBuilder(getClass().getSimpleName());
     sb.append("@").append(System.identityHashCode(this)).append("{");
     sb.append("teeOutputStream=").append(this.teeOut);
     return sb.append("}").toString();

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/AttachProcessUtils.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/AttachProcessUtils.java b/geode-core/src/main/java/org/apache/geode/internal/process/AttachProcessUtils.java
index 2103785..3b5da76 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/AttachProcessUtils.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/AttachProcessUtils.java
@@ -14,10 +14,13 @@
  */
 package org.apache.geode.internal.process;
 
-import org.apache.geode.internal.process.ProcessUtils.InternalProcessUtils;
+import static org.apache.commons.lang.Validate.isTrue;
+
 import com.sun.tools.attach.VirtualMachine;
 import com.sun.tools.attach.VirtualMachineDescriptor;
 
+import org.apache.geode.internal.process.ProcessUtils.InternalProcessUtils;
+
 /**
  * Implementation of the {@link ProcessUtils} SPI that uses the JDK Attach API.
  * 
@@ -25,10 +28,10 @@ import com.sun.tools.attach.VirtualMachineDescriptor;
  */
 class AttachProcessUtils implements InternalProcessUtils {
 
-  AttachProcessUtils() {}
-
   @Override
   public boolean isProcessAlive(final int pid) {
+    isTrue(pid > 0, "Invalid pid '" + pid + "' specified");
+
     for (VirtualMachineDescriptor vm : VirtualMachine.list()) {
       if (vm.id().equals(String.valueOf(pid))) {
         return true; // found the vm

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/BlockingProcessStreamReader.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/BlockingProcessStreamReader.java b/geode-core/src/main/java/org/apache/geode/internal/process/BlockingProcessStreamReader.java
index 9d2b497..62bded4 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/BlockingProcessStreamReader.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/BlockingProcessStreamReader.java
@@ -14,9 +14,11 @@
  */
 package org.apache.geode.internal.process;
 
+import static org.apache.commons.lang.SystemUtils.LINE_SEPARATOR;
+
 import java.io.BufferedReader;
-import java.io.IOException;
 import java.io.InputStreamReader;
+import java.io.UncheckedIOException;
 
 import org.apache.logging.log4j.Logger;
 
@@ -39,32 +41,11 @@ public class BlockingProcessStreamReader extends ProcessStreamReader {
 
   @Override
   public void run() {
-    final boolean isDebugEnabled = logger.isDebugEnabled();
-    if (isDebugEnabled) {
-      logger.debug("Running {}", this);
-    }
-    BufferedReader reader = null;
     try {
-      reader = new BufferedReader(new InputStreamReader(inputStream));
-      String line;
-      while ((line = reader.readLine()) != null) {
-        this.inputListener.notifyInputLine(line);
-      }
-    } catch (IOException e) {
-      if (isDebugEnabled) {
-        logger.debug("Failure reading from buffered input stream: {}", e.getMessage(), e);
-      }
-    } finally {
-      try {
-        reader.close();
-      } catch (IOException e) {
-        if (isDebugEnabled) {
-          logger.debug("Failure closing buffered input stream reader: {}", e.getMessage(), e);
-        }
-      }
-      if (isDebugEnabled) {
-        logger.debug("Terminating {}", this);
-      }
+      new BufferedReader(new InputStreamReader(inputStream)).lines()
+          .map(line -> line + LINE_SEPARATOR).forEach(this.inputListener::notifyInputLine);
+    } catch (UncheckedIOException e) {
+      logger.debug(e);
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ClusterConfigurationNotAvailableException.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ClusterConfigurationNotAvailableException.java b/geode-core/src/main/java/org/apache/geode/internal/process/ClusterConfigurationNotAvailableException.java
index 7699cc4..981c460 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/process/ClusterConfigurationNotAvailableException.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/ClusterConfigurationNotAvailableException.java
@@ -17,10 +17,14 @@ package org.apache.geode.internal.process;
 /**
  * Exception thrown during server startup when it requests the locators for shared configuration and
  * does not receive it.
- * 
+ *
  * @since GemFire 8.0
+ * @deprecated Please use
+ *             {@link org.apache.geode.internal.config.ClusterConfigurationNotAvailableException}
+ *             instead.
  */
-public class ClusterConfigurationNotAvailableException extends RuntimeException {
+@Deprecated
+public class ClusterConfigurationNotAvailableException extends Exception {
   private static final long serialVersionUID = -3448160213553925462L;
 
   public ClusterConfigurationNotAvailableException(String message) {

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ConnectionFailedException.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ConnectionFailedException.java b/geode-core/src/main/java/org/apache/geode/internal/process/ConnectionFailedException.java
index 0c04130..52d7cc7 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/ConnectionFailedException.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/ConnectionFailedException.java
@@ -23,23 +23,23 @@ public class ConnectionFailedException extends Exception {
   private static final long serialVersionUID = 5622636452836752700L;
 
   /**
-   * Creates a new <code>ConnectionFailedException</code>.
+   * Creates a new {@code ConnectionFailedException}.
    */
   public ConnectionFailedException(final String message) {
     super(message);
   }
 
   /**
-   * Creates a new <code>ConnectionFailedException</code> that was caused by a given exception
+   * Creates a new {@code ConnectionFailedException} that was caused by a given exception
    */
-  public ConnectionFailedException(final String message, final Throwable thr) {
-    super(message, thr);
+  public ConnectionFailedException(final String message, final Throwable cause) {
+    super(message, cause);
   }
 
   /**
-   * Creates a new <code>ConnectionFailedException</code> that was caused by a given exception
+   * Creates a new {@code ConnectionFailedException} that was caused by a given exception
    */
-  public ConnectionFailedException(final Throwable thr) {
-    super(thr.getMessage(), thr);
+  public ConnectionFailedException(final Throwable cause) {
+    super(cause.getMessage(), cause);
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ControlFileWatchdog.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ControlFileWatchdog.java b/geode-core/src/main/java/org/apache/geode/internal/process/ControlFileWatchdog.java
index 0af8758..efebe70 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/ControlFileWatchdog.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/ControlFileWatchdog.java
@@ -14,6 +14,9 @@
  */
 package org.apache.geode.internal.process;
 
+import static org.apache.commons.lang.Validate.notEmpty;
+import static org.apache.commons.lang.Validate.notNull;
+
 import java.io.File;
 import java.io.IOException;
 
@@ -30,74 +33,83 @@ class ControlFileWatchdog implements Runnable {
   private static final Logger logger = LogService.getLogger();
 
   private static final long STOP_TIMEOUT_MILLIS = 60 * 1000;
-  private static final long SLEEP_MILLIS = 1000;
+  private static final long LOOP_INTERVAL_MILLIS = 1000;
 
-  private final File workingDir;
+  private final File directory;
   private final File file;
   private final ControlRequestHandler requestHandler;
   private final boolean stopAfterRequest;
+
   private Thread thread;
   private boolean alive;
 
-  ControlFileWatchdog(final File workingDir, final String fileName,
+  ControlFileWatchdog(final File directory, final String fileName,
       final ControlRequestHandler requestHandler, final boolean stopAfterRequest) {
-    this.workingDir = workingDir;
-    this.file = new File(this.workingDir, fileName);
+    notNull(directory, "Invalid directory '" + directory + "' specified");
+    notEmpty(fileName, "Invalid fileName '" + fileName + "' specified");
+    notNull(requestHandler, "Invalid requestHandler '" + requestHandler + "' specified");
+
+    this.directory = directory;
+    this.file = new File(directory, fileName);
     this.requestHandler = requestHandler;
     this.stopAfterRequest = stopAfterRequest;
   }
 
   @Override
   public void run() {
-    try { // always set this.alive before stopping
+    try { // always set alive before stopping
       while (isAlive()) {
-        try { // handle handle exceptions
-          Thread.sleep(SLEEP_MILLIS);
-          if (this.file.exists()) {
-            try { // always check stopAfterRequest after main work
-              work();
-            } finally {
-              if (this.stopAfterRequest) {
-                stopMe();
-              }
-            }
-          }
-        } catch (InterruptedException e) {
-          Thread.currentThread().interrupt();
-          // allow to loop around and check isAlive()
-        } catch (IOException e) {
-          logger.error(
-              "Unable to control process with {}. Please add tools.jar from JDK to classpath for improved process control.",
-              this.file);
-          // allow to loop around and check isAlive()
-        }
+        doWork();
       }
     } finally {
       synchronized (this) {
-        this.alive = false;
+        alive = false;
+      }
+    }
+  }
+
+  private void doWork() {
+    try { // handle handle exceptions
+      if (file.exists()) {
+        try { // always check stopAfterRequest after handleRequest
+          handleRequest();
+        } finally {
+          if (stopAfterRequest) {
+            stopMe();
+          }
+        }
       }
+      Thread.sleep(LOOP_INTERVAL_MILLIS);
+    } catch (InterruptedException ignored) {
+      Thread.currentThread().interrupt();
+      // allow to loop around and check isAlive()
+    } catch (IOException ignored) {
+      logger.error(
+          "Unable to control process with {}. Please add tools.jar from JDK to classpath for improved process control.",
+          file);
+      // allow to loop around and check isAlive()
     }
   }
 
-  private void work() throws IOException {
+  private void handleRequest() throws IOException {
     try { // always delete file after invoking handler
-      this.requestHandler.handleRequest();
+      requestHandler.handleRequest();
     } finally {
       try {
-        this.file.delete();
+        file.delete();
       } catch (SecurityException e) {
-        logger.warn("Unable to delete {}", this.file, e);
+        logger.warn("Unable to delete {}", file, e);
       }
     }
   }
 
   void start() {
     synchronized (this) {
-      if (this.thread == null) {
-        this.thread = new Thread(this, createThreadName());
-        this.thread.setDaemon(true);
-        this.alive = true;
-        this.thread.start();
+      if (thread == null) {
+        thread = new Thread(this, createThreadName());
+        thread.setDaemon(true);
+        alive = true;
+        thread.start();
       }
     }
   }
@@ -105,13 +117,13 @@ class ControlFileWatchdog implements Runnable {
   void stop() throws InterruptedException {
     Thread stopping = null;
     synchronized (this) {
-      if (this.thread != null) {
-        this.alive = false;
-        if (this.thread != Thread.currentThread()) {
-          this.thread.interrupt();
-          stopping = this.thread;
+      if (thread != null) {
+        alive = false;
+        if (thread != Thread.currentThread()) {
+          thread.interrupt();
+          stopping = thread;
         }
-        this.thread = null;
+        thread = null;
       }
     }
     if (stopping != null) {
@@ -121,39 +133,39 @@ class ControlFileWatchdog implements Runnable {
 
   boolean isAlive() {
     synchronized (this) {
-      return this.alive;
+      return alive;
     }
   }
 
   private void stopMe() {
     synchronized (this) {
-      if (this.thread != null) {
-        this.alive = false;
-        this.thread = null;
+      if (thread != null) {
+        alive = false;
+        thread = null;
       }
     }
   }
 
   @Override
   public String toString() {
-    final StringBuilder sb = new StringBuilder(getClass().getSimpleName());
-    sb.append("@").append(System.identityHashCode(this)).append("{");
-    sb.append("workingDir=").append(this.workingDir);
-    sb.append(", file=").append(this.file);
-    sb.append(", alive=").append(this.alive);
-    sb.append(", stopAfterRequest=").append(this.stopAfterRequest);
-    return sb.append("}").toString();
+    StringBuilder sb = new StringBuilder(getClass().getSimpleName());
+    sb.append('@').append(System.identityHashCode(this)).append('{');
+    sb.append("directory=").append(directory);
+    sb.append(", file=").append(file);
+    sb.append(", alive=").append(alive); // not synchronized
+    sb.append(", stopAfterRequest=").append(stopAfterRequest);
+    return sb.append('}').toString();
   }
 
   private String createThreadName() {
-    return getClass().getSimpleName() + "@" + Integer.toHexString(hashCode()) + " monitoring "
-        + this.file.getName();
+    return getClass().getSimpleName() + '@' + Integer.toHexString(hashCode()) + " monitoring "
+        + file.getName();
   }
 
   /**
    * Defines the callback to be invoked when the control file exists.
    */
   interface ControlRequestHandler {
-    public void handleRequest() throws IOException;
+    void handleRequest() throws IOException;
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ControlNotificationHandler.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ControlNotificationHandler.java b/geode-core/src/main/java/org/apache/geode/internal/process/ControlNotificationHandler.java
index 246c1e8..a49d3a6 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/ControlNotificationHandler.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/ControlNotificationHandler.java
@@ -24,7 +24,8 @@ import org.apache.geode.distributed.AbstractLauncher.ServiceState;
  * @since GemFire 8.0
  */
 public interface ControlNotificationHandler {
-  public void handleStop();
 
-  public ServiceState<?> handleStatus();
+  void handleStop();
+
+  ServiceState<?> handleStatus();
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ControllableProcess.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ControllableProcess.java b/geode-core/src/main/java/org/apache/geode/internal/process/ControllableProcess.java
index 7641ed3..2fdd116 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/ControllableProcess.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/ControllableProcess.java
@@ -14,6 +14,8 @@
  */
 package org.apache.geode.internal.process;
 
+import static org.apache.commons.lang.Validate.notNull;
+
 import java.io.File;
 import java.io.FileWriter;
 import java.io.IOException;
@@ -25,65 +27,54 @@ import org.apache.geode.internal.logging.LogService;
 import org.apache.geode.internal.process.ControlFileWatchdog.ControlRequestHandler;
 
 /**
- * Exists inside a process launched by ServerLauncher or LocatorLauncher. Creates the PID file and
- * ControlFileWatchdogs to monitor working directory for creation of stop or status request files.
+ * Creates the {@link PidFile} and uses {@link ControlFileWatchdog} to monitor the directory for
+ * creation of stop or status request files.
  * 
  * @since GemFire 8.0
  */
 public class ControllableProcess {
   private static final Logger logger = LogService.getLogger();
 
-  private final File workingDir;
-  private final File pidFile;
+  private final File directory;
   private final LocalProcessLauncher launcher;
   private final ControlFileWatchdog stopRequestFileWatchdog;
   private final ControlFileWatchdog statusRequestFileWatchdog;
 
-  public ControllableProcess(final ControlNotificationHandler handler, final File workingDir,
-      final ProcessType processType, boolean force)
+  public ControllableProcess(final ControlNotificationHandler handler, final File directory,
+      final ProcessType processType, final boolean force)
       throws FileAlreadyExistsException, IOException, PidUnavailableException {
-    this.workingDir = workingDir;
-    this.pidFile = new File(this.workingDir, processType.getPidFileName());
-
-    deleteFiles(this.workingDir, processType);
-
-    this.launcher = new LocalProcessLauncher(this.pidFile, force);
+    this(directory, processType, force, createPidFile(directory, processType),
+        createStopHandler(handler), createStatusHandler(handler, directory, processType));
+  }
 
-    final ControlRequestHandler stopHandler = new ControlRequestHandler() {
-      @Override
-      public void handleRequest() {
-        handler.handleStop();
-      }
-    };
-    final ControlRequestHandler statusHandler = new ControlRequestHandler() {
-      @Override
-      public void handleRequest() throws IOException {
-        final ServiceState<?> state = handler.handleStatus();
-        final File statusFile = new File(workingDir, processType.getStatusFileName());
-        if (statusFile.exists()) {
-          statusFile.delete();
-        }
-        final File statusFileTmp = new File(workingDir, processType.getStatusFileName() + ".tmp");
-        if (statusFileTmp.exists()) {
-          statusFileTmp.delete();
-        }
-        boolean created = statusFileTmp.createNewFile();
-        assert created;
-        final FileWriter writer = new FileWriter(statusFileTmp);
-        writer.write(state.toJson());
-        writer.flush();
-        writer.close();
-        boolean renamed = statusFileTmp.renameTo(statusFile);
-        assert renamed;
-      }
-    };
+  private ControllableProcess(final File directory, final ProcessType processType,
+      final boolean force, final File pidFile, final ControlRequestHandler stopHandler,
+      final ControlRequestHandler statusHandler)
+      throws FileAlreadyExistsException, IOException, PidUnavailableException {
+    this(directory, processType, createLocalProcessLauncher(pidFile, force),
+        createStopRequestFileWatchdog(directory, processType, stopHandler),
+        createStatusRequestFileWatchdog(directory, processType, statusHandler));
+  }
 
-    this.stopRequestFileWatchdog = new ControlFileWatchdog(workingDir,
-        processType.getStopRequestFileName(), stopHandler, false);
-    this.stopRequestFileWatchdog.start();
-    this.statusRequestFileWatchdog = new ControlFileWatchdog(workingDir,
-        processType.getStatusRequestFileName(), statusHandler, false);
-    this.statusRequestFileWatchdog.start();
+  ControllableProcess(final File directory, final ProcessType processType,
+      final LocalProcessLauncher launcher, final ControlFileWatchdog stopRequestFileWatchdog,
+      final ControlFileWatchdog statusRequestFileWatchdog) {
+    notNull(directory, "Invalid directory '" + directory + "' specified");
+    notNull(processType, "Invalid processType '" + processType + "' specified");
+    notNull(launcher, "Invalid launcher '" + launcher + "' specified");
+    notNull(stopRequestFileWatchdog,
+        "Invalid stopRequestFileWatchdog '" + stopRequestFileWatchdog + "' specified");
+    notNull(statusRequestFileWatchdog,
+        "Invalid statusRequestFileWatchdog '" + statusRequestFileWatchdog + "' specified");
+
+    this.directory = directory;
+    this.launcher = launcher;
+    this.stopRequestFileWatchdog = stopRequestFileWatchdog;
+    this.statusRequestFileWatchdog = statusRequestFileWatchdog;
+
+    deleteFiles(directory, processType);
+    stopRequestFileWatchdog.start();
+    statusRequestFileWatchdog.start();
   }
 
   /**
@@ -92,7 +83,7 @@ public class ControllableProcess {
    * @return the process id (PID)
    */
   public int getPid() {
-    return this.launcher.getPid();
+    return launcher.getPid();
   }
 
   /**
@@ -101,38 +92,115 @@ public class ControllableProcess {
    * @return the PID file
    */
   public File getPidFile() {
-    return this.launcher.getPidFile();
+    return launcher.getPidFile();
+  }
+
+  public File getDirectory() {
+    return directory;
   }
 
   public void stop() {
+    boolean interrupted = false;
     try {
-      this.statusRequestFileWatchdog.stop();
-    } catch (InterruptedException e) {
-      logger.warn("Interrupted while stopping status handler for controllable process.", e);
+      interrupted = stop(statusRequestFileWatchdog);
+      interrupted = stop(stopRequestFileWatchdog) || interrupted;
+      launcher.close();
     } finally {
-      try {
-        this.stopRequestFileWatchdog.stop();
-      } catch (InterruptedException e) {
-        logger.warn("Interrupted while stopping stop handler for controllable process.", e);
+      if (interrupted) {
+        Thread.currentThread().interrupt();
       }
-      this.launcher.close();
     }
   }
 
-  protected File getWorkingDir() {
-    return this.workingDir;
+  public void stop(final boolean deletePidFileOnStop) {
+    boolean interrupted = false;
+    try {
+      interrupted = stop(statusRequestFileWatchdog);
+      interrupted = stop(stopRequestFileWatchdog) || interrupted;
+      launcher.close(deletePidFileOnStop);
+    } finally {
+      if (interrupted) {
+        Thread.currentThread().interrupt();
+      }
+    }
+  }
+
+  private boolean stop(final ControlFileWatchdog fileWatchdog) {
+    boolean interrupted = false;
+    try {
+      fileWatchdog.stop();
+    } catch (InterruptedException e) {
+      interrupted = true;
+      logger.warn("Interrupted while stopping status handler for controllable process.", e);
+    }
+    return interrupted;
   }
 
-  private static void deleteFiles(final File workingDir, final ProcessType processType) {
-    deleteFile(workingDir, processType.getStatusRequestFileName());
-    deleteFile(workingDir, processType.getStatusFileName());
-    deleteFile(workingDir, processType.getStopRequestFileName());
+  private void deleteFiles(final File directory, final ProcessType processType) {
+    deleteFile(directory, processType.getStatusRequestFileName());
+    deleteFile(directory, processType.getStatusFileName());
+    deleteFile(directory, processType.getStopRequestFileName());
   }
 
-  private static void deleteFile(final File workingDir, final String fileName) {
-    final File file = new File(workingDir, fileName);
+  private void deleteFile(final File directory, final String fileName) {
+    File file = new File(directory, fileName);
     if (file.exists()) {
       file.delete();
     }
   }
+
+  private static File createPidFile(final File directory, final ProcessType processType) {
+    return new File(directory, processType.getPidFileName());
+  }
+
+  private static LocalProcessLauncher createLocalProcessLauncher(final File pidFile,
+      final boolean force) throws FileAlreadyExistsException, IOException, PidUnavailableException {
+    return new LocalProcessLauncher(pidFile, force);
+  }
+
+  private static ControlRequestHandler createStopHandler(final ControlNotificationHandler handler) {
+    return handler::handleStop;
+  }
+
+  private static ControlRequestHandler createStatusHandler(final ControlNotificationHandler handler,
+      final File directory, final ProcessType processType) {
+    return () -> {
+      ServiceState<?> state = handler.handleStatus();
+
+      File statusFile = new File(directory, processType.getStatusFileName());
+      if (statusFile.exists()) {
+        boolean deleted = statusFile.delete();
+        assert deleted;
+      }
+
+      File statusFileTmp = new File(directory, processType.getStatusFileName() + ".tmp");
+      if (statusFileTmp.exists()) {
+        boolean deleted = statusFileTmp.delete();
+        assert deleted;
+      }
+
+      boolean created = statusFileTmp.createNewFile();
+      assert created;
+
+      FileWriter writer = new FileWriter(statusFileTmp);
+      writer.write(state.toJson());
+      writer.flush();
+      writer.close();
+
+      boolean renamed = statusFileTmp.renameTo(statusFile);
+      assert renamed;
+    };
+  }
+
+  private static ControlFileWatchdog createStopRequestFileWatchdog(final File directory,
+      final ProcessType processType, final ControlRequestHandler stopHandler) {
+    return new ControlFileWatchdog(directory, processType.getStopRequestFileName(), stopHandler,
+        false);
+  }
+
+  private static ControlFileWatchdog createStatusRequestFileWatchdog(final File directory,
+      final ProcessType processType, final ControlRequestHandler statusHandler) {
+    return new ControlFileWatchdog(directory, processType.getStatusRequestFileName(), statusHandler,
+        false);
+  }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/FileAlreadyExistsException.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/FileAlreadyExistsException.java b/geode-core/src/main/java/org/apache/geode/internal/process/FileAlreadyExistsException.java
index 4bb6d57..19be21d 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/FileAlreadyExistsException.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/FileAlreadyExistsException.java
@@ -24,23 +24,23 @@ public class FileAlreadyExistsException extends Exception {
   private static final long serialVersionUID = 5471082555536094256L;
 
   /**
-   * Creates a new <code>FileAlreadyExistsException</code>.
+   * Creates a new {@code FileAlreadyExistsException}.
    */
   public FileAlreadyExistsException(final String message) {
     super(message);
   }
 
   /**
-   * Creates a new <code>FileAlreadyExistsException</code> that was caused by a given exception
+   * Creates a new {@code FileAlreadyExistsException} that was caused by a given exception
    */
-  public FileAlreadyExistsException(final String message, final Throwable thr) {
-    super(message, thr);
+  public FileAlreadyExistsException(final String message, final Throwable cause) {
+    super(message, cause);
   }
 
   /**
-   * Creates a new <code>FileAlreadyExistsException</code> that was caused by a given exception
+   * Creates a new {@code FileAlreadyExistsException} that was caused by a given exception
    */
-  public FileAlreadyExistsException(final Throwable thr) {
-    super(thr.getMessage(), thr);
+  public FileAlreadyExistsException(final Throwable cause) {
+    super(cause.getMessage(), cause);
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/FileControllerParameters.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/FileControllerParameters.java b/geode-core/src/main/java/org/apache/geode/internal/process/FileControllerParameters.java
index 0beb9ff..d181894 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/FileControllerParameters.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/FileControllerParameters.java
@@ -25,7 +25,8 @@ import org.apache.geode.internal.process.ProcessController.Arguments;
  * @since GemFire 8.0
  */
 interface FileControllerParameters extends Arguments {
-  public File getPidFile();
 
-  public File getWorkingDirectory();
+  File getPidFile();
+
+  File getDirectory();
 }