geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jinmeil...@apache.org
Subject [2/4] geode git commit: GEODE-3031: Extracting startLocator and startServer from LauncherLifecycleCommands
Date Tue, 25 Jul 2017 18:19:39 GMT
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;
+  }
 }


Mime
View raw message