http://git-wip-us.apache.org/repos/asf/geode/blob/fcce2b0b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartLocatorCommand.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartLocatorCommand.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartLocatorCommand.java
new file mode 100644
index 0000000..10dc0db
--- /dev/null
+++ 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartLocatorCommand.java
@@ -0,0 +1,546 @@
+/*
+ * 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.management.internal.cli.commands;
+
+import java.io.File;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.MalformedObjectNameException;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+
+import org.apache.geode.SystemFailure;
+import org.apache.geode.distributed.AbstractLauncher;
+import org.apache.geode.distributed.ConfigurationProperties;
+import org.apache.geode.distributed.LocatorLauncher;
+import org.apache.geode.distributed.ServerLauncher;
+import org.apache.geode.internal.OSProcess;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+import org.apache.geode.internal.lang.StringUtils;
+import org.apache.geode.internal.lang.SystemUtils;
+import org.apache.geode.internal.process.ProcessStreamReader;
+import org.apache.geode.internal.process.ProcessType;
+import org.apache.geode.internal.util.IOUtils;
+import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.ConverterHint;
+import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.internal.cli.CliUtil;
+import org.apache.geode.management.internal.cli.GfshParser;
+import org.apache.geode.management.internal.cli.LogWrapper;
+import org.apache.geode.management.internal.cli.domain.ConnectToLocatorResult;
+import org.apache.geode.management.internal.cli.i18n.CliStrings;
+import org.apache.geode.management.internal.cli.result.InfoResultData;
+import org.apache.geode.management.internal.cli.result.ResultBuilder;
+import org.apache.geode.management.internal.cli.shell.Gfsh;
+import org.apache.geode.management.internal.cli.shell.JmxOperationInvoker;
+import org.apache.geode.management.internal.cli.util.CauseFinder;
+import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
+import org.apache.geode.management.internal.cli.util.ConnectionEndpoint;
+import org.apache.geode.management.internal.cli.util.HostUtils;
+import 
org.apache.geode.management.internal.configuration.utils.ClusterConfigurationStatusRetriever;
+import org.apache.geode.security.AuthenticationFailedException;
+
+public class StartLocatorCommand implements GfshCommand {
+  @CliCommand(value = CliStrings.START_LOCATOR, help = 
CliStrings.START_LOCATOR__HELP)
+  @CliMetaData(shellOnly = true,
+      relatedTopic = {CliStrings.TOPIC_GEODE_LOCATOR, 
CliStrings.TOPIC_GEODE_LIFECYCLE})
+  public Result startLocator(
+      @CliOption(key = CliStrings.START_LOCATOR__MEMBER_NAME,
+          help = CliStrings.START_LOCATOR__MEMBER_NAME__HELP) String 
memberName,
+      @CliOption(key = CliStrings.START_LOCATOR__BIND_ADDRESS,
+          help = CliStrings.START_LOCATOR__BIND_ADDRESS__HELP) final String 
bindAddress,
+      @CliOption(key = CliStrings.START_LOCATOR__CLASSPATH,
+          help = CliStrings.START_LOCATOR__CLASSPATH__HELP) final String 
classpath,
+      @CliOption(key = CliStrings.START_LOCATOR__FORCE, 
unspecifiedDefaultValue = "false",
+          specifiedDefaultValue = "true",
+          help = CliStrings.START_LOCATOR__FORCE__HELP) final Boolean force,
+      @CliOption(key = {CliStrings.GROUP, CliStrings.GROUPS},
+          optionContext = ConverterHint.MEMBERGROUP,
+          help = CliStrings.START_LOCATOR__GROUP__HELP) final String group,
+      @CliOption(key = CliStrings.START_LOCATOR__HOSTNAME_FOR_CLIENTS,
+          help = CliStrings.START_LOCATOR__HOSTNAME_FOR_CLIENTS__HELP) final 
String hostnameForClients,
+      @CliOption(key = 
ConfigurationProperties.JMX_MANAGER_HOSTNAME_FOR_CLIENTS,
+          help = 
CliStrings.START_LOCATOR__JMX_MANAGER_HOSTNAME_FOR_CLIENTS__HELP) final String 
jmxManagerHostnameForClients,
+      @CliOption(key = CliStrings.START_LOCATOR__INCLUDE_SYSTEM_CLASSPATH,
+          specifiedDefaultValue = "true", unspecifiedDefaultValue = "false",
+          help = CliStrings.START_LOCATOR__INCLUDE_SYSTEM_CLASSPATH__HELP) 
final Boolean includeSystemClasspath,
+      @CliOption(key = CliStrings.START_LOCATOR__LOCATORS,
+          optionContext = ConverterHint.LOCATOR_DISCOVERY_CONFIG,
+          help = CliStrings.START_LOCATOR__LOCATORS__HELP) final String 
locators,
+      @CliOption(key = CliStrings.START_LOCATOR__LOG_LEVEL, optionContext = 
ConverterHint.LOG_LEVEL,
+          help = CliStrings.START_LOCATOR__LOG_LEVEL__HELP) final String 
logLevel,
+      @CliOption(key = CliStrings.START_LOCATOR__MCAST_ADDRESS,
+          help = CliStrings.START_LOCATOR__MCAST_ADDRESS__HELP) final String 
mcastBindAddress,
+      @CliOption(key = CliStrings.START_LOCATOR__MCAST_PORT,
+          help = CliStrings.START_LOCATOR__MCAST_PORT__HELP) final Integer 
mcastPort,
+      @CliOption(key = CliStrings.START_LOCATOR__PORT,
+          help = CliStrings.START_LOCATOR__PORT__HELP) final Integer port,
+      @CliOption(key = CliStrings.START_LOCATOR__DIR,
+          help = CliStrings.START_LOCATOR__DIR__HELP) String workingDirectory,
+      @CliOption(key = CliStrings.START_LOCATOR__PROPERTIES,
+          optionContext = ConverterHint.FILE_PATH,
+          help = CliStrings.START_LOCATOR__PROPERTIES__HELP) String 
gemfirePropertiesPathname,
+      @CliOption(key = CliStrings.START_LOCATOR__SECURITY_PROPERTIES,
+          optionContext = ConverterHint.FILE_PATH,
+          help = CliStrings.START_LOCATOR__SECURITY_PROPERTIES__HELP) String 
gemfireSecurityPropertiesPathname,
+      @CliOption(key = CliStrings.START_LOCATOR__INITIALHEAP,
+          help = CliStrings.START_LOCATOR__INITIALHEAP__HELP) final String 
initialHeap,
+      @CliOption(key = CliStrings.START_LOCATOR__MAXHEAP,
+          help = CliStrings.START_LOCATOR__MAXHEAP__HELP) final String maxHeap,
+      @CliOption(key = CliStrings.START_LOCATOR__J, optionContext = 
GfshParser.J_OPTION_CONTEXT,
+          help = CliStrings.START_LOCATOR__J__HELP) final String[] jvmArgsOpts,
+      @CliOption(key = CliStrings.START_LOCATOR__CONNECT, 
unspecifiedDefaultValue = "true",
+          specifiedDefaultValue = "true",
+          help = CliStrings.START_LOCATOR__CONNECT__HELP) final boolean 
connect,
+      @CliOption(key = CliStrings.START_LOCATOR__ENABLE__SHARED__CONFIGURATION,
+          unspecifiedDefaultValue = "true", specifiedDefaultValue = "true",
+          help = 
CliStrings.START_LOCATOR__ENABLE__SHARED__CONFIGURATION__HELP) final boolean 
enableSharedConfiguration,
+      @CliOption(key = 
CliStrings.START_LOCATOR__LOAD__SHARED_CONFIGURATION__FROM__FILESYSTEM,
+          unspecifiedDefaultValue = "false",
+          help = 
CliStrings.START_LOCATOR__LOAD__SHARED_CONFIGURATION__FROM__FILESYSTEM__HELP) 
final boolean loadSharedConfigurationFromDirectory,
+      @CliOption(key = CliStrings.START_LOCATOR__CLUSTER__CONFIG__DIR, 
unspecifiedDefaultValue = "",
+          help = CliStrings.START_LOCATOR__CLUSTER__CONFIG__DIR__HELP) final 
String clusterConfigDir,
+      @CliOption(key = CliStrings.START_LOCATOR__HTTP_SERVICE_PORT,
+          help = CliStrings.START_LOCATOR__HTTP_SERVICE_PORT__HELP) final 
Integer httpServicePort,
+      @CliOption(key = CliStrings.START_LOCATOR__HTTP_SERVICE_BIND_ADDRESS,
+          help = CliStrings.START_LOCATOR__HTTP_SERVICE_BIND_ADDRESS__HELP) 
final String httpServiceBindAddress) {
+    try {
+      if (StringUtils.isBlank(memberName)) {
+        // when the user doesn't give us a name, we make one up!
+        memberName = StartMemberUtils.getNameGenerator().generate('-');
+      }
+
+      workingDirectory = StartMemberUtils.resolveWorkingDir(workingDirectory, 
memberName);
+
+      gemfirePropertiesPathname = 
CliUtil.resolvePathname(gemfirePropertiesPathname);
+
+      if (StringUtils.isNotBlank(gemfirePropertiesPathname)
+          && !IOUtils.isExistingPathname(gemfirePropertiesPathname)) {
+        return ResultBuilder.createUserErrorResult(
+            
CliStrings.format(CliStrings.GEODE_0_PROPERTIES_1_NOT_FOUND_MESSAGE, 
StringUtils.EMPTY,
+                gemfirePropertiesPathname));
+      }
+
+      gemfireSecurityPropertiesPathname =
+          CliUtil.resolvePathname(gemfireSecurityPropertiesPathname);
+
+      if (StringUtils.isNotBlank(gemfireSecurityPropertiesPathname)
+          && !IOUtils.isExistingPathname(gemfireSecurityPropertiesPathname)) {
+        return ResultBuilder.createUserErrorResult(
+            
CliStrings.format(CliStrings.GEODE_0_PROPERTIES_1_NOT_FOUND_MESSAGE, "Security 
",
+                gemfireSecurityPropertiesPathname));
+      }
+
+      File locatorPidFile = new File(workingDirectory, 
ProcessType.LOCATOR.getPidFileName());
+
+      final int oldPid = StartMemberUtils.readPid(locatorPidFile);
+
+      Properties gemfireProperties = new Properties();
+
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties, 
ConfigurationProperties.GROUPS,
+          group);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties, 
ConfigurationProperties.LOCATORS,
+          locators);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties, 
ConfigurationProperties.LOG_LEVEL,
+          logLevel);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.MCAST_ADDRESS, mcastBindAddress);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties, 
ConfigurationProperties.MCAST_PORT,
+          mcastPort);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION, 
enableSharedConfiguration);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.LOAD_CLUSTER_CONFIGURATION_FROM_DIR,
+          loadSharedConfigurationFromDirectory);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.CLUSTER_CONFIGURATION_DIR, clusterConfigDir);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.HTTP_SERVICE_PORT, httpServicePort);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.HTTP_SERVICE_BIND_ADDRESS, 
httpServiceBindAddress);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.JMX_MANAGER_HOSTNAME_FOR_CLIENTS, 
jmxManagerHostnameForClients);
+
+      // read the OSProcess enable redirect system property here
+      // TODO: replace with new GFSH argument
+      final boolean redirectOutput =
+          Boolean.getBoolean(OSProcess.ENABLE_OUTPUT_REDIRECTION_PROPERTY);
+      LocatorLauncher.Builder locatorLauncherBuilder =
+          new 
LocatorLauncher.Builder().setBindAddress(bindAddress).setForce(force).setPort(port)
+              
.setRedirectOutput(redirectOutput).setWorkingDirectory(workingDirectory);
+      if (hostnameForClients != null) {
+        locatorLauncherBuilder.setHostnameForClients(hostnameForClients);
+      }
+      if (memberName != null) {
+        locatorLauncherBuilder.setMemberName(memberName);
+      }
+      LocatorLauncher locatorLauncher = locatorLauncherBuilder.build();
+
+      String[] locatorCommandLine = 
createStartLocatorCommandLine(locatorLauncher,
+          gemfirePropertiesPathname, gemfireSecurityPropertiesPathname, 
gemfireProperties,
+          classpath, includeSystemClasspath, jvmArgsOpts, initialHeap, 
maxHeap);
+
+      final Process locatorProcess = new ProcessBuilder(locatorCommandLine)
+          .directory(new File(locatorLauncher.getWorkingDirectory())).start();
+
+      locatorProcess.getInputStream().close();
+      locatorProcess.getOutputStream().close();
+
+      // fix TRAC bug #51967 by using NON_BLOCKING on Windows
+      final ProcessStreamReader.ReadingMode readingMode = 
SystemUtils.isWindows()
+          ? ProcessStreamReader.ReadingMode.NON_BLOCKING : 
ProcessStreamReader.ReadingMode.BLOCKING;
+
+      final StringBuffer message = new StringBuffer(); // need thread-safe 
StringBuffer
+      ProcessStreamReader.InputListener inputListener = line -> {
+        message.append(line);
+        if (readingMode == ProcessStreamReader.ReadingMode.BLOCKING) {
+          message.append(StringUtils.LINE_SEPARATOR);
+        }
+      };
+
+      ProcessStreamReader stderrReader = new 
ProcessStreamReader.Builder(locatorProcess)
+          
.inputStream(locatorProcess.getErrorStream()).inputListener(inputListener)
+          .readingMode(readingMode).continueReadingMillis(2 * 
1000).build().start();
+
+      LocatorLauncher.LocatorState locatorState;
+
+      String previousLocatorStatusMessage = null;
+
+      LauncherSignalListener locatorSignalListener = new 
LauncherSignalListener();
+
+      final boolean registeredLocatorSignalListener =
+          getGfsh().getSignalHandler().registerListener(locatorSignalListener);
+
+      try {
+        getGfsh().logInfo(String.format(CliStrings.START_LOCATOR__RUN_MESSAGE,
+            IOUtils.tryGetCanonicalPathElseGetAbsolutePath(
+                new File(locatorLauncher.getWorkingDirectory()))),
+            null);
+
+        locatorState = 
LocatorLauncher.LocatorState.fromDirectory(workingDirectory, memberName);
+        do {
+          if (locatorProcess.isAlive()) {
+            Gfsh.print(".");
+
+            synchronized (this) {
+              TimeUnit.MILLISECONDS.timedWait(this, 500);
+            }
+
+            locatorState = 
LocatorLauncher.LocatorState.fromDirectory(workingDirectory, memberName);
+
+            String currentLocatorStatusMessage = 
locatorState.getStatusMessage();
+
+            if (locatorState.isStartingOrNotResponding()
+                && !(StringUtils.isBlank(currentLocatorStatusMessage)
+                    || 
currentLocatorStatusMessage.equalsIgnoreCase(previousLocatorStatusMessage)
+                    || 
currentLocatorStatusMessage.trim().toLowerCase().equals("null"))) {
+              Gfsh.println();
+              Gfsh.println(currentLocatorStatusMessage);
+              previousLocatorStatusMessage = currentLocatorStatusMessage;
+            }
+          } else {
+            final int exitValue = locatorProcess.exitValue();
+
+            return ResultBuilder.createShellClientErrorResult(
+                
String.format(CliStrings.START_LOCATOR__PROCESS_TERMINATED_ABNORMALLY_ERROR_MESSAGE,
+                    exitValue, locatorLauncher.getWorkingDirectory(), 
message.toString()));
+          }
+        } while (!(registeredLocatorSignalListener && 
locatorSignalListener.isSignaled())
+            && locatorState.isStartingOrNotResponding());
+      } finally {
+        // stop will close
+        
stderrReader.stopAsync(StartMemberUtils.PROCESS_STREAM_READER_ASYNC_STOP_TIMEOUT_MILLIS);
+
+        // ErrorStream
+        getGfsh().getSignalHandler().unregisterListener(locatorSignalListener);
+      }
+
+      Gfsh.println();
+
+      final boolean asyncStart =
+          (registeredLocatorSignalListener && 
locatorSignalListener.isSignaled()
+              && 
ServerLauncher.ServerState.isStartingNotRespondingOrNull(locatorState));
+
+      InfoResultData infoResultData = ResultBuilder.createInfoResultData();
+
+      if (asyncStart) {
+        infoResultData.addLine(
+            String.format(CliStrings.ASYNC_PROCESS_LAUNCH_MESSAGE, 
CliStrings.LOCATOR_TERM_NAME));
+      } else {
+        infoResultData.addLine(locatorState.toString());
+
+        String locatorHostName;
+        InetAddress bindAddr = locatorLauncher.getBindAddress();
+        if (bindAddr != null) {
+          locatorHostName = bindAddr.getCanonicalHostName();
+        } else {
+          locatorHostName = 
StringUtils.defaultIfBlank(locatorLauncher.getHostnameForClients(),
+              HostUtils.getLocalHost());
+        }
+
+        int locatorPort = Integer.parseInt(locatorState.getPort());
+
+        // AUTO-CONNECT
+        // If the connect succeeds add the connected message to the result,
+        // Else, ask the user to use the "connect" command to connect to the 
Locator.
+        if (shouldAutoConnect(connect)) {
+          doAutoConnect(locatorHostName, locatorPort, 
gemfirePropertiesPathname,
+              gemfireSecurityPropertiesPathname, infoResultData);
+        }
+        // Report on the state of the Shared Configuration service if 
enabled...
+        if (enableSharedConfiguration) {
+          infoResultData.addLine(
+              ClusterConfigurationStatusRetriever.fromLocator(locatorHostName, 
locatorPort));
+        }
+      }
+      return ResultBuilder.buildResult(infoResultData);
+    } catch (IllegalArgumentException e) {
+      String message = e.getMessage();
+      if (message != null && message.matches(
+          
LocalizedStrings.Launcher_Builder_UNKNOWN_HOST_ERROR_MESSAGE.toLocalizedString(".+")))
 {
+        message =
+            
CliStrings.format(CliStrings.LAUNCHERLIFECYCLECOMMANDS__MSG__FAILED_TO_START_0_REASON_1,
+                CliStrings.LOCATOR_TERM_NAME, message);
+      }
+      return ResultBuilder.createUserErrorResult(message);
+    } catch (IllegalStateException e) {
+      return ResultBuilder.createUserErrorResult(e.getMessage());
+    } catch (VirtualMachineError e) {
+      SystemFailure.initiateFailure(e);
+      throw e;
+    } catch (Throwable t) {
+      SystemFailure.checkFailure();
+      String errorMessage = 
String.format(CliStrings.START_LOCATOR__GENERAL_ERROR_MESSAGE,
+          StringUtils.defaultIfBlank(workingDirectory, memberName),
+          HostUtils.getLocatorId(bindAddress, port), this.toString(t, 
getGfsh().getDebug()));
+      getGfsh().logToFile(errorMessage, t);
+      return ResultBuilder.createShellClientErrorResult(errorMessage);
+    } finally {
+      Gfsh.redirectInternalJavaLoggers();
+    }
+  }
+
+  // TODO should we connect implicitly when in non-interactive, headless mode 
(e.g. gfsh -e "start
+  // locator ...")?
+  // With execute option (-e), there could be multiple commands which might 
presume that a prior
+  // "start locator" has formed the connection.
+  private boolean shouldAutoConnect(final boolean connect) {
+    return (connect && !(getGfsh() == null || isConnectedAndReady()));
+  }
+
+  private void doAutoConnect(final String locatorHostname, final int 
locatorPort,
+      final String gemfirePropertiesPathname, final String 
gemfireSecurityPropertiesPathname,
+      final InfoResultData infoResultData) {
+    boolean connectSuccess = false;
+    boolean jmxManagerAuthEnabled = false;
+    boolean jmxManagerSslEnabled = false;
+
+    Map<String, String> configurationProperties = loadConfigurationProperties(
+        gemfireSecurityPropertiesPathname, 
loadConfigurationProperties(gemfirePropertiesPathname));
+    Map<String, String> locatorConfigurationProperties = new 
HashMap<>(configurationProperties);
+
+    String responseFailureMessage = null;
+
+    for (int attempts = 0; (attempts < 10 && !connectSuccess); attempts++) {
+      try {
+        ConnectToLocatorResult connectToLocatorResult =
+            ShellCommands.connectToLocator(locatorHostname, locatorPort,
+                ShellCommands.getConnectLocatorTimeoutInMS() / 4, 
locatorConfigurationProperties);
+
+        ConnectionEndpoint memberEndpoint = 
connectToLocatorResult.getMemberEndpoint();
+
+        jmxManagerSslEnabled = connectToLocatorResult.isJmxManagerSslEnabled();
+
+        if (!jmxManagerSslEnabled) {
+          configurationProperties.clear();
+        }
+
+        getGfsh().setOperationInvoker(new 
JmxOperationInvoker(memberEndpoint.getHost(),
+            memberEndpoint.getPort(), null, null, configurationProperties, 
null));
+
+        String shellAndLogMessage = 
CliStrings.format(CliStrings.CONNECT__MSG__SUCCESS,
+            "JMX Manager " + memberEndpoint.toString(false));
+
+        infoResultData.addLine("\n");
+        infoResultData.addLine(shellAndLogMessage);
+        getGfsh().logToFile(shellAndLogMessage, null);
+
+        connectSuccess = true;
+        responseFailureMessage = null;
+      } catch (IllegalStateException unexpected) {
+        if (CauseFinder.indexOfCause(unexpected, ClassCastException.class, 
false) != -1) {
+          responseFailureMessage = "The Locator might require SSL 
Configuration.";
+        }
+      } catch (SecurityException ignore) {
+        getGfsh().logToFile(ignore.getMessage(), ignore);
+        jmxManagerAuthEnabled = true;
+        break; // no need to continue after SecurityException
+      } catch (AuthenticationFailedException ignore) {
+        getGfsh().logToFile(ignore.getMessage(), ignore);
+        jmxManagerAuthEnabled = true;
+        break; // no need to continue after AuthenticationFailedException
+      } catch (SSLException ignore) {
+        if (ignore instanceof SSLHandshakeException) {
+          // try to connect again without SSL since the SSL handshake failed 
implying a plain text
+          // connection...
+          locatorConfigurationProperties.clear();
+        } else {
+          // another type of SSL error occurred (possibly a configuration 
issue); pass the buck...
+          getGfsh().logToFile(ignore.getMessage(), ignore);
+          responseFailureMessage = "Check your SSL configuration and try 
again.";
+          break;
+        }
+      } catch (Exception ignore) {
+        getGfsh().logToFile(ignore.getMessage(), ignore);
+        responseFailureMessage = "Failed to connect; unknown cause: " + 
ignore.getMessage();
+      }
+    }
+
+    if (!connectSuccess) {
+      doOnConnectionFailure(locatorHostname, locatorPort, 
jmxManagerAuthEnabled,
+          jmxManagerSslEnabled, infoResultData);
+    }
+
+    if (StringUtils.isNotBlank(responseFailureMessage)) {
+      infoResultData.addLine("\n");
+      infoResultData.addLine(responseFailureMessage);
+    }
+
+  }
+
+  private Map<String, String> loadConfigurationProperties(
+      final String configurationPropertiesPathname) {
+    return loadConfigurationProperties(configurationPropertiesPathname, null);
+  }
+
+  private Map<String, String> loadConfigurationProperties(
+      final String configurationPropertiesPathname, Map<String, String> 
configurationProperties) {
+    configurationProperties =
+        (configurationProperties != null ? configurationProperties : new 
HashMap<>());
+
+    if (IOUtils.isExistingPathname(configurationPropertiesPathname)) {
+      try {
+        configurationProperties.putAll(ShellCommands
+            .loadPropertiesFromURL(new 
File(configurationPropertiesPathname).toURI().toURL()));
+      } catch (MalformedURLException ignore) {
+        LogWrapper.getInstance()
+            .warning(String.format(
+                "Failed to load GemFire configuration properties from pathname 
(%1$s)!",
+                configurationPropertiesPathname), ignore);
+      }
+    }
+    return configurationProperties;
+  }
+
+  private void doOnConnectionFailure(final String locatorHostName, final int 
locatorPort,
+      final boolean jmxManagerAuthEnabled, final boolean jmxManagerSslEnabled,
+      final InfoResultData infoResultData) {
+    infoResultData.addLine("\n");
+    
infoResultData.addLine(CliStrings.format(CliStrings.START_LOCATOR__USE__0__TO__CONNECT,
+        new CommandStringBuilder(CliStrings.CONNECT)
+            .addOption(CliStrings.CONNECT__LOCATOR, locatorHostName + "[" + 
locatorPort + "]")
+            .toString()));
+
+    StringBuilder message = new StringBuilder();
+
+    if (jmxManagerAuthEnabled) {
+      message.append("Authentication");
+    }
+    if (jmxManagerSslEnabled) {
+      message.append(jmxManagerAuthEnabled ? " and " : StringUtils.EMPTY)
+          .append("SSL configuration");
+    }
+    if (jmxManagerAuthEnabled || jmxManagerSslEnabled) {
+      message.append(" required to connect to the Manager.");
+      infoResultData.addLine("\n");
+      infoResultData.addLine(message.toString());
+    }
+  }
+
+  String[] createStartLocatorCommandLine(final LocatorLauncher launcher,
+      final String gemfirePropertiesPathname, final String 
gemfireSecurityPropertiesPathname,
+      final Properties gemfireProperties, final String userClasspath,
+      final Boolean includeSystemClasspath, final String[] jvmArgsOpts, final 
String initialHeap,
+      final String maxHeap) throws MalformedObjectNameException {
+    List<String> commandLine = new ArrayList<>();
+
+    commandLine.add(StartMemberUtils.getJavaPath());
+    commandLine.add("-server");
+    commandLine.add("-classpath");
+    commandLine
+        .add(getLocatorClasspath(Boolean.TRUE.equals(includeSystemClasspath), 
userClasspath));
+
+    StartMemberUtils.addCurrentLocators(this, commandLine, gemfireProperties);
+    StartMemberUtils.addGemFirePropertyFile(commandLine, 
gemfirePropertiesPathname);
+    StartMemberUtils.addGemFireSecurityPropertyFile(commandLine, 
gemfireSecurityPropertiesPathname);
+    StartMemberUtils.addGemFireSystemProperties(commandLine, 
gemfireProperties);
+    StartMemberUtils.addJvmArgumentsAndOptions(commandLine, jvmArgsOpts);
+    StartMemberUtils.addInitialHeap(commandLine, initialHeap);
+    StartMemberUtils.addMaxHeap(commandLine, maxHeap);
+
+    commandLine.add(
+        
"-D".concat(AbstractLauncher.SIGNAL_HANDLER_REGISTRATION_SYSTEM_PROPERTY.concat("=true")));
+    commandLine.add("-Djava.awt.headless=true");
+    commandLine.add(
+        
"-Dsun.rmi.dgc.server.gcInterval".concat("=").concat(Long.toString(Long.MAX_VALUE
 - 1)));
+    commandLine.add(LocatorLauncher.class.getName());
+    commandLine.add(LocatorLauncher.Command.START.getName());
+
+    if (StringUtils.isNotBlank(launcher.getMemberName())) {
+      commandLine.add(launcher.getMemberName());
+    }
+
+    if (launcher.getBindAddress() != null) {
+      commandLine.add("--bind-address=" + 
launcher.getBindAddress().getCanonicalHostName());
+    }
+
+    if (launcher.isDebugging() || isDebugging()) {
+      commandLine.add("--debug");
+    }
+
+    if (launcher.isForcing()) {
+      commandLine.add("--force");
+    }
+
+    if (StringUtils.isNotBlank(launcher.getHostnameForClients())) {
+      commandLine.add("--hostname-for-clients=" + 
launcher.getHostnameForClients());
+    }
+
+    if (launcher.getPort() != null) {
+      commandLine.add("--port=" + launcher.getPort());
+    }
+
+    if (launcher.isRedirectingOutput()) {
+      commandLine.add("--redirect-output");
+    }
+    return commandLine.toArray(new String[commandLine.size()]);
+  }
+
+  String getLocatorClasspath(final boolean includeSystemClasspath, final 
String userClasspath) {
+    return StartMemberUtils.toClasspath(includeSystemClasspath,
+        new String[] {StartMemberUtils.CORE_DEPENDENCIES_JAR_PATHNAME}, 
userClasspath);
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/fcce2b0b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartMemberUtils.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartMemberUtils.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartMemberUtils.java
new file mode 100644
index 0000000..fd95387
--- /dev/null
+++ 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartMemberUtils.java
@@ -0,0 +1,250 @@
+/*
+ * 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.management.internal.cli.commands;
+
+import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
+import static 
org.apache.geode.management.internal.cli.shell.MXBeanProvider.getDistributedSystemMXBean;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+import javax.management.MalformedObjectNameException;
+
+import org.apache.commons.lang.ArrayUtils;
+
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.internal.GemFireVersion;
+import org.apache.geode.internal.process.ProcessLauncherContext;
+import org.apache.geode.internal.util.IOUtils;
+import org.apache.geode.management.DistributedSystemMXBean;
+import org.apache.geode.management.internal.cli.util.ThreePhraseGenerator;
+
+/**
+ * Encapsulates methods used by StartServerCommand and StartLocatorCommand and 
their associated
+ * tests.
+ * 
+ * @see StartLocatorCommand
+ * @see StartServerCommand
+ */
+public class StartMemberUtils {
+  public static final String GEODE_HOME = System.getenv("GEODE_HOME");
+
+  private static final String JAVA_HOME = System.getProperty("java.home");
+  static final int CMS_INITIAL_OCCUPANCY_FRACTION = 60;
+  private static final ThreePhraseGenerator nameGenerator = new 
ThreePhraseGenerator();
+
+  static final String CORE_DEPENDENCIES_JAR_PATHNAME =
+      IOUtils.appendToPath(GEODE_HOME, "lib", "geode-dependencies.jar");
+  static final String GEODE_JAR_PATHNAME =
+      IOUtils.appendToPath(GEODE_HOME, "lib", 
GemFireVersion.getGemFireJarFileName());
+  static final long PROCESS_STREAM_READER_ASYNC_STOP_TIMEOUT_MILLIS = 5 * 1000;
+  static final int INVALID_PID = -1;
+
+  static ThreePhraseGenerator getNameGenerator() {
+    return nameGenerator;
+  }
+
+  static void setPropertyIfNotNull(Properties properties, String key, Object 
value) {
+    if (key != null && value != null) {
+      properties.setProperty(key, value.toString());
+    }
+  }
+
+  static String resolveWorkingDir(String userSpecifiedDir, String memberName) {
+    File workingDir =
+        (userSpecifiedDir == null) ? new File(memberName) : new 
File(userSpecifiedDir);
+    String workingDirPath = 
IOUtils.tryGetCanonicalPathElseGetAbsolutePath(workingDir);
+    if (!workingDir.exists()) {
+      if (!workingDir.mkdirs()) {
+        throw new IllegalStateException(String.format(
+            "Could not create directory %s. Please verify directory path or 
user permissions.",
+            workingDirPath));
+      }
+    }
+    return workingDirPath;
+  }
+
+  static void addGemFirePropertyFile(final List<String> commandLine,
+      final String gemfirePropertiesPathname) {
+    if 
(org.apache.geode.internal.lang.StringUtils.isNotBlank(gemfirePropertiesPathname))
 {
+      commandLine.add("-DgemfirePropertyFile=" + gemfirePropertiesPathname);
+    }
+  }
+
+  static void addGemFireSecurityPropertyFile(final List<String> commandLine,
+      final String gemfireSecurityPropertiesPathname) {
+    if 
(org.apache.geode.internal.lang.StringUtils.isNotBlank(gemfireSecurityPropertiesPathname))
 {
+      commandLine.add("-DgemfireSecurityPropertyFile=" + 
gemfireSecurityPropertiesPathname);
+    }
+  }
+
+  static void addGemFireSystemProperties(final List<String> commandLine,
+      final Properties gemfireProperties) {
+    for (final Object property : gemfireProperties.keySet()) {
+      final String propertyName = property.toString();
+      final String propertyValue = gemfireProperties.getProperty(propertyName);
+      if 
(org.apache.geode.internal.lang.StringUtils.isNotBlank(propertyValue)) {
+        commandLine.add(
+            "-D" + DistributionConfig.GEMFIRE_PREFIX + "" + propertyName + "=" 
+ propertyValue);
+      }
+    }
+  }
+
+  static void addJvmArgumentsAndOptions(final List<String> commandLine,
+      final String[] jvmArgsOpts) {
+    if (jvmArgsOpts != null) {
+      commandLine.addAll(Arrays.asList(jvmArgsOpts));
+    }
+  }
+
+  static void addInitialHeap(final List<String> commandLine, final String 
initialHeap) {
+    if (org.apache.geode.internal.lang.StringUtils.isNotBlank(initialHeap)) {
+      commandLine.add("-Xms" + initialHeap);
+    }
+  }
+
+  static void addMaxHeap(final List<String> commandLine, final String maxHeap) 
{
+    if (org.apache.geode.internal.lang.StringUtils.isNotBlank(maxHeap)) {
+      commandLine.add("-Xmx" + maxHeap);
+      commandLine.add("-XX:+UseConcMarkSweepGC");
+      commandLine.add("-XX:CMSInitiatingOccupancyFraction=" + 
CMS_INITIAL_OCCUPANCY_FRACTION);
+      // commandLine.add("-XX:MinHeapFreeRatio=" + MINIMUM_HEAP_FREE_RATIO);
+    }
+  }
+
+  static void addCurrentLocators(GfshCommand gfshCommand, final List<String> 
commandLine,
+      final Properties gemfireProperties) throws MalformedObjectNameException {
+    if (org.apache.geode.internal.lang.StringUtils
+        .isBlank(gemfireProperties.getProperty(LOCATORS))) {
+      String currentLocators = getCurrentLocators(gfshCommand);
+      if 
(org.apache.geode.internal.lang.StringUtils.isNotBlank(currentLocators)) {
+        
commandLine.add("-D".concat(ProcessLauncherContext.OVERRIDDEN_DEFAULTS_PREFIX)
+            .concat(LOCATORS).concat("=").concat(currentLocators));
+      }
+    }
+  }
+
+  private static String getCurrentLocators(GfshCommand gfshCommand)
+      throws MalformedObjectNameException {
+    String delimitedLocators = "";
+    try {
+      if (gfshCommand.isConnectedAndReady()) {
+        final DistributedSystemMXBean dsMBeanProxy = 
getDistributedSystemMXBean();
+        if (dsMBeanProxy != null) {
+          final String[] locators = dsMBeanProxy.listLocators();
+          if (locators != null && locators.length > 0) {
+            final StringBuilder sb = new StringBuilder();
+            for (int i = 0; i < locators.length; i++) {
+              if (i > 0) {
+                sb.append(",");
+              }
+              sb.append(locators[i]);
+            }
+            delimitedLocators = sb.toString();
+          }
+        }
+      }
+    } catch (IOException e) { // thrown by getDistributedSystemMXBean
+      // leave delimitedLocators = ""
+      gfshCommand.getGfsh().logWarning("DistributedSystemMXBean is 
unavailable\n", e);
+    }
+    return delimitedLocators;
+  }
+
+  public static int readPid(final File pidFile) {
+    assert pidFile != null : "The file from which to read the process ID (pid) 
cannot be null!";
+    if (pidFile.isFile()) {
+      BufferedReader fileReader = null;
+      try {
+        fileReader = new BufferedReader(new FileReader(pidFile));
+        return Integer.parseInt(fileReader.readLine());
+      } catch (IOException | NumberFormatException ignore) {
+      } finally {
+        IOUtils.close(fileReader);
+      }
+    }
+    return INVALID_PID;
+  }
+
+  static String getJavaPath() {
+    return new File(new File(JAVA_HOME, "bin"), "java").getPath();
+  }
+
+  static String getSystemClasspath() {
+    return System.getProperty("java.class.path");
+  }
+
+  static String toClasspath(final boolean includeSystemClasspath, String[] 
jarFilePathnames,
+      String... userClasspaths) {
+    // gemfire jar must absolutely be the first JAR file on the CLASSPATH!!!
+    StringBuilder classpath = new StringBuilder(getGemFireJarPath());
+
+    userClasspaths = (userClasspaths != null ? userClasspaths : 
ArrayUtils.EMPTY_STRING_ARRAY);
+
+    // Then, include user-specified classes on CLASSPATH to enable the user to 
override GemFire JAR
+    // dependencies
+    // with application-specific versions; this logic/block corresponds to 
classes/jar-files
+    // specified with the
+    // --classpath option to the 'start locator' and 'start server commands'; 
also this will
+    // override any
+    // System CLASSPATH environment variable setting, which is consistent with 
the Java platform
+    // behavior...
+    for (String userClasspath : userClasspaths) {
+      if 
(org.apache.geode.internal.lang.StringUtils.isNotBlank(userClasspath)) {
+        classpath.append((classpath.length() == 0)
+            ? org.apache.geode.internal.lang.StringUtils.EMPTY : 
File.pathSeparator);
+        classpath.append(userClasspath);
+      }
+    }
+
+    // Now, include any System-specified CLASSPATH environment variable 
setting...
+    if (includeSystemClasspath) {
+      classpath.append(File.pathSeparator);
+      classpath.append(getSystemClasspath());
+    }
+
+    jarFilePathnames =
+        (jarFilePathnames != null ? jarFilePathnames : 
ArrayUtils.EMPTY_STRING_ARRAY);
+
+    // And finally, include all GemFire dependencies on the CLASSPATH...
+    for (String jarFilePathname : jarFilePathnames) {
+      if 
(org.apache.geode.internal.lang.StringUtils.isNotBlank(jarFilePathname)) {
+        classpath.append((classpath.length() == 0)
+            ? org.apache.geode.internal.lang.StringUtils.EMPTY : 
File.pathSeparator);
+        classpath.append(jarFilePathname);
+      }
+    }
+    return classpath.toString();
+  }
+
+  static String getGemFireJarPath() {
+    String classpath = getSystemClasspath();
+    String gemfireJarPath = GEODE_JAR_PATHNAME;
+    for (String classpathElement : classpath.split(File.pathSeparator)) {
+      // MUST CHANGE THIS TO REGEX SINCE VERSION CHANGES IN JAR NAME
+      if (classpathElement.endsWith("gemfire-core-8.2.0.0-SNAPSHOT.jar")) {
+        gemfireJarPath = classpathElement;
+        break;
+      }
+    }
+    return gemfireJarPath;
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/fcce2b0b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartServerCommand.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartServerCommand.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartServerCommand.java
new file mode 100644
index 0000000..432a065
--- /dev/null
+++ 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartServerCommand.java
@@ -0,0 +1,594 @@
+/*
+ * 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.management.internal.cli.commands;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.MalformedObjectNameException;
+
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+
+import org.apache.geode.SystemFailure;
+import org.apache.geode.cache.server.CacheServer;
+import org.apache.geode.distributed.AbstractLauncher;
+import org.apache.geode.distributed.ConfigurationProperties;
+import org.apache.geode.distributed.ServerLauncher;
+import org.apache.geode.internal.OSProcess;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+import org.apache.geode.internal.lang.StringUtils;
+import org.apache.geode.internal.lang.SystemUtils;
+import 
org.apache.geode.internal.process.ClusterConfigurationNotAvailableException;
+import org.apache.geode.internal.process.ProcessStreamReader;
+import org.apache.geode.internal.process.ProcessType;
+import org.apache.geode.internal.util.IOUtils;
+import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.ConverterHint;
+import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.internal.cli.CliUtil;
+import org.apache.geode.management.internal.cli.GfshParser;
+import org.apache.geode.management.internal.cli.i18n.CliStrings;
+import org.apache.geode.management.internal.cli.result.ResultBuilder;
+import org.apache.geode.management.internal.cli.shell.Gfsh;
+import org.apache.geode.management.internal.security.ResourceConstants;
+
+public class StartServerCommand implements GfshCommand {
+  private static final String SERVER_TERM_NAME = "Server";
+
+  @CliCommand(value = CliStrings.START_SERVER, help = 
CliStrings.START_SERVER__HELP)
+  @CliMetaData(shellOnly = true,
+      relatedTopic = {CliStrings.TOPIC_GEODE_SERVER, 
CliStrings.TOPIC_GEODE_LIFECYCLE})
+  public Result startServer(
+      @CliOption(key = CliStrings.START_SERVER__NAME,
+          help = CliStrings.START_SERVER__NAME__HELP) String memberName,
+      @CliOption(key = CliStrings.START_SERVER__ASSIGN_BUCKETS, 
unspecifiedDefaultValue = "false",
+          specifiedDefaultValue = "true",
+          help = CliStrings.START_SERVER__ASSIGN_BUCKETS__HELP) final Boolean 
assignBuckets,
+      @CliOption(key = CliStrings.START_SERVER__BIND_ADDRESS,
+          help = CliStrings.START_SERVER__BIND_ADDRESS__HELP) final String 
bindAddress,
+      @CliOption(key = CliStrings.START_SERVER__CACHE_XML_FILE,
+          optionContext = ConverterHint.FILE_PATH,
+          help = CliStrings.START_SERVER__CACHE_XML_FILE__HELP) String 
cacheXmlPathname,
+      @CliOption(key = CliStrings.START_SERVER__CLASSPATH,
+          /* optionContext = ConverterHint.FILE_PATH, // there's an issue with 
TAB here */
+          help = CliStrings.START_SERVER__CLASSPATH__HELP) final String 
classpath,
+      @CliOption(key = CliStrings.START_SERVER__CRITICAL__HEAP__PERCENTAGE,
+          help = CliStrings.START_SERVER__CRITICAL__HEAP__HELP) final Float 
criticalHeapPercentage,
+      @CliOption(key = CliStrings.START_SERVER__CRITICAL_OFF_HEAP_PERCENTAGE,
+          help = CliStrings.START_SERVER__CRITICAL_OFF_HEAP__HELP) final Float 
criticalOffHeapPercentage,
+      @CliOption(key = CliStrings.START_SERVER__DIR,
+          help = CliStrings.START_SERVER__DIR__HELP) String workingDirectory,
+      @CliOption(key = CliStrings.START_SERVER__DISABLE_DEFAULT_SERVER,
+          unspecifiedDefaultValue = "false", specifiedDefaultValue = "true",
+          help = CliStrings.START_SERVER__DISABLE_DEFAULT_SERVER__HELP) final 
Boolean disableDefaultServer,
+      @CliOption(key = 
CliStrings.START_SERVER__DISABLE_EXIT_WHEN_OUT_OF_MEMORY,
+          unspecifiedDefaultValue = "false", specifiedDefaultValue = "true",
+          help = 
CliStrings.START_SERVER__DISABLE_EXIT_WHEN_OUT_OF_MEMORY_HELP) final Boolean 
disableExitWhenOutOfMemory,
+      @CliOption(key = CliStrings.START_SERVER__ENABLE_TIME_STATISTICS,
+          specifiedDefaultValue = "true",
+          help = CliStrings.START_SERVER__ENABLE_TIME_STATISTICS__HELP) final 
Boolean enableTimeStatistics,
+      @CliOption(key = CliStrings.START_SERVER__EVICTION__HEAP__PERCENTAGE,
+          help = CliStrings.START_SERVER__EVICTION__HEAP__PERCENTAGE__HELP) 
final Float evictionHeapPercentage,
+      @CliOption(key = CliStrings.START_SERVER__EVICTION_OFF_HEAP_PERCENTAGE,
+          help = CliStrings.START_SERVER__EVICTION_OFF_HEAP_PERCENTAGE__HELP) 
final Float evictionOffHeapPercentage,
+      @CliOption(key = CliStrings.START_SERVER__FORCE, unspecifiedDefaultValue 
= "false",
+          specifiedDefaultValue = "true",
+          help = CliStrings.START_SERVER__FORCE__HELP) final Boolean force,
+      @CliOption(key = {CliStrings.GROUP, CliStrings.GROUPS},
+          optionContext = ConverterHint.MEMBERGROUP,
+          help = CliStrings.START_SERVER__GROUP__HELP) final String group,
+      @CliOption(key = CliStrings.START_SERVER__HOSTNAME__FOR__CLIENTS,
+          help = CliStrings.START_SERVER__HOSTNAME__FOR__CLIENTS__HELP) final 
String hostNameForClients,
+      @CliOption(key = 
ConfigurationProperties.JMX_MANAGER_HOSTNAME_FOR_CLIENTS,
+          help = 
CliStrings.START_SERVER__JMX_MANAGER_HOSTNAME_FOR_CLIENTS__HELP) final String 
jmxManagerHostnameForClients,
+      @CliOption(key = CliStrings.START_SERVER__INCLUDE_SYSTEM_CLASSPATH,
+          specifiedDefaultValue = "true", unspecifiedDefaultValue = "false",
+          help = CliStrings.START_SERVER__INCLUDE_SYSTEM_CLASSPATH__HELP) 
final Boolean includeSystemClasspath,
+      @CliOption(key = CliStrings.START_SERVER__INITIAL_HEAP,
+          help = CliStrings.START_SERVER__INITIAL_HEAP__HELP) final String 
initialHeap,
+      @CliOption(key = CliStrings.START_SERVER__J, optionContext = 
GfshParser.J_OPTION_CONTEXT,
+          help = CliStrings.START_SERVER__J__HELP) final String[] jvmArgsOpts,
+      @CliOption(key = CliStrings.START_SERVER__LOCATORS,
+          optionContext = ConverterHint.LOCATOR_DISCOVERY_CONFIG,
+          help = CliStrings.START_SERVER__LOCATORS__HELP) final String 
locators,
+      @CliOption(key = CliStrings.START_SERVER__LOCATOR_WAIT_TIME,
+          help = CliStrings.START_SERVER__LOCATOR_WAIT_TIME_HELP) final 
Integer locatorWaitTime,
+      @CliOption(key = CliStrings.START_SERVER__LOCK_MEMORY, 
specifiedDefaultValue = "true",
+          help = CliStrings.START_SERVER__LOCK_MEMORY__HELP) final Boolean 
lockMemory,
+      @CliOption(key = CliStrings.START_SERVER__LOG_LEVEL, optionContext = 
ConverterHint.LOG_LEVEL,
+          help = CliStrings.START_SERVER__LOG_LEVEL__HELP) final String 
logLevel,
+      @CliOption(key = CliStrings.START_SERVER__MAX__CONNECTIONS,
+          help = CliStrings.START_SERVER__MAX__CONNECTIONS__HELP) final 
Integer maxConnections,
+      @CliOption(key = CliStrings.START_SERVER__MAXHEAP,
+          help = CliStrings.START_SERVER__MAXHEAP__HELP) final String maxHeap,
+      @CliOption(key = CliStrings.START_SERVER__MAX__MESSAGE__COUNT,
+          help = CliStrings.START_SERVER__MAX__MESSAGE__COUNT__HELP) final 
Integer maxMessageCount,
+      @CliOption(key = CliStrings.START_SERVER__MAX__THREADS,
+          help = CliStrings.START_SERVER__MAX__THREADS__HELP) final Integer 
maxThreads,
+      @CliOption(key = CliStrings.START_SERVER__MCAST_ADDRESS,
+          help = CliStrings.START_SERVER__MCAST_ADDRESS__HELP) final String 
mcastBindAddress,
+      @CliOption(key = CliStrings.START_SERVER__MCAST_PORT,
+          help = CliStrings.START_SERVER__MCAST_PORT__HELP) final Integer 
mcastPort,
+      @CliOption(key = CliStrings.START_SERVER__MEMCACHED_PORT,
+          help = CliStrings.START_SERVER__MEMCACHED_PORT__HELP) final Integer 
memcachedPort,
+      @CliOption(key = CliStrings.START_SERVER__MEMCACHED_PROTOCOL,
+          help = CliStrings.START_SERVER__MEMCACHED_PROTOCOL__HELP) final 
String memcachedProtocol,
+      @CliOption(key = CliStrings.START_SERVER__MEMCACHED_BIND_ADDRESS,
+          help = CliStrings.START_SERVER__MEMCACHED_BIND_ADDRESS__HELP) final 
String memcachedBindAddress,
+      @CliOption(key = CliStrings.START_SERVER__REDIS_PORT,
+          help = CliStrings.START_SERVER__REDIS_PORT__HELP) final Integer 
redisPort,
+      @CliOption(key = CliStrings.START_SERVER__REDIS_BIND_ADDRESS,
+          help = CliStrings.START_SERVER__REDIS_BIND_ADDRESS__HELP) final 
String redisBindAddress,
+      @CliOption(key = CliStrings.START_SERVER__REDIS_PASSWORD,
+          help = CliStrings.START_SERVER__REDIS_PASSWORD__HELP) final String 
redisPassword,
+      @CliOption(key = CliStrings.START_SERVER__MESSAGE__TIME__TO__LIVE,
+          help = CliStrings.START_SERVER__MESSAGE__TIME__TO__LIVE__HELP) final 
Integer messageTimeToLive,
+      @CliOption(key = CliStrings.START_SERVER__OFF_HEAP_MEMORY_SIZE,
+          help = CliStrings.START_SERVER__OFF_HEAP_MEMORY_SIZE__HELP) final 
String offHeapMemorySize,
+      @CliOption(key = CliStrings.START_SERVER__PROPERTIES, optionContext = 
ConverterHint.FILE_PATH,
+          help = CliStrings.START_SERVER__PROPERTIES__HELP) String 
gemfirePropertiesPathname,
+      @CliOption(key = CliStrings.START_SERVER__REBALANCE, 
unspecifiedDefaultValue = "false",
+          specifiedDefaultValue = "true",
+          help = CliStrings.START_SERVER__REBALANCE__HELP) final Boolean 
rebalance,
+      @CliOption(key = CliStrings.START_SERVER__SECURITY_PROPERTIES,
+          optionContext = ConverterHint.FILE_PATH,
+          help = CliStrings.START_SERVER__SECURITY_PROPERTIES__HELP) String 
gemfireSecurityPropertiesPathname,
+      @CliOption(key = CliStrings.START_SERVER__SERVER_BIND_ADDRESS,
+          unspecifiedDefaultValue = CacheServer.DEFAULT_BIND_ADDRESS,
+          help = CliStrings.START_SERVER__SERVER_BIND_ADDRESS__HELP) final 
String serverBindAddress,
+      @CliOption(key = CliStrings.START_SERVER__SERVER_PORT,
+          unspecifiedDefaultValue = ("" + CacheServer.DEFAULT_PORT),
+          help = CliStrings.START_SERVER__SERVER_PORT__HELP) final Integer 
serverPort,
+      @CliOption(key = CliStrings.START_SERVER__SOCKET__BUFFER__SIZE,
+          help = CliStrings.START_SERVER__SOCKET__BUFFER__SIZE__HELP) final 
Integer socketBufferSize,
+      @CliOption(key = CliStrings.START_SERVER__SPRING_XML_LOCATION,
+          help = CliStrings.START_SERVER__SPRING_XML_LOCATION_HELP) final 
String springXmlLocation,
+      @CliOption(key = CliStrings.START_SERVER__STATISTIC_ARCHIVE_FILE,
+          help = CliStrings.START_SERVER__STATISTIC_ARCHIVE_FILE__HELP) final 
String statisticsArchivePathname,
+      @CliOption(key = CliStrings.START_SERVER__USE_CLUSTER_CONFIGURATION,
+          unspecifiedDefaultValue = "true", specifiedDefaultValue = "true",
+          help = CliStrings.START_SERVER__USE_CLUSTER_CONFIGURATION__HELP) 
final Boolean requestSharedConfiguration,
+      @CliOption(key = CliStrings.START_SERVER__REST_API, 
unspecifiedDefaultValue = "false",
+          specifiedDefaultValue = "true",
+          help = CliStrings.START_SERVER__REST_API__HELP) final Boolean 
startRestApi,
+      @CliOption(key = CliStrings.START_SERVER__HTTP_SERVICE_PORT, 
unspecifiedDefaultValue = "",
+          help = CliStrings.START_SERVER__HTTP_SERVICE_PORT__HELP) final 
String httpServicePort,
+      @CliOption(key = CliStrings.START_SERVER__HTTP_SERVICE_BIND_ADDRESS,
+          unspecifiedDefaultValue = "",
+          help = CliStrings.START_SERVER__HTTP_SERVICE_BIND_ADDRESS__HELP) 
final String httpServiceBindAddress,
+      @CliOption(key = CliStrings.START_SERVER__USERNAME, 
unspecifiedDefaultValue = "",
+          help = CliStrings.START_SERVER__USERNAME__HELP) final String 
userName,
+      @CliOption(key = CliStrings.START_SERVER__PASSWORD, 
unspecifiedDefaultValue = "",
+          help = CliStrings.START_SERVER__PASSWORD__HELP) String passwordToUse)
+  // NOTICE: keep the parameters in alphabetical order based on their 
CliStrings.START_SERVER_* text
+  {
+    try {
+      if (StringUtils.isBlank(memberName)) {
+        // when the user doesn't give us a name, we make one up!
+        memberName = StartMemberUtils.getNameGenerator().generate('-');
+      }
+
+      // prompt for password is username is specified in the command
+      if (StringUtils.isNotBlank(userName)) {
+        if (StringUtils.isBlank(passwordToUse)) {
+          passwordToUse = 
getGfsh().readPassword(CliStrings.START_SERVER__PASSWORD + ": ");
+        }
+        if (StringUtils.isBlank(passwordToUse)) {
+          return ResultBuilder.createConnectionErrorResult(
+              CliStrings.START_SERVER__MSG__PASSWORD_MUST_BE_SPECIFIED);
+        }
+      }
+
+      workingDirectory = StartMemberUtils.resolveWorkingDir(workingDirectory, 
memberName);
+
+      cacheXmlPathname = CliUtil.resolvePathname(cacheXmlPathname);
+
+      if (StringUtils.isNotBlank(cacheXmlPathname)
+          && !IOUtils.isExistingPathname(cacheXmlPathname)) {
+        return ResultBuilder.createUserErrorResult(
+            CliStrings.format(CliStrings.CACHE_XML_NOT_FOUND_MESSAGE, 
cacheXmlPathname));
+      }
+
+      gemfirePropertiesPathname = 
CliUtil.resolvePathname(gemfirePropertiesPathname);
+
+      if (StringUtils.isNotBlank(gemfirePropertiesPathname)
+          && !IOUtils.isExistingPathname(gemfirePropertiesPathname)) {
+        return ResultBuilder.createUserErrorResult(
+            
CliStrings.format(CliStrings.GEODE_0_PROPERTIES_1_NOT_FOUND_MESSAGE, 
StringUtils.EMPTY,
+                gemfirePropertiesPathname));
+      }
+
+      gemfireSecurityPropertiesPathname =
+          CliUtil.resolvePathname(gemfireSecurityPropertiesPathname);
+
+      if (StringUtils.isNotBlank(gemfireSecurityPropertiesPathname)
+          && !IOUtils.isExistingPathname(gemfireSecurityPropertiesPathname)) {
+        return ResultBuilder.createUserErrorResult(
+            
CliStrings.format(CliStrings.GEODE_0_PROPERTIES_1_NOT_FOUND_MESSAGE, "Security 
",
+                gemfireSecurityPropertiesPathname));
+      }
+
+      File serverPidFile = new File(workingDirectory, 
ProcessType.SERVER.getPidFileName());
+
+      final int oldPid = StartMemberUtils.readPid(serverPidFile);
+
+      Properties gemfireProperties = new Properties();
+
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties, 
ConfigurationProperties.BIND_ADDRESS,
+          bindAddress);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.CACHE_XML_FILE, cacheXmlPathname);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.ENABLE_TIME_STATISTICS, 
enableTimeStatistics);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties, 
ConfigurationProperties.GROUPS,
+          group);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.JMX_MANAGER_HOSTNAME_FOR_CLIENTS, 
jmxManagerHostnameForClients);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties, 
ConfigurationProperties.LOCATORS,
+          locators);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.LOCATOR_WAIT_TIME, locatorWaitTime);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties, 
ConfigurationProperties.LOG_LEVEL,
+          logLevel);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.MCAST_ADDRESS, mcastBindAddress);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties, 
ConfigurationProperties.MCAST_PORT,
+          mcastPort);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.MEMCACHED_PORT, memcachedPort);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.MEMCACHED_PROTOCOL, memcachedProtocol);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.MEMCACHED_BIND_ADDRESS, 
memcachedBindAddress);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties, 
ConfigurationProperties.REDIS_PORT,
+          redisPort);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.REDIS_BIND_ADDRESS, redisBindAddress);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.REDIS_PASSWORD, redisPassword);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.STATISTIC_ARCHIVE_FILE, 
statisticsArchivePathname);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.USE_CLUSTER_CONFIGURATION, 
requestSharedConfiguration);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties, 
ConfigurationProperties.LOCK_MEMORY,
+          lockMemory);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.OFF_HEAP_MEMORY_SIZE, offHeapMemorySize);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.START_DEV_REST_API, startRestApi);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.HTTP_SERVICE_PORT, httpServicePort);
+      StartMemberUtils.setPropertyIfNotNull(gemfireProperties,
+          ConfigurationProperties.HTTP_SERVICE_BIND_ADDRESS, 
httpServiceBindAddress);
+      // if username is specified in the command line, it will overwrite 
what's set in the
+      // properties file
+      if (StringUtils.isNotBlank(userName)) {
+        gemfireProperties.setProperty(ResourceConstants.USER_NAME, userName);
+        gemfireProperties.setProperty(ResourceConstants.PASSWORD, 
passwordToUse);
+      }
+
+      // read the OSProcess enable redirect system property here -- TODO: 
replace with new GFSH
+      // argument
+      final boolean redirectOutput =
+          Boolean.getBoolean(OSProcess.ENABLE_OUTPUT_REDIRECTION_PROPERTY);
+
+      ServerLauncher.Builder serverLauncherBuilder = new 
ServerLauncher.Builder()
+          
.setAssignBuckets(assignBuckets).setDisableDefaultServer(disableDefaultServer)
+          
.setForce(force).setRebalance(rebalance).setRedirectOutput(redirectOutput)
+          .setServerBindAddress(serverBindAddress).setServerPort(serverPort)
+          
.setSpringXmlLocation(springXmlLocation).setWorkingDirectory(workingDirectory)
+          .setCriticalHeapPercentage(criticalHeapPercentage)
+          .setEvictionHeapPercentage(evictionHeapPercentage)
+          .setCriticalOffHeapPercentage(criticalOffHeapPercentage)
+          
.setEvictionOffHeapPercentage(evictionOffHeapPercentage).setMaxConnections(maxConnections)
+          .setMaxMessageCount(maxMessageCount).setMaxThreads(maxThreads)
+          
.setMessageTimeToLive(messageTimeToLive).setSocketBufferSize(socketBufferSize);
+      if (hostNameForClients != null) {
+        serverLauncherBuilder.setHostNameForClients(hostNameForClients);
+      }
+      if (memberName != null) {
+        serverLauncherBuilder.setMemberName(memberName);
+      }
+      ServerLauncher serverLauncher = serverLauncherBuilder.build();
+
+      String[] serverCommandLine = createStartServerCommandLine(serverLauncher,
+          gemfirePropertiesPathname, gemfireSecurityPropertiesPathname, 
gemfireProperties,
+          classpath, includeSystemClasspath, jvmArgsOpts, 
disableExitWhenOutOfMemory, initialHeap,
+          maxHeap);
+
+      if (getGfsh().getDebug()) {
+        getGfsh().logInfo(StringUtils.join(serverCommandLine, 
StringUtils.SPACE), null);
+      }
+
+      Process serverProcess = new ProcessBuilder(serverCommandLine)
+          .directory(new File(serverLauncher.getWorkingDirectory())).start();
+
+      serverProcess.getInputStream().close();
+      serverProcess.getOutputStream().close();
+
+      // fix TRAC bug #51967 by using NON_BLOCKING on Windows
+      final ProcessStreamReader.ReadingMode readingMode = 
SystemUtils.isWindows()
+          ? ProcessStreamReader.ReadingMode.NON_BLOCKING : 
ProcessStreamReader.ReadingMode.BLOCKING;
+
+      final StringBuffer message = new StringBuffer(); // need thread-safe 
StringBuffer
+      ProcessStreamReader.InputListener inputListener = line -> {
+        message.append(line);
+        if (readingMode == ProcessStreamReader.ReadingMode.BLOCKING) {
+          message.append(StringUtils.LINE_SEPARATOR);
+        }
+      };
+
+      ProcessStreamReader stderrReader = new 
ProcessStreamReader.Builder(serverProcess)
+          
.inputStream(serverProcess.getErrorStream()).inputListener(inputListener)
+          .readingMode(readingMode).continueReadingMillis(2 * 
1000).build().start();
+
+      ServerLauncher.ServerState serverState;
+
+      String previousServerStatusMessage = null;
+
+      LauncherSignalListener serverSignalListener = new 
LauncherSignalListener();
+
+      final boolean registeredServerSignalListener =
+          getGfsh().getSignalHandler().registerListener(serverSignalListener);
+
+      try {
+        getGfsh().logInfo(String.format(CliStrings.START_SERVER__RUN_MESSAGE,
+            IOUtils.tryGetCanonicalPathElseGetAbsolutePath(
+                new File(serverLauncher.getWorkingDirectory()))),
+            null);
+
+        serverState = 
ServerLauncher.ServerState.fromDirectory(workingDirectory, memberName);
+        do {
+          if (serverProcess.isAlive()) {
+            Gfsh.print(".");
+
+            synchronized (this) {
+              TimeUnit.MILLISECONDS.timedWait(this, 500);
+            }
+
+            serverState = 
ServerLauncher.ServerState.fromDirectory(workingDirectory, memberName);
+
+            String currentServerStatusMessage = serverState.getStatusMessage();
+
+            if (serverState.isStartingOrNotResponding()
+                && !(StringUtils.isBlank(currentServerStatusMessage)
+                    || 
currentServerStatusMessage.equalsIgnoreCase(previousServerStatusMessage)
+                    || 
currentServerStatusMessage.trim().toLowerCase().equals("null"))) {
+              Gfsh.println();
+              Gfsh.println(currentServerStatusMessage);
+              previousServerStatusMessage = currentServerStatusMessage;
+            }
+          } else {
+            final int exitValue = serverProcess.exitValue();
+
+            return ResultBuilder.createShellClientErrorResult(
+                
String.format(CliStrings.START_SERVER__PROCESS_TERMINATED_ABNORMALLY_ERROR_MESSAGE,
+                    exitValue, serverLauncher.getWorkingDirectory(), 
message.toString()));
+
+          }
+        } while (!(registeredServerSignalListener && 
serverSignalListener.isSignaled())
+            && serverState.isStartingOrNotResponding());
+      } finally {
+        
stderrReader.stopAsync(StartMemberUtils.PROCESS_STREAM_READER_ASYNC_STOP_TIMEOUT_MILLIS);
 // stop
+                                                                               
                   // will
+                                                                               
                   // close
+        // ErrorStream
+        getGfsh().getSignalHandler().unregisterListener(serverSignalListener);
+      }
+
+      Gfsh.println();
+
+      final boolean asyncStart =
+          
ServerLauncher.ServerState.isStartingNotRespondingOrNull(serverState);
+
+      if (asyncStart) { // async start
+        Gfsh.print(String.format(CliStrings.ASYNC_PROCESS_LAUNCH_MESSAGE, 
SERVER_TERM_NAME));
+        return ResultBuilder.createInfoResult("");
+      } else {
+        return ResultBuilder.createInfoResult(serverState.toString());
+      }
+    } catch (IllegalArgumentException e) {
+      String message = e.getMessage();
+      if (message != null && message.matches(
+          
LocalizedStrings.Launcher_Builder_UNKNOWN_HOST_ERROR_MESSAGE.toLocalizedString(".+")))
 {
+        message =
+            
CliStrings.format(CliStrings.LAUNCHERLIFECYCLECOMMANDS__MSG__FAILED_TO_START_0_REASON_1,
+                SERVER_TERM_NAME, message);
+      }
+      return ResultBuilder.createUserErrorResult(message);
+    } catch (IllegalStateException e) {
+      return ResultBuilder.createUserErrorResult(e.getMessage());
+    } catch (ClusterConfigurationNotAvailableException e) {
+      return ResultBuilder.createShellClientErrorResult(e.getMessage());
+    } catch (VirtualMachineError e) {
+      SystemFailure.initiateFailure(e);
+      throw e;
+    } catch (Throwable t) {
+      SystemFailure.checkFailure();
+      return ResultBuilder.createShellClientErrorResult(String.format(
+          CliStrings.START_SERVER__GENERAL_ERROR_MESSAGE, this.toString(t, 
getGfsh().getDebug())));
+    }
+  }
+
+  String[] createStartServerCommandLine(final ServerLauncher launcher,
+      final String gemfirePropertiesPathname, final String 
gemfireSecurityPropertiesPathname,
+      final Properties gemfireProperties, final String userClasspath,
+      final Boolean includeSystemClasspath, final String[] jvmArgsOpts,
+      final Boolean disableExitWhenOutOfMemory, final String initialHeap, 
final String maxHeap)
+      throws MalformedObjectNameException {
+    List<String> commandLine = new ArrayList<>();
+
+    commandLine.add(StartMemberUtils.getJavaPath());
+    commandLine.add("-server");
+    commandLine.add("-classpath");
+    
commandLine.add(getServerClasspath(Boolean.TRUE.equals(includeSystemClasspath), 
userClasspath));
+
+    StartMemberUtils.addCurrentLocators(this, commandLine, gemfireProperties);
+    StartMemberUtils.addGemFirePropertyFile(commandLine, 
gemfirePropertiesPathname);
+    StartMemberUtils.addGemFireSecurityPropertyFile(commandLine, 
gemfireSecurityPropertiesPathname);
+    StartMemberUtils.addGemFireSystemProperties(commandLine, 
gemfireProperties);
+    StartMemberUtils.addJvmArgumentsAndOptions(commandLine, jvmArgsOpts);
+
+    // NOTE asserting not equal to true rather than equal to false handles the 
null case and ensures
+    // the user
+    // explicitly specified the command-line option in order to disable JVM 
memory checks.
+    if (!Boolean.TRUE.equals(disableExitWhenOutOfMemory)) {
+      addJvmOptionsForOutOfMemoryErrors(commandLine);
+    }
+
+    StartMemberUtils.addInitialHeap(commandLine, initialHeap);
+    StartMemberUtils.addMaxHeap(commandLine, maxHeap);
+
+    commandLine.add(
+        
"-D".concat(AbstractLauncher.SIGNAL_HANDLER_REGISTRATION_SYSTEM_PROPERTY.concat("=true")));
+    commandLine.add("-Djava.awt.headless=true");
+    commandLine.add(
+        
"-Dsun.rmi.dgc.server.gcInterval".concat("=").concat(Long.toString(Long.MAX_VALUE
 - 1)));
+
+    commandLine.add(ServerLauncher.class.getName());
+    commandLine.add(ServerLauncher.Command.START.getName());
+
+    if (StringUtils.isNotBlank(launcher.getMemberName())) {
+      commandLine.add(launcher.getMemberName());
+    }
+
+    if (launcher.isAssignBuckets()) {
+      commandLine.add("--assign-buckets");
+    }
+
+    if (launcher.isDebugging() || isDebugging()) {
+      commandLine.add("--debug");
+    }
+
+    if (launcher.isDisableDefaultServer()) {
+      commandLine.add("--disable-default-server");
+    }
+
+    if (launcher.isForcing()) {
+      commandLine.add("--force");
+    }
+
+    if (launcher.isRebalancing()) {
+      commandLine.add("--rebalance");
+    }
+
+    if (launcher.isRedirectingOutput()) {
+      commandLine.add("--redirect-output");
+    }
+
+    if (launcher.getServerBindAddress() != null) {
+      commandLine
+          .add("--server-bind-address=" + 
launcher.getServerBindAddress().getCanonicalHostName());
+    }
+
+    if (launcher.getServerPort() != null) {
+      commandLine.add("--server-port=" + launcher.getServerPort());
+    }
+
+    if (launcher.isSpringXmlLocationSpecified()) {
+      
commandLine.add("--spring-xml-location=".concat(launcher.getSpringXmlLocation()));
+    }
+
+    if (launcher.getCriticalHeapPercentage() != null) {
+      commandLine.add("--" + 
CliStrings.START_SERVER__CRITICAL__HEAP__PERCENTAGE + "="
+          + launcher.getCriticalHeapPercentage());
+    }
+
+    if (launcher.getEvictionHeapPercentage() != null) {
+      commandLine.add("--" + 
CliStrings.START_SERVER__EVICTION__HEAP__PERCENTAGE + "="
+          + launcher.getEvictionHeapPercentage());
+    }
+
+    if (launcher.getCriticalOffHeapPercentage() != null) {
+      commandLine.add("--" + 
CliStrings.START_SERVER__CRITICAL_OFF_HEAP_PERCENTAGE + "="
+          + launcher.getCriticalOffHeapPercentage());
+    }
+
+    if (launcher.getEvictionOffHeapPercentage() != null) {
+      commandLine.add("--" + 
CliStrings.START_SERVER__EVICTION_OFF_HEAP_PERCENTAGE + "="
+          + launcher.getEvictionOffHeapPercentage());
+    }
+
+    if (launcher.getMaxConnections() != null) {
+      commandLine.add(
+          "--" + CliStrings.START_SERVER__MAX__CONNECTIONS + "=" + 
launcher.getMaxConnections());
+    }
+
+    if (launcher.getMaxMessageCount() != null) {
+      commandLine.add("--" + CliStrings.START_SERVER__MAX__MESSAGE__COUNT + "="
+          + launcher.getMaxMessageCount());
+    }
+
+    if (launcher.getMaxThreads() != null) {
+      commandLine
+          .add("--" + CliStrings.START_SERVER__MAX__THREADS + "=" + 
launcher.getMaxThreads());
+    }
+
+    if (launcher.getMessageTimeToLive() != null) {
+      commandLine.add("--" + CliStrings.START_SERVER__MESSAGE__TIME__TO__LIVE 
+ "="
+          + launcher.getMessageTimeToLive());
+    }
+
+    if (launcher.getSocketBufferSize() != null) {
+      commandLine.add("--" + CliStrings.START_SERVER__SOCKET__BUFFER__SIZE + 
"="
+          + launcher.getSocketBufferSize());
+    }
+
+    if (launcher.getHostNameForClients() != null) {
+      commandLine.add("--" + CliStrings.START_SERVER__HOSTNAME__FOR__CLIENTS + 
"="
+          + launcher.getHostNameForClients());
+    }
+
+    return commandLine.toArray(new String[commandLine.size()]);
+  }
+
+  String getServerClasspath(final boolean includeSystemClasspath, final String 
userClasspath) {
+    List<String> jarFilePathnames = new ArrayList<>();
+
+    jarFilePathnames.add(StartMemberUtils.CORE_DEPENDENCIES_JAR_PATHNAME);
+
+    return StartMemberUtils.toClasspath(includeSystemClasspath,
+        jarFilePathnames.toArray(new String[jarFilePathnames.size()]), 
userClasspath);
+  }
+
+  private void addJvmOptionsForOutOfMemoryErrors(final List<String> 
commandLine) {
+    if (SystemUtils.isHotSpotVM()) {
+      if (SystemUtils.isWindows()) {
+        // ProcessBuilder "on Windows" needs every word (space separated) to be
+        // a different element in the array/list. See #47312. Need to study 
why!
+        commandLine.add("-XX:OnOutOfMemoryError=taskkill /F /PID %p");
+      } else { // All other platforms (Linux, Mac OS X, UNIX, etc)
+        commandLine.add("-XX:OnOutOfMemoryError=kill -KILL %p");
+      }
+    } else if (SystemUtils.isJ9VM()) {
+      // NOTE IBM states the following IBM J9 JVM command-line option/switch 
has side-effects on
+      // "performance",
+      // as noted in the reference documentation...
+      // 
http://publib.boulder.ibm.com/infocenter/javasdk/v6r0/index.jsp?topic=/com.ibm.java.doc.diagnostics.60/diag/appendixes/cmdline/commands_jvm.html
+      commandLine.add("-Xcheck:memory");
+    } else if (SystemUtils.isJRockitVM()) {
+      // NOTE the following Oracle JRockit JVM documentation was referenced to 
identify the
+      // appropriate JVM option to
+      // set when handling OutOfMemoryErrors.
+      // 
http://docs.oracle.com/cd/E13150_01/jrockit_jvm/jrockit/jrdocs/refman/optionXX.html
+      commandLine.add("-XXexitOnOutOfMemory");
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/fcce2b0b/geode-core/src/main/java/org/apache/geode/management/internal/web/controllers/LauncherLifecycleCommandsController.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/management/internal/web/controllers/LauncherLifecycleCommandsController.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/web/controllers/LauncherLifecycleCommandsController.java
index dcc1712..2e10842 100644
--- 
a/geode-core/src/main/java/org/apache/geode/management/internal/web/controllers/LauncherLifecycleCommandsController.java
+++ 
b/geode-core/src/main/java/org/apache/geode/management/internal/web/controllers/LauncherLifecycleCommandsController.java
@@ -24,8 +24,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
  * The LauncherLifecycleCommandsController class implements REST API calls for 
the Gfsh Launcher
  * Lifecycle commands.
  * <p/>
- * 
- * @see 
org.apache.geode.management.internal.cli.commands.LauncherLifecycleCommands
+ *
  * @see 
org.apache.geode.management.internal.web.controllers.AbstractCommandsController
  * @see org.springframework.stereotype.Controller
  * @see org.springframework.web.bind.annotation.PathVariable

http://git-wip-us.apache.org/repos/asf/geode/blob/fcce2b0b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/GfshCommandJUnitTest.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/GfshCommandJUnitTest.java
 
b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/GfshCommandJUnitTest.java
index 8ee27a6..67c3f5a 100644
--- 
a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/GfshCommandJUnitTest.java
+++ 
b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/GfshCommandJUnitTest.java
@@ -14,6 +14,14 @@
  */
 package org.apache.geode.management.internal.cli.commands;
 
+import static 
org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_BIND_ADDRESS;
+import static 
org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
+import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.NAME;
+import static 
org.apache.geode.distributed.ConfigurationProperties.START_DEV_REST_API;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -25,12 +33,12 @@ import org.apache.geode.cache.execute.Function;
 import org.apache.geode.cache.execute.FunctionService;
 import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.distributed.DistributedSystem;
+import org.apache.geode.distributed.internal.DistributionConfig;
 import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.internal.lang.StringUtils;
 import org.apache.geode.internal.util.CollectionUtils;
 import org.apache.geode.management.cli.CliMetaData;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
-import org.apache.geode.management.internal.cli.shell.Gfsh;
 import org.apache.geode.management.internal.cli.util.MemberNotFoundException;
 import org.apache.geode.test.junit.categories.UnitTest;
 import org.jmock.Expectations;
@@ -42,9 +50,13 @@ import org.junit.Before;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
+import java.io.File;
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
 import java.util.Set;
 
 /**
@@ -394,4 +406,222 @@ public class GfshCommandJUnitTest {
     }
   }
 
+  @Test
+  public void testAddGemFirePropertyFileToCommandLine() {
+    final List<String> commandLine = new ArrayList<>();
+    assertTrue(commandLine.isEmpty());
+    StartMemberUtils.addGemFirePropertyFile(commandLine, null);
+    assertTrue(commandLine.isEmpty());
+    StartMemberUtils.addGemFirePropertyFile(commandLine, 
org.apache.commons.lang.StringUtils.EMPTY);
+    assertTrue(commandLine.isEmpty());
+    StartMemberUtils.addGemFirePropertyFile(commandLine, " ");
+    assertTrue(commandLine.isEmpty());
+    StartMemberUtils.addGemFirePropertyFile(commandLine, 
"/path/to/gemfire.properties");
+    assertFalse(commandLine.isEmpty());
+    
assertTrue(commandLine.contains("-DgemfirePropertyFile=/path/to/gemfire.properties"));
+  }
+
+  @Test
+  public void testAddGemFireSystemPropertiesToCommandLine() {
+    final List<String> commandLine = new ArrayList<>();
+    assertTrue(commandLine.isEmpty());
+    StartMemberUtils.addGemFireSystemProperties(commandLine, new Properties());
+    assertTrue(commandLine.isEmpty());
+
+    final Properties gemfireProperties = new Properties();
+    gemfireProperties.setProperty(LOCATORS, "localhost[11235]");
+    gemfireProperties.setProperty(LOG_LEVEL, "config");
+    gemfireProperties.setProperty(LOG_FILE, 
org.apache.commons.lang.StringUtils.EMPTY);
+    gemfireProperties.setProperty(MCAST_PORT, "0");
+    gemfireProperties.setProperty(NAME, "machine");
+    StartMemberUtils.addGemFireSystemProperties(commandLine, 
gemfireProperties);
+
+    assertFalse(commandLine.isEmpty());
+    assertEquals(4, commandLine.size());
+
+    for (final String propertyName : gemfireProperties.stringPropertyNames()) {
+      final String propertyValue = gemfireProperties.getProperty(propertyName);
+      if (org.apache.commons.lang.StringUtils.isBlank(propertyValue)) {
+        for (final String systemProperty : commandLine) {
+          assertFalse(systemProperty.startsWith(
+              "-D" + DistributionConfig.GEMFIRE_PREFIX + 
"".concat(propertyName).concat("=")));
+        }
+      } else {
+        assertTrue(commandLine.contains("-D" + 
DistributionConfig.GEMFIRE_PREFIX
+            + "".concat(propertyName).concat("=").concat(propertyValue)));
+      }
+    }
+  }
+
+  @Test
+  public void testAddGemFireSystemPropertiesToCommandLineWithRestAPI() {
+    final List<String> commandLine = new ArrayList<>();
+    assertTrue(commandLine.isEmpty());
+    StartMemberUtils.addGemFireSystemProperties(commandLine, new Properties());
+    assertTrue(commandLine.isEmpty());
+    final Properties gemfireProperties = new Properties();
+    gemfireProperties.setProperty(LOCATORS, "localhost[11235]");
+    gemfireProperties.setProperty(LOG_LEVEL, "config");
+    gemfireProperties.setProperty(LOG_FILE, StringUtils.EMPTY);
+    gemfireProperties.setProperty(MCAST_PORT, "0");
+    gemfireProperties.setProperty(NAME, "machine");
+    gemfireProperties.setProperty(START_DEV_REST_API, "true");
+    gemfireProperties.setProperty(HTTP_SERVICE_PORT, "8080");
+    gemfireProperties.setProperty(HTTP_SERVICE_BIND_ADDRESS, "localhost");
+
+    StartMemberUtils.addGemFireSystemProperties(commandLine, 
gemfireProperties);
+
+    assertFalse(commandLine.isEmpty());
+    assertEquals(7, commandLine.size());
+
+    for (final String propertyName : gemfireProperties.stringPropertyNames()) {
+      final String propertyValue = gemfireProperties.getProperty(propertyName);
+      if (StringUtils.isBlank(propertyValue)) {
+        for (final String systemProperty : commandLine) {
+          assertFalse(systemProperty.startsWith(
+              "-D" + DistributionConfig.GEMFIRE_PREFIX + 
"".concat(propertyName).concat("=")));
+        }
+      } else {
+        assertTrue(commandLine.contains("-D" + 
DistributionConfig.GEMFIRE_PREFIX
+            + "".concat(propertyName).concat("=").concat(propertyValue)));
+      }
+    }
+  }
+
+  @Test
+  public void testAddInitialHeapToCommandLine() {
+    final List<String> commandLine = new ArrayList<>();
+    assertTrue(commandLine.isEmpty());
+    StartMemberUtils.addInitialHeap(commandLine, null);
+    assertTrue(commandLine.isEmpty());
+    StartMemberUtils.addInitialHeap(commandLine, 
org.apache.commons.lang.StringUtils.EMPTY);
+    assertTrue(commandLine.isEmpty());
+    StartMemberUtils.addInitialHeap(commandLine, " ");
+    assertTrue(commandLine.isEmpty());
+    StartMemberUtils.addInitialHeap(commandLine, "512M");
+    assertFalse(commandLine.isEmpty());
+    assertEquals("-Xms512M", commandLine.get(0));
+  }
+
+  @Test
+  public void testAddJvmArgumentsAndOptionsToCommandLine() {
+    final List<String> commandLine = new ArrayList<>();
+    assertTrue(commandLine.isEmpty());
+    StartMemberUtils.addJvmArgumentsAndOptions(commandLine, null);
+    assertTrue(commandLine.isEmpty());
+    StartMemberUtils.addJvmArgumentsAndOptions(commandLine, new String[] {});
+    assertTrue(commandLine.isEmpty());
+    StartMemberUtils.addJvmArgumentsAndOptions(commandLine,
+        new String[] {"-DmyProp=myVal", "-d64", "-server", "-Xprof"});
+    assertFalse(commandLine.isEmpty());
+    assertEquals(4, commandLine.size());
+    assertEquals("-DmyProp=myVal", commandLine.get(0));
+    assertEquals("-d64", commandLine.get(1));
+    assertEquals("-server", commandLine.get(2));
+    assertEquals("-Xprof", commandLine.get(3));
+  }
+
+  @Test
+  public void testAddMaxHeapToCommandLine() {
+    final List<String> commandLine = new ArrayList<>();
+    assertTrue(commandLine.isEmpty());
+    StartMemberUtils.addMaxHeap(commandLine, null);
+    assertTrue(commandLine.isEmpty());
+    StartMemberUtils.addMaxHeap(commandLine, 
org.apache.commons.lang.StringUtils.EMPTY);
+    assertTrue(commandLine.isEmpty());
+    StartMemberUtils.addMaxHeap(commandLine, "  ");
+    assertTrue(commandLine.isEmpty());
+    StartMemberUtils.addMaxHeap(commandLine, "1024M");
+    assertFalse(commandLine.isEmpty());
+    assertEquals(3, commandLine.size());
+    assertEquals("-Xmx1024M", commandLine.get(0));
+    assertEquals("-XX:+UseConcMarkSweepGC", commandLine.get(1));
+    assertEquals(
+        "-XX:CMSInitiatingOccupancyFraction=" + 
StartMemberUtils.CMS_INITIAL_OCCUPANCY_FRACTION,
+        commandLine.get(2));
+  }
+
+  @Test(expected = AssertionError.class)
+  public void testReadPidWithNull() {
+    try {
+      StartMemberUtils.readPid(null);
+    } catch (AssertionError expected) {
+      assertEquals("The file from which to read the process ID (pid) cannot be 
null!",
+          expected.getMessage());
+      throw expected;
+    }
+  }
+
+  @Test
+  public void testReadPidWithNonExistingFile() {
+    assertEquals(StartMemberUtils.INVALID_PID,
+        StartMemberUtils.readPid(new File("/path/to/non_existing/pid.file")));
+  }
+
+  @Test
+  public void testGetSystemClasspath() {
+    assertEquals(System.getProperty("java.class.path"), 
StartMemberUtils.getSystemClasspath());
+  }
+
+  @Test
+  public void testToClasspath() {
+    final boolean EXCLUDE_SYSTEM_CLASSPATH = false;
+    final boolean INCLUDE_SYSTEM_CLASSPATH = true;
+    String[] jarFilePathnames =
+        {"/path/to/user/libs/A.jar", "/path/to/user/libs/B.jar", 
"/path/to/user/libs/C.jar"};
+    String[] userClasspaths = 
{"/path/to/classes:/path/to/libs/1.jar:/path/to/libs/2.jar",
+        
"/path/to/ext/libs/1.jar:/path/to/ext/classes:/path/to/ext/lib/10.jar"};
+    String expectedClasspath = 
StartMemberUtils.GEODE_JAR_PATHNAME.concat(File.pathSeparator)
+        .concat(toClasspath(userClasspaths)).concat(File.pathSeparator)
+        .concat(toClasspath(jarFilePathnames));
+    assertEquals(expectedClasspath,
+        StartMemberUtils.toClasspath(EXCLUDE_SYSTEM_CLASSPATH, 
jarFilePathnames, userClasspaths));
+    expectedClasspath = 
StartMemberUtils.GEODE_JAR_PATHNAME.concat(File.pathSeparator)
+        .concat(toClasspath(userClasspaths)).concat(File.pathSeparator)
+        
.concat(System.getProperty("java.class.path")).concat(File.pathSeparator)
+        .concat(toClasspath(jarFilePathnames));
+    assertEquals(expectedClasspath,
+        StartMemberUtils.toClasspath(INCLUDE_SYSTEM_CLASSPATH, 
jarFilePathnames, userClasspaths));
+    expectedClasspath = 
StartMemberUtils.GEODE_JAR_PATHNAME.concat(File.pathSeparator)
+        .concat(System.getProperty("java.class.path"));
+    assertEquals(expectedClasspath,
+        StartMemberUtils.toClasspath(INCLUDE_SYSTEM_CLASSPATH, null, 
(String[]) null));
+    assertEquals(StartMemberUtils.GEODE_JAR_PATHNAME,
+        StartMemberUtils.toClasspath(EXCLUDE_SYSTEM_CLASSPATH, null, 
(String[]) null));
+    assertEquals(StartMemberUtils.GEODE_JAR_PATHNAME,
+        StartMemberUtils.toClasspath(EXCLUDE_SYSTEM_CLASSPATH, new String[0], 
""));
+  }
+
+  @Test
+  public void testToClassPathOrder() {
+    String userClasspathOne = "/path/to/user/lib/a.jar:/path/to/user/classes";
+    String userClasspathTwo =
+        
"/path/to/user/lib/x.jar:/path/to/user/lib/y.jar:/path/to/user/lib/z.jar";
+
+    String expectedClasspath = 
StartMemberUtils.getGemFireJarPath().concat(File.pathSeparator)
+        
.concat(userClasspathOne).concat(File.pathSeparator).concat(userClasspathTwo)
+        
.concat(File.pathSeparator).concat(System.getProperty("java.class.path"))
+        
.concat(File.pathSeparator).concat(StartMemberUtils.CORE_DEPENDENCIES_JAR_PATHNAME)
+        
.concat(File.pathSeparator).concat(StartMemberUtils.CORE_DEPENDENCIES_JAR_PATHNAME);
+
+    String actualClasspath =
+        StartMemberUtils.toClasspath(true,
+            new String[] {StartMemberUtils.CORE_DEPENDENCIES_JAR_PATHNAME,
+                StartMemberUtils.CORE_DEPENDENCIES_JAR_PATHNAME},
+            userClasspathOne, userClasspathTwo);
+
+    assertEquals(expectedClasspath, actualClasspath);
+  }
+
+  private String toClasspath(final String... jarFilePathnames) {
+    String classpath = org.apache.commons.lang.StringUtils.EMPTY;
+    if (jarFilePathnames != null) {
+      for (final String jarFilePathname : jarFilePathnames) {
+        classpath +=
+            (classpath.isEmpty() ? org.apache.commons.lang.StringUtils.EMPTY : 
File.pathSeparator);
+        classpath += jarFilePathname;
+      }
+    }
+    return classpath;
+  }
 }

Reply via email to