Return-Path: X-Original-To: apmail-geode-commits-archive@minotaur.apache.org Delivered-To: apmail-geode-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 3AE4518605 for ; Thu, 25 Feb 2016 20:27:05 +0000 (UTC) Received: (qmail 59366 invoked by uid 500); 25 Feb 2016 20:27:05 -0000 Delivered-To: apmail-geode-commits-archive@geode.apache.org Received: (qmail 59331 invoked by uid 500); 25 Feb 2016 20:27:05 -0000 Mailing-List: contact commits-help@geode.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@geode.incubator.apache.org Delivered-To: mailing list commits@geode.incubator.apache.org Received: (qmail 59318 invoked by uid 99); 25 Feb 2016 20:27:05 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd1-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 25 Feb 2016 20:27:05 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd1-us-west.apache.org (ASF Mail Server at spamd1-us-west.apache.org) with ESMTP id 8DB33C0854 for ; Thu, 25 Feb 2016 20:27:04 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd1-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: 0.98 X-Spam-Level: X-Spam-Status: No, score=0.98 tagged_above=-999 required=6.31 tests=[KAM_LAZY_DOMAIN_SECURITY=1, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01] autolearn=disabled Received: from mx1-lw-us.apache.org ([10.40.0.8]) by localhost (spamd1-us-west.apache.org [10.40.0.7]) (amavisd-new, port 10024) with ESMTP id ICZ6sAKcT2EI for ; Thu, 25 Feb 2016 20:26:59 +0000 (UTC) Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx1-lw-us.apache.org (ASF Mail Server at mx1-lw-us.apache.org) with SMTP id 197515FBE8 for ; Thu, 25 Feb 2016 20:26:51 +0000 (UTC) Received: (qmail 56207 invoked by uid 99); 25 Feb 2016 20:26:49 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 25 Feb 2016 20:26:49 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id E08CAE8F1B; Thu, 25 Feb 2016 20:26:49 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: jensdeppe@apache.org To: commits@geode.incubator.apache.org Date: Thu, 25 Feb 2016 20:27:24 -0000 Message-Id: In-Reply-To: <73e7879c18f143a3b34041911bfd1983@git.apache.org> References: <73e7879c18f143a3b34041911bfd1983@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [36/50] [abbrv] incubator-geode git commit: Merge branch 'develop' into feature/GEODE-17 http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5c01d5f4/geode-core/src/main/java/com/gemstone/gemfire/management/internal/cli/commands/LauncherLifecycleCommands.java ---------------------------------------------------------------------- diff --cc geode-core/src/main/java/com/gemstone/gemfire/management/internal/cli/commands/LauncherLifecycleCommands.java index 0000000,8eae00b..3ec52e3 mode 000000,100755..100755 --- a/geode-core/src/main/java/com/gemstone/gemfire/management/internal/cli/commands/LauncherLifecycleCommands.java +++ b/geode-core/src/main/java/com/gemstone/gemfire/management/internal/cli/commands/LauncherLifecycleCommands.java @@@ -1,0 -1,2803 +1,2816 @@@ + /* + * 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 com.gemstone.gemfire.management.internal.cli.commands; + + import java.awt.Desktop; + import java.io.BufferedReader; + import java.io.BufferedWriter; + import java.io.File; + import java.io.FileFilter; + import java.io.FileNotFoundException; + import java.io.FileReader; + import java.io.FileWriter; + import java.io.IOException; + import java.io.InputStream; + import java.io.InputStreamReader; + import java.net.InetAddress; + import java.net.MalformedURLException; + import java.net.URI; + import java.net.UnknownHostException; + import java.util.ArrayList; + import java.util.Arrays; + import java.util.Collections; + import java.util.EmptyStackException; + import java.util.HashMap; + import java.util.HashSet; + import java.util.List; + import java.util.Map; + import java.util.Properties; + import java.util.Set; + import java.util.Stack; + import java.util.TreeSet; + import java.util.concurrent.TimeUnit; + import java.util.concurrent.atomic.AtomicReference; + + import javax.management.MalformedObjectNameException; + import javax.management.ObjectName; + import javax.management.Query; + import javax.management.QueryExp; + import javax.net.ssl.SSLException; + import javax.net.ssl.SSLHandshakeException; + + import com.gemstone.gemfire.GemFireException; + import com.gemstone.gemfire.SystemFailure; + import com.gemstone.gemfire.cache.server.CacheServer; + import com.gemstone.gemfire.distributed.AbstractLauncher; + import com.gemstone.gemfire.distributed.AbstractLauncher.ServiceState; + import com.gemstone.gemfire.distributed.AbstractLauncher.Status; + import com.gemstone.gemfire.distributed.LocatorLauncher; + import com.gemstone.gemfire.distributed.LocatorLauncher.LocatorState; + import com.gemstone.gemfire.distributed.ServerLauncher; + import com.gemstone.gemfire.distributed.ServerLauncher.ServerState; + import com.gemstone.gemfire.distributed.internal.DistributionConfig; + import com.gemstone.gemfire.distributed.internal.tcpserver.TcpClient; + import com.gemstone.gemfire.internal.DistributionLocator; + import com.gemstone.gemfire.internal.GemFireVersion; + import com.gemstone.gemfire.internal.OSProcess; + import com.gemstone.gemfire.internal.SocketCreator; + import com.gemstone.gemfire.internal.cache.persistence.PersistentMemberPattern; + import com.gemstone.gemfire.internal.i18n.LocalizedStrings; + import com.gemstone.gemfire.internal.lang.ClassUtils; + import com.gemstone.gemfire.internal.lang.ObjectUtils; + import com.gemstone.gemfire.internal.lang.StringUtils; + import com.gemstone.gemfire.internal.lang.SystemUtils; + import com.gemstone.gemfire.internal.process.ClusterConfigurationNotAvailableException; + import com.gemstone.gemfire.internal.process.NonBlockingProcessStreamReader; + import com.gemstone.gemfire.internal.process.ProcessLauncherContext; + import com.gemstone.gemfire.internal.process.ProcessStreamReader; + import com.gemstone.gemfire.internal.process.ProcessStreamReader.InputListener; + import com.gemstone.gemfire.internal.process.ProcessStreamReader.ReadingMode; + import com.gemstone.gemfire.internal.process.ProcessType; + import com.gemstone.gemfire.internal.process.ProcessUtils; + import com.gemstone.gemfire.internal.process.signal.SignalEvent; + import com.gemstone.gemfire.internal.process.signal.SignalListener; + import com.gemstone.gemfire.internal.util.IOUtils; + import com.gemstone.gemfire.internal.util.StopWatch; + import com.gemstone.gemfire.lang.AttachAPINotFoundException; + import com.gemstone.gemfire.management.DistributedSystemMXBean; + import com.gemstone.gemfire.management.MemberMXBean; + import com.gemstone.gemfire.management.cli.CliMetaData; + import com.gemstone.gemfire.management.cli.ConverterHint; + import com.gemstone.gemfire.management.cli.Result; + import com.gemstone.gemfire.management.internal.ManagementConstants; + import com.gemstone.gemfire.management.internal.cli.CliUtil; + import com.gemstone.gemfire.management.internal.cli.LogWrapper; + import com.gemstone.gemfire.management.internal.cli.converters.ConnectionEndpointConverter; + import com.gemstone.gemfire.management.internal.cli.domain.ConnectToLocatorResult; + import com.gemstone.gemfire.management.internal.cli.i18n.CliStrings; + import com.gemstone.gemfire.management.internal.cli.result.InfoResultData; + import com.gemstone.gemfire.management.internal.cli.result.ResultBuilder; + import com.gemstone.gemfire.management.internal.cli.shell.Gfsh; + import com.gemstone.gemfire.management.internal.cli.shell.JmxOperationInvoker; + import com.gemstone.gemfire.management.internal.cli.shell.OperationInvoker; + import com.gemstone.gemfire.management.internal.cli.util.CauseFinder; + import com.gemstone.gemfire.management.internal.cli.util.CommandStringBuilder; + import com.gemstone.gemfire.management.internal.cli.util.ConnectionEndpoint; + import com.gemstone.gemfire.management.internal.cli.util.JConsoleNotFoundException; + import com.gemstone.gemfire.management.internal.cli.util.VisualVmNotFoundException; + import com.gemstone.gemfire.management.internal.configuration.domain.SharedConfigurationStatus; + import com.gemstone.gemfire.management.internal.configuration.messages.SharedConfigurationStatusRequest; + import com.gemstone.gemfire.management.internal.configuration.messages.SharedConfigurationStatusResponse; - ++import com.gemstone.gemfire.management.internal.security.Resource; ++import com.gemstone.gemfire.management.internal.security.ResourceConstants; ++import com.gemstone.gemfire.management.internal.security.ResourceOperation; + import org.springframework.shell.core.annotation.CliAvailabilityIndicator; + import org.springframework.shell.core.annotation.CliCommand; + import org.springframework.shell.core.annotation.CliOption; + + /** + * The LauncherLifecycleCommands class encapsulates all GemFire launcher commands for GemFire tools (like starting + * GemFire Monitor (GFMon) and Visual Statistics Display (VSD)) as well external tools (like jconsole). + *

+ * @author John Blum + * @see com.gemstone.gemfire.distributed.LocatorLauncher + * @see com.gemstone.gemfire.distributed.ServerLauncher + * @see com.gemstone.gemfire.management.internal.cli.commands.AbstractCommandsSupport + * @see com.gemstone.gemfire.management.internal.cli.shell.Gfsh + * @since 7.0 + */ + @SuppressWarnings("unused") + public class LauncherLifecycleCommands extends AbstractCommandsSupport { + + private static final String LOCATOR_TERM_NAME = "Locator"; + private static final String SERVER_TERM_NAME = "Server"; + + private static final long PROCESS_STREAM_READER_JOIN_TIMEOUT_MILLIS = 30*1000; + private static final long PROCESS_STREAM_READER_ASYNC_STOP_TIMEOUT_MILLIS = 5*1000; + private static final long WAITING_FOR_STOP_TO_MAKE_PID_GO_AWAY_TIMEOUT_MILLIS = 30*1000; + private static final long WAITING_FOR_PID_FILE_TO_CONTAIN_PID_TIMEOUT_MILLIS = 2*1000; + + protected static final int CMS_INITIAL_OCCUPANCY_FRACTION = 60; + protected static final int DEFAULT_PROCESS_OUTPUT_WAIT_TIME_MILLISECONDS = 5000; + protected static final int INVALID_PID = -1; + protected static final int MINIMUM_HEAP_FREE_RATIO = 10; + protected static final int NUM_ATTEMPTS_FOR_SHARED_CONFIGURATION_STATUS = 3; + + protected static final AtomicReference ATTACH_API_AVAILABLE = new AtomicReference<>(null); + + protected static final String ATTACH_API_CLASS_NAME = "com.sun.tools.attach.AttachNotSupportedException"; + protected static final String GEMFIRE_HOME = System.getenv("GEMFIRE"); + protected static final String JAVA_HOME = System.getProperty("java.home"); + protected static final String LOCALHOST = "localhost"; + + // MUST CHANGE THIS TO REGEX SINCE VERSION CHANGES IN JAR NAME + protected static final String GEMFIRE_JAR_PATHNAME = IOUtils.appendToPath(GEMFIRE_HOME, "lib", GemFireVersion.getGemFireJarFileName()); + + protected static final String CORE_DEPENDENCIES_JAR_PATHNAME = + IOUtils.appendToPath(GEMFIRE_HOME, "lib", "geode-dependencies.jar"); + + protected static final String SPRING_AOP_JAR_NAME_PREFIX = "spring-aop"; + protected static final String SPRING_BEANS_JAR_NAME_PREFIX = "spring-beans"; + protected static final String SPRING_CONTEXT_JAR_NAME_PREFIX = "spring-context"; + protected static final String SPRING_CONTEXT_SUPPORT_JAR_NAME_PREFIX = "spring-context-support"; + protected static final String SPRING_DATA_COMMONS_JAR_NAME_PREFIX = "spring-data-commons"; + protected static final String SPRING_DATA_GEMFIRE_JAR_NAME_PREFIX = "spring-data-gemfire"; + protected static final String SPRING_EXPRESSION_JAR_NAME_PREFIX = "spring-expression"; + protected static final String SPRING_TX_JAR_NAME_PREFIX = "spring-tx"; + + protected static final Set SPRING_JAR_NAME_PREFIXES; + + static { + Set springJarNamePrefixes = new HashSet<>(8); + + springJarNamePrefixes.add(SPRING_AOP_JAR_NAME_PREFIX); + springJarNamePrefixes.add(SPRING_BEANS_JAR_NAME_PREFIX); + springJarNamePrefixes.add(SPRING_CONTEXT_JAR_NAME_PREFIX); + springJarNamePrefixes.add(SPRING_CONTEXT_SUPPORT_JAR_NAME_PREFIX); + springJarNamePrefixes.add(SPRING_DATA_COMMONS_JAR_NAME_PREFIX); + springJarNamePrefixes.add(SPRING_DATA_GEMFIRE_JAR_NAME_PREFIX); + springJarNamePrefixes.add(SPRING_EXPRESSION_JAR_NAME_PREFIX); + springJarNamePrefixes.add(SPRING_TX_JAR_NAME_PREFIX); + + SPRING_JAR_NAME_PREFIXES = Collections.unmodifiableSet(springJarNamePrefixes); + } + + protected static boolean isAttachApiAvailable() { + if (ATTACH_API_AVAILABLE.get() == null) { + try { + ClassUtils.forName(ATTACH_API_CLASS_NAME, new AttachAPINotFoundException()); + ATTACH_API_AVAILABLE.set(Boolean.TRUE); + } + catch (AttachAPINotFoundException ignore) { + ATTACH_API_AVAILABLE.set(Boolean.FALSE); + } + } + + return ATTACH_API_AVAILABLE.get(); + } + + @CliCommand(value = CliStrings.START_LOCATOR, help = CliStrings.START_LOCATOR__HELP) + @CliMetaData(shellOnly = true, relatedTopic = { CliStrings.TOPIC_GEMFIRE_LOCATOR, CliStrings.TOPIC_GEMFIRE_LIFECYCLE }) ++ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS) + public Result startLocator(@CliOption(key = CliStrings.START_LOCATOR__MEMBER_NAME, + mandatory = true, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_LOCATOR__MEMBER_NAME__HELP) + final String memberName, + @CliOption(key = CliStrings.START_LOCATOR__BIND_ADDRESS, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_LOCATOR__BIND_ADDRESS__HELP) + final String bindAddress, + @CliOption(key = CliStrings.START_LOCATOR__CLASSPATH, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + 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.START_LOCATOR__GROUP, + optionContext = ConverterHint.MEMBERGROUP, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_LOCATOR__GROUP__HELP) + final String group, + @CliOption(key = CliStrings.START_LOCATOR__HOSTNAME_FOR_CLIENTS, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_LOCATOR__HOSTNAME_FOR_CLIENTS__HELP) + final String hostnameForClients, + @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, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_LOCATOR__LOCATORS__HELP) + final String locators, + @CliOption(key = CliStrings.START_LOCATOR__LOG_LEVEL, + optionContext = ConverterHint.LOG_LEVEL, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_LOCATOR__LOG_LEVEL__HELP) + final String logLevel, + @CliOption(key = CliStrings.START_LOCATOR__MCAST_ADDRESS, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_LOCATOR__MCAST_ADDRESS__HELP) + final String mcastBindAddress, + @CliOption(key = CliStrings.START_LOCATOR__MCAST_PORT, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_LOCATOR__MCAST_PORT__HELP) + final Integer mcastPort, + @CliOption(key = CliStrings.START_LOCATOR__PORT, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_LOCATOR__PORT__HELP) + final Integer port, + @CliOption(key = CliStrings.START_LOCATOR__DIR, + optionContext = ConverterHint.DIR_PATHSTRING, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_LOCATOR__DIR__HELP) + String workingDirectory, + @CliOption(key = CliStrings.START_LOCATOR__PROPERTIES, + optionContext = ConverterHint.FILE_PATHSTRING, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_LOCATOR__PROPERTIES__HELP) + String gemfirePropertiesPathname, + @CliOption(key = CliStrings.START_LOCATOR__SECURITY_PROPERTIES, + optionContext = ConverterHint.FILE_PATHSTRING, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_LOCATOR__SECURITY_PROPERTIES__HELP) + String gemfireSecurityPropertiesPathname, + @CliOption(key = CliStrings.START_LOCATOR__INITIALHEAP, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_LOCATOR__INITIALHEAP__HELP) + final String initialHeap, + @CliOption(key = CliStrings.START_LOCATOR__MAXHEAP, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_LOCATOR__MAXHEAP__HELP) + final String maxHeap, + @CliOption(key = CliStrings.START_LOCATOR__J, + optionContext = ConverterHint.STRING_LIST, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_LOCATOR__J__HELP) + @CliMetaData(valueSeparator = ",") + 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 + ) { + try { + if (workingDirectory == null) { + // attempt to use or make sub-directory using memberName... + File locatorWorkingDirectory = new File(memberName); + + if (!(locatorWorkingDirectory.exists() || locatorWorkingDirectory.mkdir())) { + throw new IllegalStateException(CliStrings.format(CliStrings.START_LOCATOR__MSG__COULD_NOT_CREATE_DIRECTORY_0_VERIFY_PERMISSIONS, + locatorWorkingDirectory.getAbsolutePath())); + } + + workingDirectory = IOUtils.tryGetCanonicalPathElseGetAbsolutePath(locatorWorkingDirectory); + } + + gemfirePropertiesPathname = CliUtil.resolvePathname(gemfirePropertiesPathname); + + if (!StringUtils.isBlank(gemfirePropertiesPathname) && !IOUtils.isExistingPathname(gemfirePropertiesPathname)) { + return ResultBuilder.createUserErrorResult(CliStrings.format(CliStrings.GEMFIRE_0_PROPERTIES_1_NOT_FOUND_MESSAGE, + StringUtils.EMPTY_STRING, gemfirePropertiesPathname)); + } + + gemfireSecurityPropertiesPathname = CliUtil.resolvePathname(gemfireSecurityPropertiesPathname); + + if (!StringUtils.isBlank(gemfireSecurityPropertiesPathname) && !IOUtils.isExistingPathname(gemfireSecurityPropertiesPathname)) { + return ResultBuilder.createUserErrorResult(CliStrings.format(CliStrings.GEMFIRE_0_PROPERTIES_1_NOT_FOUND_MESSAGE, + "Security ", gemfireSecurityPropertiesPathname)); + } + + File locatorPidFile = new File(workingDirectory, ProcessType.LOCATOR.getPidFileName()); + + final int oldPid = readPid(locatorPidFile); + + Properties gemfireProperties = new Properties(); + + gemfireProperties.setProperty(DistributionConfig.GROUPS_NAME, StringUtils.valueOf(group, StringUtils.EMPTY_STRING)); + gemfireProperties.setProperty(DistributionConfig.LOCATORS_NAME, StringUtils.valueOf(locators, StringUtils.EMPTY_STRING)); + gemfireProperties.setProperty(DistributionConfig.LOG_LEVEL_NAME, StringUtils.valueOf(logLevel, StringUtils.EMPTY_STRING)); + gemfireProperties.setProperty(DistributionConfig.MCAST_ADDRESS_NAME, StringUtils.valueOf(mcastBindAddress, StringUtils.EMPTY_STRING)); + gemfireProperties.setProperty(DistributionConfig.MCAST_PORT_NAME, StringUtils.valueOf(mcastPort, StringUtils.EMPTY_STRING)); + gemfireProperties.setProperty(DistributionConfig.ENABLE_CLUSTER_CONFIGURATION_NAME, StringUtils.valueOf(enableSharedConfiguration, StringUtils.EMPTY_STRING)); + gemfireProperties.setProperty(DistributionConfig.LOAD_CLUSTER_CONFIG_FROM_DIR_NAME, StringUtils.valueOf(loadSharedConfigurationFromDirectory, StringUtils.EMPTY_STRING)); + gemfireProperties.setProperty(DistributionConfig.CLUSTER_CONFIGURATION_DIR, StringUtils.valueOf(clusterConfigDir, StringUtils.EMPTY_STRING)); + + // 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 locatorLauncher = new LocatorLauncher.Builder() + .setBindAddress(bindAddress) + .setForce(force) + .setHostnameForClients(hostnameForClients) + .setMemberName(memberName) + .setPort(port) + .setRedirectOutput(redirectOutput) + .setWorkingDirectory(workingDirectory) + .build(); + + String[] locatorCommandLine = createStartLocatorCommandLine(locatorLauncher, gemfirePropertiesPathname, + gemfireSecurityPropertiesPathname, gemfireProperties, classpath, includeSystemClasspath, jvmArgsOpts, initialHeap, maxHeap); + + //getGfsh().logInfo(StringUtils.concat(locatorCommandLine, " "), null); + + 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 ReadingMode readingMode = SystemUtils.isWindows() ? ReadingMode.NON_BLOCKING : ReadingMode.BLOCKING; + + final StringBuffer message = new StringBuffer(); // need thread-safe StringBuffer + InputListener inputListener = new InputListener() { + @Override + public void notifyInputLine(String line) { + message.append(line); + if (readingMode == 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(); + + 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); + + do { + try { + final int exitValue = locatorProcess.exitValue(); + + stderrReader.join(PROCESS_STREAM_READER_JOIN_TIMEOUT_MILLIS); // was Long.MAX_VALUE + + //Gfsh.println(message); + + return ResultBuilder.createShellClientErrorResult(String.format( + CliStrings.START_LOCATOR__PROCESS_TERMINATED_ABNORMALLY_ERROR_MESSAGE, + exitValue, locatorLauncher.getWorkingDirectory(), message.toString())); + } + catch (IllegalThreadStateException ignore) { + // the IllegalThreadStateException is expected; it means the Locator's process has not terminated, + // and basically should not + Gfsh.print("."); + + synchronized (this) { + TimeUnit.MILLISECONDS.timedWait(this, 500); + } + + locatorState = (ProcessUtils.isAttachApiAvailable() ? locatorStatus(locatorPidFile, oldPid, memberName) + : locatorStatus(workingDirectory, memberName)); + + String currentLocatorStatusMessage = locatorState.getStatusMessage(); + + if (isStartingOrNotResponding(locatorState.getStatus()) + && !(StringUtils.isBlank(currentLocatorStatusMessage) + || currentLocatorStatusMessage.equalsIgnoreCase(previousLocatorStatusMessage))) + { + Gfsh.println(); + Gfsh.println(currentLocatorStatusMessage); + previousLocatorStatusMessage = currentLocatorStatusMessage; + } + } + } + while (!(registeredLocatorSignalListener && locatorSignalListener.isSignaled()) + && isStartingOrNotResponding(locatorState.getStatus())); + } + finally { + stderrReader.stopAsync(PROCESS_STREAM_READER_ASYNC_STOP_TIMEOUT_MILLIS); // stop will close ErrorStream + getGfsh().getSignalHandler().unregisterListener(locatorSignalListener); + } + + Gfsh.println(); + + final boolean asyncStart = (registeredLocatorSignalListener && locatorSignalListener.isSignaled() + && isStartingNotRespondingOrNull(locatorState)); + + InfoResultData infoResultData = ResultBuilder.createInfoResultData(); + + if (asyncStart) { + infoResultData.addLine(String.format(CliStrings.ASYNC_PROCESS_LAUNCH_MESSAGE, LOCATOR_TERM_NAME)); + } + else { + infoResultData.addLine(locatorState.toString()); + + String locatorHostName = StringUtils.defaultIfBlank(locatorLauncher.getHostnameForClients(), getLocalHost()); + int locatorPort = locatorLauncher.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(getSharedConfigurationStatusFromLocator(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, 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), getLocatorId(bindAddress, port), + toString(t, getGfsh().getDebug())); + getGfsh().logToFile(errorMessage, t); + return ResultBuilder.createShellClientErrorResult(errorMessage); + } + finally { + Gfsh.redirectInternalJavaLoggers(); + } + } + + protected 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 commandLine = new ArrayList<>(); + + commandLine.add(getJavaPath()); + commandLine.add("-server"); + commandLine.add("-classpath"); + commandLine.add(getLocatorClasspath(Boolean.TRUE.equals(includeSystemClasspath), userClasspath)); + + addCurrentLocators(commandLine, gemfireProperties); + addGemFirePropertyFile(commandLine, gemfirePropertiesPathname); + addGemFireSecurityPropertyFile(commandLine, gemfireSecurityPropertiesPathname); + addGemFireSystemProperties(commandLine, gemfireProperties); + addJvmArgumentsAndOptions(commandLine, jvmArgsOpts); + addInitialHeap(commandLine, initialHeap); + 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.isBlank(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.isBlank(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()]); + } + + // 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 boolean 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 configurationProperties = loadConfigurationProperties(gemfireSecurityPropertiesPathname, + loadConfigurationProperties(gemfirePropertiesPathname)); + Map 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, null, configurationProperties, null)); + + String shellAndLogMessage = CliStrings.format(CliStrings.CONNECT__MSG__SUCCESS, 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 (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.isBlank(responseFailureMessage)) { + infoResultData.addLine("\n"); + infoResultData.addLine(responseFailureMessage); + } + + return connectSuccess; + } + + 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_STRING).append("SSL configuration"); + } + if (jmxManagerAuthEnabled || jmxManagerSslEnabled) { + message.append(" required to connect to the Manager."); + infoResultData.addLine("\n"); + infoResultData.addLine(message.toString()); + } + } + + private Map loadConfigurationProperties(final String configurationPropertiesPathname) { + return loadConfigurationProperties(configurationPropertiesPathname, null); + } + + private Map loadConfigurationProperties(final String configurationPropertiesPathname, + Map 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 String getSharedConfigurationStatusFromLocatorState(LocatorState locatorState) throws ClassNotFoundException, IOException { + return getSharedConfigurationStatusFromLocator(locatorState.getHost(), Integer.parseInt(locatorState.getPort())); + } + + private String getSharedConfigurationStatusFromLocator(String locatorHostName, int locatorPort) throws ClassNotFoundException, IOException { + final StringBuilder buffer = new StringBuilder(); + + try { + final InetAddress networkAddress = InetAddress.getByName(locatorHostName); + + SharedConfigurationStatusResponse statusResponse = (SharedConfigurationStatusResponse) + TcpClient.requestToServer(networkAddress, locatorPort, new SharedConfigurationStatusRequest(), 10000, true); + + for (int i=0; i pmpSet = statusResponse.getOtherLocatorInformation(); + if (!pmpSet.isEmpty()) { + buffer.append("\nThis locator might have stale cluster configuration data."); + buffer.append("\nFollowing locators contain potentially newer cluster configuration data"); + + for (PersistentMemberPattern pmp : pmpSet) { + buffer.append("\nHost : ").append(pmp.getHost()); + buffer.append("\nDirectory : ").append(pmp.getDirectory()); + } + } + else { + buffer.append("\nPlease check the log file for errors"); + } + break; + case UNDETERMINED: + buffer.append("\nUnable to determine the status of shared configuration service, please check the log file"); + break; + case NOT_STARTED: + buffer.append("\nCluster configuration service has not been started yet"); + break; + case STARTED: + buffer.append("\nCluster configuration service has been started, but its not running yet"); + break; + } + } + catch (Exception e) { + // TODO fix this once Trac Bug #50513 gets fixed + // NOTE this ClassCastException occurs if the a plain text TCP/IP connection is used to connect to a Locator + // configured with SSL. + getGfsh().logToFile(String.format("Failed to get the status of the Shared Configuration Service running on Locator (%1$s[%2$d])!", + locatorHostName, locatorPort), e); + } + + return buffer.toString(); + } + + @CliCommand(value = CliStrings.STATUS_LOCATOR, help = CliStrings.STATUS_LOCATOR__HELP) + @CliMetaData(shellOnly = true, relatedTopic = { CliStrings.TOPIC_GEMFIRE_LOCATOR, CliStrings.TOPIC_GEMFIRE_LIFECYCLE }) ++ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS) + public Result statusLocator(@CliOption(key = CliStrings.STATUS_LOCATOR__MEMBER, + optionContext = ConverterHint.LOCATOR_MEMBER_IDNAME, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.STATUS_LOCATOR__MEMBER__HELP) + final String member, + @CliOption(key = CliStrings.STATUS_LOCATOR__HOST, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.STATUS_LOCATOR__HOST__HELP) + final String locatorHost, + @CliOption(key = CliStrings.STATUS_LOCATOR__PORT, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.STATUS_LOCATOR__PORT__HELP) + final Integer locatorPort, + @CliOption(key = CliStrings.STATUS_LOCATOR__PID, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.STATUS_LOCATOR__PID__HELP) + final Integer pid, + @CliOption(key = CliStrings.STATUS_LOCATOR__DIR, + optionContext = ConverterHint.DIR_PATHSTRING, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.STATUS_LOCATOR__DIR__HELP) + final String workingDirectory) + { + try { + if (!StringUtils.isBlank(member)) { + if (isConnectedAndReady()) { + final MemberMXBean locatorProxy = getMemberMXBean(member); + + if (locatorProxy != null) { + LocatorState state = LocatorState.fromJson(locatorProxy.status()); + return createStatusLocatorResult(state); + } + else { + return ResultBuilder.createUserErrorResult(CliStrings.format( + CliStrings.STATUS_LOCATOR__NO_LOCATOR_FOUND_FOR_MEMBER_ERROR_MESSAGE, member)); + } + } + else { + return ResultBuilder.createUserErrorResult(CliStrings.format( + CliStrings.STATUS_SERVICE__GFSH_NOT_CONNECTED_ERROR_MESSAGE, LOCATOR_TERM_NAME)); + } + } + else { + final LocatorLauncher locatorLauncher = new LocatorLauncher.Builder() + .setCommand(LocatorLauncher.Command.STATUS) + .setBindAddress(locatorHost) + .setDebug(isDebugging()) + .setPid(pid) + .setPort(locatorPort) + .setWorkingDirectory(workingDirectory) + .build(); + + final LocatorState state = locatorLauncher.status(); + return createStatusLocatorResult(state); + } + } + catch (IllegalArgumentException e) { + return ResultBuilder.createUserErrorResult(e.getMessage()); + } + catch (IllegalStateException e) { + return ResultBuilder.createUserErrorResult(e.getMessage()); + } + catch (VirtualMachineError e) { + SystemFailure.initiateFailure(e); + throw e; + } + catch (Throwable t) { + SystemFailure.checkFailure(); + return ResultBuilder.createShellClientErrorResult(String.format(CliStrings.STATUS_LOCATOR__GENERAL_ERROR_MESSAGE, + getLocatorId(locatorHost, locatorPort), StringUtils.defaultIfBlank(workingDirectory, SystemUtils.CURRENT_DIRECTORY), + toString(t, getGfsh().getDebug()))); + } + } + + @CliCommand(value=CliStrings.STOP_LOCATOR, help=CliStrings.STOP_LOCATOR__HELP) + @CliMetaData(shellOnly=true, relatedTopic = {CliStrings.TOPIC_GEMFIRE_LOCATOR, CliStrings.TOPIC_GEMFIRE_LIFECYCLE}) ++ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS) + public Result stopLocator(@CliOption(key = CliStrings.STOP_LOCATOR__MEMBER, + optionContext = ConverterHint.LOCATOR_MEMBER_IDNAME, + unspecifiedDefaultValue=CliMetaData.ANNOTATION_NULL_VALUE, + help=CliStrings.STOP_LOCATOR__MEMBER__HELP) + final String member, + @CliOption(key=CliStrings.STOP_LOCATOR__PID, + unspecifiedDefaultValue=CliMetaData.ANNOTATION_NULL_VALUE, + help=CliStrings.STOP_LOCATOR__PID__HELP) + final Integer pid, + @CliOption(key=CliStrings.STOP_LOCATOR__DIR, + optionContext = ConverterHint.DIR_PATHSTRING, + unspecifiedDefaultValue=CliMetaData.ANNOTATION_NULL_VALUE, + help=CliStrings.STOP_LOCATOR__DIR__HELP) + final String workingDirectory) + { + LocatorState locatorState; + + try { + if (!StringUtils.isBlank(member)) { + if (isConnectedAndReady()) { + final MemberMXBean locatorProxy = getMemberMXBean(member); + + if (locatorProxy != null) { + if (!locatorProxy.isLocator()) { + throw new IllegalStateException(CliStrings.format(CliStrings.STOP_LOCATOR__NOT_LOCATOR_ERROR_MESSAGE, member)); + } + + if (locatorProxy.isServer()) { + throw new IllegalStateException(CliStrings.format(CliStrings.STOP_LOCATOR__LOCATOR_IS_CACHE_SERVER_ERROR_MESSAGE, member)); + } + + locatorState = LocatorState.fromJson(locatorProxy.status()); + locatorProxy.shutDownMember(); + } + else { + return ResultBuilder.createUserErrorResult(CliStrings.format( + CliStrings.STOP_LOCATOR__NO_LOCATOR_FOUND_FOR_MEMBER_ERROR_MESSAGE, member)); + } + } + else { + return ResultBuilder.createUserErrorResult(CliStrings.format( + CliStrings.STOP_SERVICE__GFSH_NOT_CONNECTED_ERROR_MESSAGE, LOCATOR_TERM_NAME)); + } + } + else { + final LocatorLauncher locatorLauncher = new LocatorLauncher.Builder() + .setCommand(LocatorLauncher.Command.STOP) + .setDebug(isDebugging()) + .setPid(pid) + .setWorkingDirectory(workingDirectory) + .build(); + + locatorState = locatorLauncher.status(); + locatorLauncher.stop(); + } + + if (Status.ONLINE.equals(locatorState.getStatus())) { + getGfsh().logInfo(String.format(CliStrings.STOP_LOCATOR__STOPPING_LOCATOR_MESSAGE, + locatorState.getWorkingDirectory(), locatorState.getServiceLocation(), locatorState.getMemberName(), + locatorState.getPid(), locatorState.getLogFile()), null); + + StopWatch stopWatch = new StopWatch(true); + while (isVmWithProcessIdRunning(locatorState.getPid())) { + Gfsh.print("."); + if (stopWatch.elapsedTimeMillis() > WAITING_FOR_STOP_TO_MAKE_PID_GO_AWAY_TIMEOUT_MILLIS) { + break; + } + synchronized (this) { + TimeUnit.MILLISECONDS.timedWait(this, 500); + } + } + + return ResultBuilder.createInfoResult(StringUtils.EMPTY_STRING); + } + else { + return ResultBuilder.createUserErrorResult(locatorState.toString()); + } + } + catch (IllegalArgumentException e) { + return ResultBuilder.createUserErrorResult(e.getMessage()); + } + catch (IllegalStateException e) { + return ResultBuilder.createUserErrorResult(e.getMessage()); + } + catch (VirtualMachineError e) { + SystemFailure.initiateFailure(e); + throw e; + } + catch (Throwable t) { + SystemFailure.checkFailure(); + return ResultBuilder.createShellClientErrorResult(String.format(CliStrings.STOP_LOCATOR__GENERAL_ERROR_MESSAGE, + toString(t, getGfsh().getDebug()))); + } finally { + Gfsh.redirectInternalJavaLoggers(); + } + } + + // TODO re-evaluate whether a MalformedObjectNameException should be thrown here; just because we were not able to find + // the "current" Locators in order to conveniently add the new member to the GemFire cluster does not mean we should + // throw an Exception! + protected void addCurrentLocators(final List commandLine, final Properties gemfireProperties) throws MalformedObjectNameException { + if (StringUtils.isBlank(gemfireProperties.getProperty(DistributionConfig.LOCATORS_NAME))) { + String currentLocators = getCurrentLocators(); + + if (!StringUtils.isBlank(currentLocators)) { + commandLine.add("-D".concat(ProcessLauncherContext.OVERRIDDEN_DEFAULTS_PREFIX) + .concat(DistributionConfig.LOCATORS_NAME).concat("=").concat(currentLocators)); + } + } + } + + protected Result createStatusLocatorResult(final LocatorState state) throws NumberFormatException, IOException, ClassNotFoundException { + InfoResultData infoResultData = ResultBuilder.createInfoResultData(); + infoResultData.addLine(state.toString()); + infoResultData.addLine(getSharedConfigurationStatusFromLocatorState(state)); + return ResultBuilder.buildResult(infoResultData); + } + + protected void addGemFirePropertyFile(final List commandLine, final String gemfirePropertiesPathname) { + if (!StringUtils.isBlank(gemfirePropertiesPathname)) { + commandLine.add("-DgemfirePropertyFile=" + gemfirePropertiesPathname); + } + } + + protected void addGemFireSecurityPropertyFile(final List commandLine, final String gemfireSecurityPropertiesPathname) { + if (!StringUtils.isBlank(gemfireSecurityPropertiesPathname)) { + commandLine.add("-DgemfireSecurityPropertyFile=" + gemfireSecurityPropertiesPathname); + } + } + + protected void addGemFireSystemProperties(final List commandLine, final Properties gemfireProperties) { + for (final Object property : gemfireProperties.keySet()) { + final String propertyName = property.toString(); + final String propertyValue = gemfireProperties.getProperty(propertyName); + if (!StringUtils.isBlank(propertyValue)) { + commandLine.add("-Dgemfire." + propertyName + "=" + propertyValue); + } + } + } + + protected void addInitialHeap(final List commandLine, final String initialHeap) { + if (!StringUtils.isBlank(initialHeap)) { + commandLine.add("-Xms" + initialHeap); + } + } + + protected void addJvmArgumentsAndOptions(final List commandLine, final String[] jvmArgsOpts) { + if (jvmArgsOpts != null) { + commandLine.addAll(Arrays.asList(jvmArgsOpts)); + } + } + + // Fix for Bug #47192 - "Causing the GemFire member (JVM process) to exit on OutOfMemoryErrors" + protected void addJvmOptionsForOutOfMemoryErrors(final List 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"); + } + } + + protected void addMaxHeap(final List commandLine, final String maxHeap) { + if (!StringUtils.isBlank(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); + } + } + + protected LocatorState locatorStatus(final File locatorPidFile, final int oldPid, final String memberName) { + final int newPid = readPid(locatorPidFile); + + if (newPid != INVALID_PID && newPid != oldPid) { + LocatorState locatorState = new LocatorLauncher.Builder().setPid(newPid).build().status(); + + if (ObjectUtils.equals(locatorState.getMemberName(), memberName)) { + return locatorState; + } + } + + return new LocatorState(new LocatorLauncher.Builder().build(), Status.NOT_RESPONDING); + } + + protected LocatorState locatorStatus(final String workingDirectory, final String memberName) { + LocatorState locatorState = new LocatorLauncher.Builder().setWorkingDirectory(workingDirectory).build().status(); + + if (ObjectUtils.equals(locatorState.getMemberName(), memberName)) { + return locatorState; + } + + return new LocatorState(new LocatorLauncher.Builder().build(), Status.NOT_RESPONDING); + } + + protected String readErrorStream(final Process process) throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream())); + StringBuilder message = new StringBuilder(); + + for (String line = reader.readLine(); line != null; line = reader.readLine()) { + message.append(line); + message.append(StringUtils.LINE_SEPARATOR); + } + + IOUtils.close(reader); + + return message.toString(); + } + + protected 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 ignore) { + } + catch (NumberFormatException ignore) { + } + finally { + IOUtils.close(fileReader); + } + } + + return INVALID_PID; + } + + protected ServerState serverStatus(final File serverPidFile, final int oldPid, final String memberName) { + final int newPid = readPid(serverPidFile); + + if (newPid != INVALID_PID && newPid != oldPid) { + ServerState serverState = new ServerLauncher.Builder().setPid(newPid).setDisableDefaultServer(true) + .build().status(); + + if (ObjectUtils.equals(serverState.getMemberName(), memberName)) { + return serverState; + } + } + + return new ServerState(new ServerLauncher.Builder().build(), Status.NOT_RESPONDING); + } + + protected ServerState serverStatus(final String workingDirectory, final String memberName) { + ServerState serverState = new ServerLauncher.Builder().setWorkingDirectory(workingDirectory) + .setDisableDefaultServer(true).build().status(); + + if (ObjectUtils.equals(serverState.getMemberName(), memberName)) { + return serverState; + } + + return new ServerState(new ServerLauncher.Builder().build(), Status.NOT_RESPONDING); + } + + @Deprecated + protected String getClasspath(final String userClasspath) { + String classpath = getSystemClasspath(); + + if (!StringUtils.isBlank(userClasspath)) { + classpath += (File.pathSeparator + userClasspath); + } + + return classpath; + } + + protected String getLocatorClasspath(final boolean includeSystemClasspath, final String userClasspath) { + return toClasspath(includeSystemClasspath, new String[] { CORE_DEPENDENCIES_JAR_PATHNAME }, userClasspath); + } + + protected String getServerClasspath(final boolean includeSystemClasspath, + final boolean includeSpringDependencies, + final String userClasspath) + { + List jarFilePathnames = new ArrayList<>(); + + jarFilePathnames.add(CORE_DEPENDENCIES_JAR_PATHNAME); + + if (includeSpringDependencies) { + jarFilePathnames.addAll(getSpringJars()); + } + + return toClasspath(includeSystemClasspath, jarFilePathnames.toArray(new String[jarFilePathnames.size()]), + userClasspath); + } + + protected List getSpringJars() { + File gemfireHomeDirectory= new File(GEMFIRE_HOME); + + assertArgument(gemfireHomeDirectory.isDirectory(), + "Please set the GEMFIRE environment variable to the product installation directory."); + + List springJarFilePathnames = new ArrayList<>(SPRING_JAR_NAME_PREFIXES.size()); + + for (File jarFile : new File(gemfireHomeDirectory, "lib").listFiles(new FileFilter() { + @Override public boolean accept(final File pathname) { + return (pathname.getName().startsWith("spring-") && pathname.getAbsolutePath().endsWith(".jar")); + } + })) { + String jarFileName = jarFile.getName(); + String jarFileNamePrefix = jarFileName.substring(0, jarFileName.lastIndexOf("-")); + + if (SPRING_JAR_NAME_PREFIXES.contains(jarFileNamePrefix.toLowerCase().trim())) { + springJarFilePathnames.add(jarFile.getAbsolutePath()); + } + } + + assertState(springJarFilePathnames.size() == SPRING_JAR_NAME_PREFIXES.size(), + "Unable to find all the necessary Spring JAR files in $GEMFIRE/lib (%1$s): expected (%2$s); but was (%3$s)", + gemfireHomeDirectory, SPRING_JAR_NAME_PREFIXES, springJarFilePathnames); + + return springJarFilePathnames; + } + + protected String getSystemClasspath() { + return System.getProperty("java.class.path"); + } + + String toClasspath(final boolean includeSystemClasspath, String[] jarFilePathnames, String... userClasspaths) { + // gemfire jar must absolutely be the first JAR file on the CLASSPATH!!! + String classpath = getGemFireJarPath(); + + userClasspaths = (userClasspaths != null ? userClasspaths : StringUtils.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 (!StringUtils.isBlank(userClasspath)) { + classpath += (classpath.isEmpty() ? StringUtils.EMPTY_STRING : File.pathSeparator); + classpath += userClasspath; + } + } + + // Now, include any System-specified CLASSPATH environment variable setting... + if (includeSystemClasspath) { + classpath += File.pathSeparator; + classpath += getSystemClasspath(); + } + + jarFilePathnames = (jarFilePathnames != null ? jarFilePathnames : StringUtils.EMPTY_STRING_ARRAY); + + // And finally, include all GemFire dependencies on the CLASSPATH... + for (String jarFilePathname : jarFilePathnames) { + if (!StringUtils.isBlank(jarFilePathname)) { + classpath += (classpath.isEmpty() ? StringUtils.EMPTY_STRING : File.pathSeparator); + classpath += jarFilePathname; + } + } + + return classpath; + } + + protected String getGemFireJarPath() { + String classpath = getSystemClasspath(); + String gemfireJarPath = GEMFIRE_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; + } + + protected String getJavaPath() { + return new File(new File(JAVA_HOME, "bin"), "java").getPath(); + } + + @Deprecated + protected String getToolsJarPath() throws AttachAPINotFoundException { + String toolsJarPathname = null; + + if (!SystemUtils.isMacOSX()) { + toolsJarPathname = IOUtils.appendToPath(JAVA_HOME, "lib", "tools.jar"); + + if (!IOUtils.isExistingPathname(toolsJarPathname)) { + // perhaps the java.home System property refers to the JRE ($JAVA_HOME/jre)... + String JDK_HOME = new File(JAVA_HOME).getParentFile().getPath(); + toolsJarPathname = IOUtils.appendToPath(JDK_HOME, "lib", "tools.jar"); + } + + try { + IOUtils.verifyPathnameExists(toolsJarPathname); + } + catch (IOException e) { + throw new AttachAPINotFoundException(getAttachAPINotFoundMessage()); + } + } + + return toolsJarPathname; + } + + // TODO refactor the following method into a common base class or utility class + protected String getLocalHost() { + try { + return SocketCreator.getLocalHost().getCanonicalHostName(); + } + catch (UnknownHostException ignore) { + return LOCALHOST; + } + } + + protected String getAttachAPINotFoundMessage() { + return CliStrings.format(CliStrings.ATTACH_API_IN_0_NOT_FOUND_ERROR_MESSAGE, + ((SystemUtils.isMacOSX() && SystemUtils.isAppleJVM()) ? "classes.jar" : "tools.jar")); + } + + protected String getLocatorId(final String host, final Integer port) { + final String locatorHost = (host != null ? host : getLocalHost()); + final String locatorPort = StringUtils.valueOf(port, String.valueOf(DistributionLocator.DEFAULT_LOCATOR_PORT)); + return locatorHost.concat("[").concat(locatorPort).concat("]"); + } + + /** + * Gets a proxy to the DistributedSystemMXBean from the GemFire Manager's MBeanServer, or null if unable to find + * the DistributedSystemMXBean. + *

+ * @return a proxy to the DistributedSystemMXBean from the GemFire Manager's MBeanServer, or null if unable to find + * the DistributedSystemMXBean. + */ + protected DistributedSystemMXBean getDistributedSystemMXBean() throws IOException, MalformedObjectNameException { + assertState(isConnectedAndReady(), "Gfsh must be connected in order to get proxy to a GemFire DistributedSystemMXBean."); + return getGfsh().getOperationInvoker().getDistributedSystemMXBean(); + } + + /** + * Gets a proxy to the MemberMXBean for the GemFire member specified by member name or ID from the GemFire Manager's + * MBeanServer. + *

+ * @param member a String indicating the GemFire member's name or ID. + * @return a proxy to the MemberMXBean having the specified GemFire member's name or ID from the GemFire Manager's + * MBeanServer, or null if no GemFire member could be found with the specified member name or ID. + * @see #getMemberMXBean(String, String) + */ + protected MemberMXBean getMemberMXBean(final String member) throws IOException { + return getMemberMXBean(null, member); + } + + protected MemberMXBean getMemberMXBean(final String serviceName, final String member) throws IOException { + assertState(isConnectedAndReady(), "Gfsh must be connected in order to get proxy to a GemFire Member MBean."); + + MemberMXBean memberBean = null; + + try { + String objectNamePattern = ManagementConstants.OBJECTNAME__PREFIX; + + objectNamePattern += (StringUtils.isBlank(serviceName) ? StringUtils.EMPTY_STRING + : "service=" + serviceName + StringUtils.COMMA_DELIMITER); + objectNamePattern += "type=Member,*"; + + // NOTE throws a MalformedObjectNameException, however, this should not happen since the ObjectName is constructed + // here in a conforming pattern + final ObjectName objectName = ObjectName.getInstance(objectNamePattern); + + final QueryExp query = Query.or( + Query.eq(Query.attr("Name"), Query.value(member)), + Query.eq(Query.attr("Id"), Query.value(member)) + ); + + final Set memberObjectNames = getGfsh().getOperationInvoker().queryNames(objectName, query); + + if (!memberObjectNames.isEmpty()) { + memberBean = getGfsh().getOperationInvoker().getMBeanProxy(memberObjectNames.iterator().next(), MemberMXBean.class); + } + } + catch (MalformedObjectNameException e) { + getGfsh().logSevere(e.getMessage(), e); + } + + return memberBean; + } + + protected String getServerId(final String host, final Integer port) { + String serverHost = (host != null ? host : getLocalHost()); + String serverPort = StringUtils.valueOf(port, String.valueOf(CacheServer.DEFAULT_PORT)); + return serverHost.concat("[").concat(serverPort).concat("]"); + } + + protected boolean isStartingNotRespondingOrNull(final ServiceState serviceState) { + return (serviceState == null || isStartingOrNotResponding(serviceState.getStatus())); + } + + protected boolean isStartingOrNotResponding(final Status processStatus) { + return (Status.NOT_RESPONDING.equals(processStatus) || Status.STARTING.equals(processStatus)); + } + + protected boolean isVmWithProcessIdRunning(final Integer pid) { + // note: this will use JNA if available or Attach if available or return false if neither is available + return ProcessUtils.isProcessAlive(pid); + } + + @CliCommand(value = CliStrings.START_SERVER, help = CliStrings.START_SERVER__HELP) + @CliMetaData(shellOnly = true, relatedTopic = { CliStrings.TOPIC_GEMFIRE_SERVER, CliStrings.TOPIC_GEMFIRE_LIFECYCLE }) ++ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS) + public Result startServer(@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, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__BIND_ADDRESS__HELP) + final String bindAddress, + @CliOption(key = CliStrings.START_SERVER__CACHE_XML_FILE, + optionContext = ConverterHint.FILE_PATHSTRING, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__CACHE_XML_FILE__HELP) + String cacheXmlPathname, + @CliOption(key = CliStrings.START_SERVER__CLASSPATH, + /*optionContext = ConverterHint.FILE_PATHSTRING, // there's an issue with TAB here*/ + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__CLASSPATH__HELP) + final String classpath, + @CliOption(key = CliStrings.START_SERVER__CRITICAL__HEAP__PERCENTAGE, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__CRITICAL__HEAP__HELP) + final Float criticalHeapPercentage, + @CliOption(key = CliStrings.START_SERVER__CRITICAL_OFF_HEAP_PERCENTAGE, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__CRITICAL_OFF_HEAP__HELP) + final Float criticalOffHeapPercentage, + @CliOption(key = CliStrings.START_SERVER__DIR, + optionContext = ConverterHint.DIR_PATHSTRING, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + 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, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + specifiedDefaultValue = "true", + help = CliStrings.START_SERVER__ENABLE_TIME_STATISTICS__HELP) + final Boolean enableTimeStatistics, + @CliOption(key = CliStrings.START_SERVER__EVICTION__HEAP__PERCENTAGE, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__EVICTION__HEAP__PERCENTAGE__HELP) + final Float evictionHeapPercentage, + @CliOption(key = CliStrings.START_SERVER__EVICTION_OFF_HEAP_PERCENTAGE, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + 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.START_SERVER__GROUP, + optionContext = ConverterHint.MEMBERGROUP, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__GROUP__HELP) + final String group, + @CliOption(key = CliStrings.START_SERVER__HOSTNAME__FOR__CLIENTS, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__HOSTNAME__FOR__CLIENTS__HELP) + final String hostNameForClients, + @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, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__INITIAL_HEAP__HELP) + final String initialHeap, + @CliOption(key = CliStrings.START_SERVER__J, + optionContext = ConverterHint.STRING_LIST, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__J__HELP) + @CliMetaData(valueSeparator = ",") + final String[] jvmArgsOpts, + @CliOption(key = CliStrings.START_SERVER__LOCATORS, + optionContext = ConverterHint.LOCATOR_DISCOVERY_CONFIG, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__LOCATORS__HELP) + final String locators, + @CliOption(key = CliStrings.START_SERVER__LOCATOR_WAIT_TIME, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__LOCATOR_WAIT_TIME_HELP) + final Integer locatorWaitTime, + @CliOption(key = CliStrings.START_SERVER__LOCK_MEMORY, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + specifiedDefaultValue = "true", + help = CliStrings.START_SERVER__LOCK_MEMORY__HELP) + final Boolean lockMemory, + @CliOption(key = CliStrings.START_SERVER__LOG_LEVEL, + optionContext = ConverterHint.LOG_LEVEL, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__LOG_LEVEL__HELP) + final String logLevel, + @CliOption(key = CliStrings.START_SERVER__MAX__CONNECTIONS, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__MAX__CONNECTIONS__HELP) + final Integer maxConnections, + @CliOption(key = CliStrings.START_SERVER__MAXHEAP, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__MAXHEAP__HELP) + final String maxHeap, + @CliOption(key = CliStrings.START_SERVER__MAX__MESSAGE__COUNT, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__MAX__MESSAGE__COUNT__HELP) + final Integer maxMessageCount, + @CliOption(key = CliStrings.START_SERVER__MAX__THREADS, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__MAX__THREADS__HELP) + final Integer maxThreads, + @CliOption(key = CliStrings.START_SERVER__MCAST_ADDRESS, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__MCAST_ADDRESS__HELP) + final String mcastBindAddress, + @CliOption(key = CliStrings.START_SERVER__MCAST_PORT, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__MCAST_PORT__HELP) + final Integer mcastPort, + @CliOption(key = CliStrings.START_SERVER__MEMCACHED_PORT, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__MEMCACHED_PORT__HELP) + final Integer memcachedPort, + @CliOption(key = CliStrings.START_SERVER__MEMCACHED_PROTOCOL, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__MEMCACHED_PROTOCOL__HELP) + final String memcachedProtocol, + @CliOption(key = CliStrings.START_SERVER__MEMCACHED_BIND_ADDRESS, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__MEMCACHED_BIND_ADDRESS__HELP) + final String memcachedBindAddress, + @CliOption(key = CliStrings.START_SERVER__REDIS_PORT, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__REDIS_PORT__HELP) + final Integer redisPort, + @CliOption(key = CliStrings.START_SERVER__REDIS_BIND_ADDRESS, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__REDIS_BIND_ADDRESS__HELP) + final String redisBindAddress, + @CliOption(key = CliStrings.START_SERVER__REDIS_PASSWORD, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__REDIS_PASSWORD__HELP) + final String redisPassword, + @CliOption(key = CliStrings.START_SERVER__MESSAGE__TIME__TO__LIVE, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__MESSAGE__TIME__TO__LIVE__HELP) + final Integer messageTimeToLive, + @CliOption(key = CliStrings.START_SERVER__NAME, + mandatory = true, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__NAME__HELP) + final String memberName, + @CliOption(key = CliStrings.START_SERVER__OFF_HEAP_MEMORY_SIZE, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__OFF_HEAP_MEMORY_SIZE__HELP) + final String offHeapMemorySize, + @CliOption(key = CliStrings.START_SERVER__PROPERTIES, + optionContext = ConverterHint.FILE_PATHSTRING, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + 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_PATHSTRING, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + 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, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__SOCKET__BUFFER__SIZE__HELP) + final Integer socketBufferSize, + @CliOption(key = CliStrings.START_SERVER__SPRING_XML_LOCATION, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = CliStrings.START_SERVER__SPRING_XML_LOCATION_HELP) + final String springXmlLocation, + @CliOption(key = CliStrings.START_SERVER__STATISTIC_ARCHIVE_FILE, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + 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) + // NOTICE: keep the parameters in alphabetical order based on their CliStrings.START_SERVER_* text + { + + try { + if (workingDirectory == null) { + // attempt to use or make sub-directory using memberName... + File serverWorkingDirectory = new File(memberName); + + if (!(serverWorkingDirectory.exists() || serverWorkingDirectory.mkdir())) { + throw new IllegalStateException(CliStrings.format(CliStrings.START_SERVER__MSG__COULD_NOT_CREATE_DIRECTORY_0_VERIFY_PERMISSIONS, + serverWorkingDirectory.getAbsolutePath())); + } + + workingDirectory = IOUtils.tryGetCanonicalPathElseGetAbsolutePath(serverWorkingDirectory); + } + + cacheXmlPathname = CliUtil.resolvePathname(cacheXmlPathname); + + if (!StringUtils.isBlank(cacheXmlPathname) && !IOUtils.isExistingPathname(cacheXmlPathname)) { + return ResultBuilder.createUserErrorResult(CliStrings.format(CliStrings.CACHE_XML_NOT_FOUND_MESSAGE, cacheXmlPathname)); + } + + gemfirePropertiesPathname = CliUtil.resolvePathname(gemfirePropertiesPathname); + + if (!StringUtils.isBlank(gemfirePropertiesPathname) && !IOUtils.isExistingPathname(gemfirePropertiesPathname)) { + return ResultBuilder.createUserErrorResult(CliStrings.format(CliStrings.GEMFIRE_0_PROPERTIES_1_NOT_FOUND_MESSAGE, + StringUtils.EMPTY_STRING, gemfirePropertiesPathname)); + } + + gemfireSecurityPropertiesPathname = CliUtil.resolvePathname(gemfireSecurityPropertiesPathname); + + if (!StringUtils.isBlank(gemfireSecurityPropertiesPathname) && !IOUtils.isExistingPathname(gemfireSecurityPropertiesPathname)) { + return ResultBuilder.createUserErrorResult(CliStrings.format(CliStrings.GEMFIRE_0_PROPERTIES_1_NOT_FOUND_MESSAGE, + "Security ", gemfireSecurityPropertiesPathname)); + } + + File serverPidFile = new File(workingDirectory, ProcessType.SERVER.getPidFileName()); + +