/*
* 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.BIND_ADDRESS;
import static org.apache.geode.distributed.ConfigurationProperties.CACHE_XML_FILE;
import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_CONFIGURATION_DIR;
import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION;
import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_TIME_STATISTICS;
import static org.apache.geode.distributed.ConfigurationProperties.GROUPS;
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.LOAD_CLUSTER_CONFIGURATION_FROM_DIR;
import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
import static org.apache.geode.distributed.ConfigurationProperties.LOCATOR_WAIT_TIME;
import static org.apache.geode.distributed.ConfigurationProperties.LOCK_MEMORY;
import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
import static org.apache.geode.distributed.ConfigurationProperties.MCAST_ADDRESS;
import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
import static org.apache.geode.distributed.ConfigurationProperties.MEMCACHED_BIND_ADDRESS;
import static org.apache.geode.distributed.ConfigurationProperties.MEMCACHED_PORT;
import static org.apache.geode.distributed.ConfigurationProperties.MEMCACHED_PROTOCOL;
import static org.apache.geode.distributed.ConfigurationProperties.OFF_HEAP_MEMORY_SIZE;
import static org.apache.geode.distributed.ConfigurationProperties.REDIS_BIND_ADDRESS;
import static org.apache.geode.distributed.ConfigurationProperties.REDIS_PASSWORD;
import static org.apache.geode.distributed.ConfigurationProperties.REDIS_PORT;
import static org.apache.geode.distributed.ConfigurationProperties.START_DEV_REST_API;
import static org.apache.geode.distributed.ConfigurationProperties.STATISTIC_ARCHIVE_FILE;
import static org.apache.geode.distributed.ConfigurationProperties.USE_CLUSTER_CONFIGURATION;
import static org.apache.geode.management.internal.cli.i18n.CliStrings.START_SERVER__PASSWORD;
import org.apache.geode.GemFireException;
import org.apache.geode.SystemFailure;
import org.apache.geode.cache.server.CacheServer;
import org.apache.geode.distributed.AbstractLauncher;
import org.apache.geode.distributed.AbstractLauncher.ServiceState;
import org.apache.geode.distributed.AbstractLauncher.Status;
import org.apache.geode.distributed.LocatorLauncher;
import org.apache.geode.distributed.LocatorLauncher.LocatorState;
import org.apache.geode.distributed.ServerLauncher;
import org.apache.geode.distributed.ServerLauncher.ServerState;
import org.apache.geode.distributed.internal.DistributionConfig;
import org.apache.geode.distributed.internal.tcpserver.TcpClient;
import org.apache.geode.internal.DistributionLocator;
import org.apache.geode.internal.GemFireVersion;
import org.apache.geode.internal.OSProcess;
import org.apache.geode.internal.cache.persistence.PersistentMemberPattern;
import org.apache.geode.internal.i18n.LocalizedStrings;
import org.apache.geode.internal.lang.ClassUtils;
import org.apache.geode.internal.lang.ObjectUtils;
import org.apache.geode.internal.lang.StringUtils;
import org.apache.geode.internal.lang.SystemUtils;
import org.apache.geode.internal.net.SocketCreator;
import org.apache.geode.internal.process.ClusterConfigurationNotAvailableException;
import org.apache.geode.internal.process.ProcessLauncherContext;
import org.apache.geode.internal.process.ProcessStreamReader;
import org.apache.geode.internal.process.ProcessStreamReader.InputListener;
import org.apache.geode.internal.process.ProcessStreamReader.ReadingMode;
import org.apache.geode.internal.process.ProcessType;
import org.apache.geode.internal.process.ProcessUtils;
import org.apache.geode.internal.process.signal.SignalEvent;
import org.apache.geode.internal.process.signal.SignalListener;
import org.apache.geode.internal.util.IOUtils;
import org.apache.geode.internal.util.StopWatch;
import org.apache.geode.lang.AttachAPINotFoundException;
import org.apache.geode.management.DistributedSystemMXBean;
import org.apache.geode.management.MemberMXBean;
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.ManagementConstants;
import org.apache.geode.management.internal.cli.CliUtil;
import org.apache.geode.management.internal.cli.LogWrapper;
import org.apache.geode.management.internal.cli.converters.ConnectionEndpointConverter;
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.shell.OperationInvoker;
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.JConsoleNotFoundException;
import org.apache.geode.management.internal.cli.util.ThreePhraseGenerator;
import org.apache.geode.management.internal.cli.util.VisualVmNotFoundException;
import org.apache.geode.management.internal.configuration.domain.SharedConfigurationStatus;
import org.apache.geode.management.internal.configuration.messages.SharedConfigurationStatusRequest;
import org.apache.geode.management.internal.configuration.messages.SharedConfigurationStatusResponse;
import org.apache.geode.management.internal.security.ResourceConstants;
import org.apache.geode.security.AuthenticationFailedException;
import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.shell.core.annotation.CliOption;
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.EmptyStackException;
import java.util.HashMap;
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;
/**
* 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).
* <p>
*
* @see org.apache.geode.distributed.LocatorLauncher
* @see org.apache.geode.distributed.ServerLauncher
* @see org.apache.geode.management.internal.cli.commands.AbstractCommandsSupport
* @see org.apache.geode.management.internal.cli.shell.Gfsh
* @since GemFire 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<Boolean> ATTACH_API_AVAILABLE =
new AtomicReference<>(null);
protected static final String ATTACH_API_CLASS_NAME =
"com.sun.tools.attach.AttachNotSupportedException";
protected static final String GEODE_HOME = System.getenv("GEODE_HOME");
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 GEODE_JAR_PATHNAME =
IOUtils.appendToPath(GEODE_HOME, "lib", GemFireVersion.getGemFireJarFileName());
protected static final String CORE_DEPENDENCIES_JAR_PATHNAME =
IOUtils.appendToPath(GEODE_HOME, "lib", "geode-dependencies.jar");
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();
}
private final ThreePhraseGenerator nameGenerator;
public LauncherLifecycleCommands() {
nameGenerator = new ThreePhraseGenerator();
}
@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, mandatory = false,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.START_LOCATOR__MEMBER_NAME__HELP) 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 (StringUtils.isBlank(memberName)) {
// when the user doesn't give us a name, we make one up!
memberName = nameGenerator.generate('-');
}
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.GEODE_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.GEODE_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(GROUPS, StringUtils.valueOf(group, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(LOCATORS,
StringUtils.valueOf(locators, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(LOG_LEVEL,
StringUtils.valueOf(logLevel, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(MCAST_ADDRESS,
StringUtils.valueOf(mcastBindAddress, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(MCAST_PORT,
StringUtils.valueOf(mcastPort, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(ENABLE_CLUSTER_CONFIGURATION,
StringUtils.valueOf(enableSharedConfiguration, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(LOAD_CLUSTER_CONFIGURATION_FROM_DIR,
StringUtils.valueOf(loadSharedConfigurationFromDirectory, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(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;
InetAddress bindAddr = locatorLauncher.getBindAddress();
if (bindAddr != null) {
locatorHostName = bindAddr.getCanonicalHostName();
} else {
locatorHostName =
StringUtils.defaultIfBlank(locatorLauncher.getHostnameForClients(), 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(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<String> 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<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.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<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<String, String>());
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);
TcpClient client = new TcpClient();
SharedConfigurationStatusResponse statusResponse =
(SharedConfigurationStatusResponse) client.requestToServer(networkAddress, locatorPort,
new SharedConfigurationStatusRequest(), 10000, true);
for (int i = 0; i < NUM_ATTEMPTS_FOR_SHARED_CONFIGURATION_STATUS; i++) {
if (statusResponse.getStatus().equals(SharedConfigurationStatus.STARTED)
|| statusResponse.getStatus().equals(SharedConfigurationStatus.NOT_STARTED)) {
statusResponse =
(SharedConfigurationStatusResponse) client.requestToServer(networkAddress,
locatorPort, new SharedConfigurationStatusRequest(), 10000, true);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// Swallow the exception
}
} else {
break;
}
}
switch (statusResponse.getStatus()) {
case RUNNING:
buffer.append("\nCluster configuration service is up and running.");
break;
case STOPPED:
buffer.append(
"\nCluster configuration service failed to start , please check the log file for errors.");
break;
case WAITING:
buffer.append(
"\nCluster configuration service is waiting for other locators with newer shared configuration data.");
Set<PersistentMemberPattern> 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_GEODE_LOCATOR, CliStrings.TOPIC_GEODE_LIFECYCLE})
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_GEODE_LOCATOR, CliStrings.TOPIC_GEODE_LIFECYCLE})
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<String> commandLine,
final Properties gemfireProperties) throws MalformedObjectNameException {
if (StringUtils.isBlank(gemfireProperties.getProperty(LOCATORS))) {
String currentLocators = getCurrentLocators();
if (!StringUtils.isBlank(currentLocators)) {
commandLine.add("-D".concat(ProcessLauncherContext.OVERRIDDEN_DEFAULTS_PREFIX)
.concat(LOCATORS).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<String> commandLine,
final String gemfirePropertiesPathname) {
if (!StringUtils.isBlank(gemfirePropertiesPathname)) {
commandLine.add("-DgemfirePropertyFile=" + gemfirePropertiesPathname);
}
}
protected void addGemFireSecurityPropertyFile(final List<String> commandLine,
final String gemfireSecurityPropertiesPathname) {
if (!StringUtils.isBlank(gemfireSecurityPropertiesPathname)) {
commandLine.add("-DgemfireSecurityPropertyFile=" + gemfireSecurityPropertiesPathname);
}
}
protected 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 (!StringUtils.isBlank(propertyValue)) {
commandLine.add(
"-D" + DistributionConfig.GEMFIRE_PREFIX + "" + propertyName + "=" + propertyValue);
}
}
}
protected void addInitialHeap(final List<String> commandLine, final String initialHeap) {
if (!StringUtils.isBlank(initialHeap)) {
commandLine.add("-Xms" + initialHeap);
}
}
protected void addJvmArgumentsAndOptions(final List<String> 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<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");
}
}
protected void addMaxHeap(final List<String> 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 String userClasspath) {
List<String> jarFilePathnames = new ArrayList<>();
jarFilePathnames.add(CORE_DEPENDENCIES_JAR_PATHNAME);
return toClasspath(includeSystemClasspath,
jarFilePathnames.toArray(new String[jarFilePathnames.size()]), userClasspath);
}
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 = 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;
}
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.
* </p>
*
* @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.
* </p>
*
* @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<ObjectName> 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_GEODE_SERVER, CliStrings.TOPIC_GEODE_LIFECYCLE})
public Result startServer(
@CliOption(key = CliStrings.START_SERVER__NAME, mandatory = false,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
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,
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__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,
@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 = 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 = nameGenerator.generate('-');
}
// prompt for password is username is specified in the command
if (!StringUtils.isBlank(userName)) {
if (StringUtils.isBlank(passwordToUse)) {
passwordToUse = getGfsh().readPassword(START_SERVER__PASSWORD + ": ");
}
if (StringUtils.isBlank(passwordToUse)) {
return ResultBuilder.createConnectionErrorResult(
CliStrings.START_SERVER__MSG__PASSWORD_MUST_BE_SPECIFIED);
}
}
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.GEODE_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.GEODE_0_PROPERTIES_1_NOT_FOUND_MESSAGE, "Security ",
gemfireSecurityPropertiesPathname));
}
File serverPidFile = new File(workingDirectory, ProcessType.SERVER.getPidFileName());
final int oldPid = readPid(serverPidFile);
Properties gemfireProperties = new Properties();
gemfireProperties.setProperty(BIND_ADDRESS,
StringUtils.valueOf(bindAddress, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(CACHE_XML_FILE,
StringUtils.valueOf(cacheXmlPathname, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(ENABLE_TIME_STATISTICS,
StringUtils.valueOf(enableTimeStatistics, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(GROUPS, StringUtils.valueOf(group, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(LOCATORS,
StringUtils.valueOf(locators, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(LOCATOR_WAIT_TIME,
StringUtils.valueOf(locatorWaitTime, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(LOG_LEVEL,
StringUtils.valueOf(logLevel, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(MCAST_ADDRESS,
StringUtils.valueOf(mcastBindAddress, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(MCAST_PORT,
StringUtils.valueOf(mcastPort, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(MEMCACHED_PORT,
StringUtils.valueOf(memcachedPort, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(MEMCACHED_PROTOCOL,
StringUtils.valueOf(memcachedProtocol, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(MEMCACHED_BIND_ADDRESS,
StringUtils.valueOf(memcachedBindAddress, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(REDIS_PORT,
StringUtils.valueOf(redisPort, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(REDIS_BIND_ADDRESS,
StringUtils.valueOf(redisBindAddress, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(REDIS_PASSWORD,
StringUtils.valueOf(redisPassword, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(STATISTIC_ARCHIVE_FILE,
StringUtils.valueOf(statisticsArchivePathname, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(USE_CLUSTER_CONFIGURATION,
StringUtils.valueOf(requestSharedConfiguration, Boolean.TRUE.toString()));
gemfireProperties.setProperty(LOCK_MEMORY,
StringUtils.valueOf(lockMemory, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(OFF_HEAP_MEMORY_SIZE,
StringUtils.valueOf(offHeapMemorySize, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(START_DEV_REST_API,
StringUtils.valueOf(startRestApi, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(HTTP_SERVICE_PORT,
StringUtils.valueOf(httpServicePort, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(HTTP_SERVICE_BIND_ADDRESS,
StringUtils.valueOf(httpServiceBindAddress, StringUtils.EMPTY_STRING));
// if username is specified in the command line, it will overwrite what's set in the
// properties file
if (!StringUtils.isBlank(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 serverLauncher = new ServerLauncher.Builder().setAssignBuckets(assignBuckets)
.setDisableDefaultServer(disableDefaultServer).setForce(force).setMemberName(memberName)
.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)
.setHostNameForClients(hostNameForClients).build();
String[] serverCommandLine = createStartServerCommandLine(serverLauncher,
gemfirePropertiesPathname, gemfireSecurityPropertiesPathname, gemfireProperties,
classpath, includeSystemClasspath, jvmArgsOpts, disableExitWhenOutOfMemory, initialHeap,
maxHeap);
if (getGfsh().getDebug()) {
getGfsh().logInfo(StringUtils.concat(serverCommandLine, " "), 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 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(serverProcess)
.inputStream(serverProcess.getErrorStream()).inputListener(inputListener)
.readingMode(readingMode).continueReadingMillis(2 * 1000).build().start();
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);
do {
try {
final int exitValue = serverProcess.exitValue();
stderrReader.join(PROCESS_STREAM_READER_JOIN_TIMEOUT_MILLIS); // was Long.MAX_VALUE
// Gfsh.println(message);
return ResultBuilder.createShellClientErrorResult(
String.format(CliStrings.START_SERVER__PROCESS_TERMINATED_ABNORMALLY_ERROR_MESSAGE,
exitValue, serverLauncher.getWorkingDirectory(), message.toString()));
} catch (IllegalThreadStateException ignore) {
// the IllegalThreadStateException is expected; it means the Server's process has not
// terminated,
// and should not
Gfsh.print(".");
synchronized (this) {
TimeUnit.MILLISECONDS.timedWait(this, 500);
}
serverState = (ProcessUtils.isAttachApiAvailable()
? serverStatus(serverPidFile, oldPid, memberName)
: serverStatus(workingDirectory, memberName));
String currentServerStatusMessage = serverState.getStatusMessage();
if (isStartingOrNotResponding(serverState.getStatus())
&& !(StringUtils.isBlank(currentServerStatusMessage)
|| currentServerStatusMessage.equalsIgnoreCase(previousServerStatusMessage))) {
Gfsh.println();
Gfsh.println(currentServerStatusMessage);
previousServerStatusMessage = currentServerStatusMessage;
}
}
} while (!(registeredServerSignalListener && serverSignalListener.isSignaled())
&& isStartingOrNotResponding(serverState.getStatus()));
} finally {
stderrReader.stopAsync(PROCESS_STREAM_READER_ASYNC_STOP_TIMEOUT_MILLIS); // stop will close
// ErrorStream
getGfsh().getSignalHandler().unregisterListener(serverSignalListener);
}
Gfsh.println();
final boolean asyncStart = 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, toString(t, getGfsh().getDebug())));
}
}
protected 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(getJavaPath());
commandLine.add("-server");
commandLine.add("-classpath");
commandLine.add(getServerClasspath(Boolean.TRUE.equals(includeSystemClasspath), userClasspath));
addCurrentLocators(commandLine, gemfireProperties);
addGemFirePropertyFile(commandLine, gemfirePropertiesPathname);
addGemFireSecurityPropertyFile(commandLine, gemfireSecurityPropertiesPathname);
addGemFireSystemProperties(commandLine, gemfireProperties);
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);
}
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(ServerLauncher.class.getName());
commandLine.add(ServerLauncher.Command.START.getName());
if (!StringUtils.isBlank(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()]);
}
private String getCurrentLocators() throws MalformedObjectNameException {
String delimitedLocators = "";
try {
if (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 = ""
getGfsh().logWarning("DistributedSystemMXBean is unavailable\n", e);
}
return delimitedLocators;
}
@CliCommand(value = CliStrings.STATUS_SERVER, help = CliStrings.STATUS_SERVER__HELP)
@CliMetaData(shellOnly = true,
relatedTopic = {CliStrings.TOPIC_GEODE_SERVER, CliStrings.TOPIC_GEODE_LIFECYCLE})
public Result statusServer(
@CliOption(key = CliStrings.STATUS_SERVER__MEMBER, optionContext = ConverterHint.MEMBERIDNAME,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.STATUS_SERVER__MEMBER__HELP) final String member,
@CliOption(key = CliStrings.STATUS_SERVER__PID,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.STATUS_SERVER__PID__HELP) final Integer pid,
@CliOption(key = CliStrings.STATUS_SERVER__DIR, optionContext = ConverterHint.DIR_PATHSTRING,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.STATUS_SERVER__DIR__HELP) final String workingDirectory) {
try {
if (!StringUtils.isBlank(member)) {
if (isConnectedAndReady()) {
final MemberMXBean serverProxy = getMemberMXBean(member);
if (serverProxy != null) {
return ResultBuilder
.createInfoResult(ServerState.fromJson(serverProxy.status()).toString());
} else {
return ResultBuilder.createUserErrorResult(CliStrings.format(
CliStrings.STATUS_SERVER__NO_SERVER_FOUND_FOR_MEMBER_ERROR_MESSAGE, member));
}
} else {
return ResultBuilder.createUserErrorResult(CliStrings
.format(CliStrings.STATUS_SERVICE__GFSH_NOT_CONNECTED_ERROR_MESSAGE, "Cache Server"));
}
} else {
final ServerLauncher serverLauncher = new ServerLauncher.Builder()
.setCommand(ServerLauncher.Command.STATUS).setDebug(isDebugging())
// NOTE since we do not know whether the "CacheServer" was enabled or not on the GemFire
// server when it was started,
// set the disableDefaultServer property in the ServerLauncher.Builder to default status
// to the MemberMBean
// TODO fix this hack! (how, the 'start server' loop needs it)
.setDisableDefaultServer(true).setMemberName(member).setPid(pid)
.setWorkingDirectory(workingDirectory).build();
final ServerState status = serverLauncher.status();
return ResultBuilder.createInfoResult(status.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.STATUS_SERVER__GENERAL_ERROR_MESSAGE, toString(t, getGfsh().getDebug())));
}
}
@CliCommand(value = CliStrings.STOP_SERVER, help = CliStrings.STOP_SERVER__HELP)
@CliMetaData(shellOnly = true,
relatedTopic = {CliStrings.TOPIC_GEODE_SERVER, CliStrings.TOPIC_GEODE_LIFECYCLE})
public Result stopServer(
@CliOption(key = CliStrings.STOP_SERVER__MEMBER, optionContext = ConverterHint.MEMBERIDNAME,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.STOP_SERVER__MEMBER__HELP) final String member,
@CliOption(key = CliStrings.STOP_SERVER__PID,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.STOP_SERVER__PID__HELP) final Integer pid,
@CliOption(key = CliStrings.STOP_SERVER__DIR, optionContext = ConverterHint.DIR_PATHSTRING,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.STOP_SERVER__DIR__HELP) final String workingDirectory) {
ServerState serverState;
try {
if (!StringUtils.isBlank(member)) {
if (isConnectedAndReady()) {
final MemberMXBean serverProxy = getMemberMXBean(member);
if (serverProxy != null) {
if (!serverProxy.isServer()) {
throw new IllegalStateException(CliStrings
.format(CliStrings.STOP_SERVER__MEMBER_IS_NOT_SERVER_ERROR_MESSAGE, member));
}
serverState = ServerState.fromJson(serverProxy.status());
serverProxy.shutDownMember();
} else {
return ResultBuilder.createUserErrorResult(CliStrings
.format(CliStrings.STOP_SERVER__NO_SERVER_FOUND_FOR_MEMBER_ERROR_MESSAGE, member));
}
} else {
return ResultBuilder.createUserErrorResult(CliStrings
.format(CliStrings.STOP_SERVICE__GFSH_NOT_CONNECTED_ERROR_MESSAGE, "Cache Server"));
}
} else {
final ServerLauncher serverLauncher = new ServerLauncher.Builder()
.setCommand(ServerLauncher.Command.STOP).setDebug(isDebugging()).setMemberName(member)
.setPid(pid).setWorkingDirectory(workingDirectory).build();
serverState = serverLauncher.status();
serverLauncher.stop();
}
if (Status.ONLINE.equals(serverState.getStatus())) {
getGfsh().logInfo(
String.format(CliStrings.STOP_SERVER__STOPPING_SERVER_MESSAGE,
serverState.getWorkingDirectory(), serverState.getServiceLocation(),
serverState.getMemberName(), serverState.getPid(), serverState.getLogFile()),
null);
StopWatch stopWatch = new StopWatch(true);
while (isVmWithProcessIdRunning(serverState.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(serverState.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_SERVER__GENERAL_ERROR_MESSAGE, toString(t, getGfsh().getDebug())));
} finally {
Gfsh.redirectInternalJavaLoggers();
}
}
// @CliCommand(value=CliStrings.START_MANAGER, help=CliStrings.START_MANAGER__HELP)
// @CliMetaData(shellOnly=true, relatedTopic = {CliStrings.TOPIC_GEODE_MANAGER,
// CliStrings.TOPIC_GEODE_JMX, CliStrings.TOPIC_GEODE_LIFECYCLE})
public Result startManager(
@CliOption(key = CliStrings.START_MANAGER__MEMBERNAME,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.START_MANAGER__MEMBERNAME__HELP) String memberName,
@CliOption(key = CliStrings.START_MANAGER__DIR,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.START_MANAGER__DIR__HELP) String dir,
@CliOption(key = CliStrings.START_MANAGER__PORT, unspecifiedDefaultValue = "1099",
help = CliStrings.START_MANAGER__PORT__HELP) int cacheServerPort,
@CliOption(key = CliStrings.START_MANAGER__BIND_ADDRESS,
unspecifiedDefaultValue = "localhost",
help = CliStrings.START_MANAGER__BIND_ADDRESS__HELP) String cacheServerHost,
@CliOption(key = CliStrings.START_MANAGER__CLASSPATH,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.START_MANAGER__CLASSPATH__HELP) String classpath,
@CliOption(key = CliStrings.START_MANAGER__MAXHEAP,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.START_MANAGER__MAXHEAP__HELP) String maxHeap,
@CliOption(key = CliStrings.START_MANAGER__INITIALHEAP,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.START_MANAGER__INITIALHEAP__HELP) String initialHeap,
@CliOption(key = CliStrings.START_MANAGER__J,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.START_MANAGER__J__HELP) Map<String, String> systepProps,
@CliOption(key = CliStrings.START_MANAGER__GEODEPROPS,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.START_MANAGER__GEODEPROPS__HELP) Map<String, String> gemfireProps) {
return ResultBuilder.createInfoResult("Not-implemented");
}
@CliCommand(value = CliStrings.START_JCONSOLE, help = CliStrings.START_JCONSOLE__HELP)
@CliMetaData(shellOnly = true, relatedTopic = {CliStrings.TOPIC_GEODE_MANAGER,
CliStrings.TOPIC_GEODE_JMX, CliStrings.TOPIC_GEODE_M_AND_M})
public Result startJConsole(
@CliOption(key = CliStrings.START_JCONSOLE__INTERVAL, unspecifiedDefaultValue = "4",
help = CliStrings.START_JCONSOLE__INTERVAL__HELP) final int interval,
@CliOption(key = CliStrings.START_JCONSOLE__NOTILE, specifiedDefaultValue = "true",
unspecifiedDefaultValue = "false",
help = CliStrings.START_JCONSOLE__NOTILE__HELP) final boolean notile,
@CliOption(key = CliStrings.START_JCONSOLE__PLUGINPATH,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.START_JCONSOLE__PLUGINPATH__HELP) final String pluginpath,
@CliOption(key = CliStrings.START_JCONSOLE__VERSION, specifiedDefaultValue = "true",
unspecifiedDefaultValue = "false",
help = CliStrings.START_JCONSOLE__VERSION__HELP) final boolean version,
@CliOption(key = CliStrings.START_JCONSOLE__J, optionContext = ConverterHint.STRING_LIST,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.START_JCONSOLE__J__HELP) @CliMetaData(
valueSeparator = ",") final List<String> jvmArgs) {
try {
String[] jconsoleCommandLine =
createJConsoleCommandLine(null, interval, notile, pluginpath, version, jvmArgs);
if (isDebugging()) {
getGfsh().printAsInfo(
String.format("JConsole command-line ($1%s)", Arrays.toString(jconsoleCommandLine)));
}
Process jconsoleProcess = Runtime.getRuntime().exec(jconsoleCommandLine);
StringBuilder message = new StringBuilder();
if (version) {
jconsoleProcess.waitFor();
BufferedReader reader =
new BufferedReader(new InputStreamReader(jconsoleProcess.getErrorStream()));
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
message.append(line);
message.append(StringUtils.LINE_SEPARATOR);
}
IOUtils.close(reader);
} else {
getGfsh().printAsInfo(CliStrings.START_JCONSOLE__RUN);
String jconsoleProcessOutput = waitAndCaptureProcessStandardErrorStream(jconsoleProcess);
if (!StringUtils.isBlank(jconsoleProcessOutput)) {
message.append(StringUtils.LINE_SEPARATOR);
message.append(jconsoleProcessOutput);
}
}
return ResultBuilder.createInfoResult(message.toString());
} catch (GemFireException e) {
return ResultBuilder.createShellClientErrorResult(e.getMessage());
} catch (IllegalArgumentException e) {
return ResultBuilder.createShellClientErrorResult(e.getMessage());
} catch (IllegalStateException e) {
return ResultBuilder.createShellClientErrorResult(e.getMessage());
} catch (IOException e) {
return ResultBuilder
.createShellClientErrorResult(CliStrings.START_JCONSOLE__IO_EXCEPTION_MESSAGE);
} catch (VirtualMachineError e) {
SystemFailure.initiateFailure(e);
throw e;
} catch (Throwable t) {
SystemFailure.checkFailure();
return ResultBuilder.createShellClientErrorResult(
String.format(CliStrings.START_JCONSOLE__CATCH_ALL_ERROR_MESSAGE, toString(t, false)));
}
}
protected String[] createJConsoleCommandLine(final String member, final int interval,
final boolean notile, final String pluginpath, final boolean version,
final List<String> jvmArgs) {
List<String> commandLine = new ArrayList<>();
commandLine.add(getJConsolePathname());
if (version) {
commandLine.add("-version");
} else {
commandLine.add("-interval=" + interval);
if (notile) {
commandLine.add("-notile");
}
if (!StringUtils.isBlank(pluginpath)) {
commandLine.add("-pluginpath " + pluginpath);
}
if (jvmArgs != null) {
for (final String arg : jvmArgs) {
commandLine.add("-J" + arg);
}
}
String jmxServiceUrl = getJmxServiceUrlAsString(member);
if (!StringUtils.isBlank(jmxServiceUrl)) {
commandLine.add(jmxServiceUrl);
}
}
return commandLine.toArray(new String[commandLine.size()]);
}
protected String getJConsolePathname() {
return getJdkToolPathname("jconsole" + getExecutableSuffix(),
new JConsoleNotFoundException(CliStrings.START_JCONSOLE__NOT_FOUND_ERROR_MESSAGE));
}
protected String getJdkToolPathname(final String jdkToolExecutableName,
final GemFireException throwable) {
assertNotNull(jdkToolExecutableName, "The JDK tool executable name cannot be null!");
assertNotNull(throwable, "The GemFireException cannot be null!");
Stack<String> pathnames = new Stack<>();
pathnames.push(jdkToolExecutableName);
pathnames
.push(IOUtils.appendToPath(System.getenv("JAVA_HOME"), "..", "bin", jdkToolExecutableName));
pathnames.push(IOUtils.appendToPath(System.getenv("JAVA_HOME"), "bin", jdkToolExecutableName));
pathnames.push(IOUtils.appendToPath(JAVA_HOME, "..", "bin", jdkToolExecutableName));
pathnames.push(IOUtils.appendToPath(JAVA_HOME, "bin", jdkToolExecutableName));
return getJdkToolPathname(pathnames, throwable);
}
protected String getJdkToolPathname(final Stack<String> pathnames,
final GemFireException throwable) {
assertNotNull(pathnames, "The JDK tool executable pathnames cannot be null!");
assertNotNull(throwable, "The GemFireException cannot be null!");
try {
// assume 'java.home' JVM System property refers to the JDK installation directory. note,
// however, that the
// 'java.home' JVM System property usually refers to the JRE used to launch this application
return IOUtils.verifyPathnameExists(pathnames.pop());
} catch (EmptyStackException ignore) {
throw throwable;
} catch (FileNotFoundException ignore) {
return getJdkToolPathname(pathnames, throwable);
}
}
protected static String getExecutableSuffix() {
return SystemUtils.isWindows() ? ".exe" : StringUtils.EMPTY_STRING;
}
protected String getJmxServiceUrlAsString(final String member) {
if (!StringUtils.isBlank(member)) {
ConnectionEndpointConverter converter = new ConnectionEndpointConverter();
try {
ConnectionEndpoint connectionEndpoint =
converter.convertFromText(member, ConnectionEndpoint.class, null);
return StringUtils.concat("service:jmx:rmi://", connectionEndpoint.getHost(), ":",
connectionEndpoint.getPort(), "/jndi/rmi://", connectionEndpoint.getHost(), ":",
connectionEndpoint.getPort(), "/jmxrmi");
} catch (Exception e) {
throw new IllegalArgumentException(
CliStrings.START_JCONSOLE__CONNECT_BY_MEMBER_NAME_ID_ERROR_MESSAGE);
}
} else {
if (isConnectedAndReady()
&& (getGfsh().getOperationInvoker() instanceof JmxOperationInvoker)) {
JmxOperationInvoker jmxOperationInvoker =
(JmxOperationInvoker) getGfsh().getOperationInvoker();
return ObjectUtils.toString(jmxOperationInvoker.getJmxServiceUrl());
}
}
return null;
}
@CliCommand(value = CliStrings.START_JVISUALVM, help = CliStrings.START_JVISUALVM__HELP)
@CliMetaData(shellOnly = true, relatedTopic = {CliStrings.TOPIC_GEODE_MANAGER,
CliStrings.TOPIC_GEODE_JMX, CliStrings.TOPIC_GEODE_M_AND_M})
public Result startJVisualVM(
@CliOption(key = CliStrings.START_JCONSOLE__J, optionContext = ConverterHint.STRING_LIST,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.START_JCONSOLE__J__HELP) @CliMetaData(
valueSeparator = ",") final List<String> jvmArgs) {
try {
String[] jvisualvmCommandLine = createJVisualVMCommandLine(jvmArgs);
if (isDebugging()) {
getGfsh().printAsInfo(
String.format("JVisualVM command-line (%1$s)", Arrays.toString(jvisualvmCommandLine)));
}
Process jvisualvmProcess = Runtime.getRuntime().exec(jvisualvmCommandLine);
getGfsh().printAsInfo(CliStrings.START_JVISUALVM__RUN);
String jvisualvmProcessOutput = waitAndCaptureProcessStandardErrorStream(jvisualvmProcess);
InfoResultData infoResultData = ResultBuilder.createInfoResultData();
if (!StringUtils.isBlank(jvisualvmProcessOutput)) {
infoResultData.addLine(StringUtils.LINE_SEPARATOR);
infoResultData.addLine(jvisualvmProcessOutput);
}
return ResultBuilder.buildResult(infoResultData);
} catch (GemFireException e) {
return ResultBuilder.createShellClientErrorResult(e.getMessage());
} catch (IllegalArgumentException e) {
return ResultBuilder.createShellClientErrorResult(e.getMessage());
} catch (IllegalStateException 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_JVISUALVM__ERROR_MESSAGE, toString(t, false)));
}
}
protected String[] createJVisualVMCommandLine(final List<String> jvmArgs) {
List<String> commandLine = new ArrayList<>();
commandLine.add(getJVisualVMPathname());
if (jvmArgs != null) {
for (final String arg : jvmArgs) {
commandLine.add("-J" + arg);
}
}
return commandLine.toArray(new String[commandLine.size()]);
}
protected String getJVisualVMPathname() {
if (SystemUtils.isMacOSX()) {
try {
return IOUtils.verifyPathnameExists(
"/System/Library/Java/Support/VisualVM.bundle/Contents/Home/bin/jvisualvm");
} catch (FileNotFoundException e) {
throw new VisualVmNotFoundException(CliStrings.START_JVISUALVM__NOT_FOUND_ERROR_MESSAGE, e);
}
} else { // Linux, Solaris, Windows, etc...
try {
return getJdkToolPathname("jvisualvm" + getExecutableSuffix(),
new VisualVmNotFoundException(CliStrings.START_JVISUALVM__NOT_FOUND_ERROR_MESSAGE));
} catch (VisualVmNotFoundException e) {
if (!SystemUtils.isJavaVersionAtLeast("1.6")) {
throw new VisualVmNotFoundException(
CliStrings.START_JVISUALVM__EXPECTED_JDK_VERSION_ERROR_MESSAGE);
}
throw e;
}
}
}
@CliCommand(value = CliStrings.START_PULSE, help = CliStrings.START_PULSE__HELP)
@CliMetaData(shellOnly = true, relatedTopic = {CliStrings.TOPIC_GEODE_MANAGER,
CliStrings.TOPIC_GEODE_JMX, CliStrings.TOPIC_GEODE_M_AND_M})
// TODO change url parameter type to URL when I figure out the Converter logic in Gfsh
public Result startPulse(@CliOption(key = CliStrings.START_PULSE__URL,
unspecifiedDefaultValue = "http://localhost:7070/pulse",
help = CliStrings.START_PULSE__URL__HELP) final String url) {
try {
if (!StringUtils.isBlank(url)) {
browse(URI.create(url));
return ResultBuilder.createInfoResult(CliStrings.START_PULSE__RUN);
} else {
if (isConnectedAndReady()) {
OperationInvoker operationInvoker = getGfsh().getOperationInvoker();
ObjectName managerObjectName = (ObjectName) operationInvoker.getAttribute(
ManagementConstants.OBJECTNAME__DISTRIBUTEDSYSTEM_MXBEAN, "ManagerObjectName");
String pulseURL =
(String) operationInvoker.getAttribute(managerObjectName.toString(), "PulseURL");
if (!StringUtils.isBlank(pulseURL)) {
browse(URI.create(pulseURL));
return ResultBuilder
.createInfoResult(CliStrings.START_PULSE__RUN + " with URL: " + pulseURL);
} else {
String pulseMessage = (String) operationInvoker
.getAttribute(managerObjectName.toString(), "StatusMessage");
return (!StringUtils.isBlank(pulseMessage)
? ResultBuilder.createGemFireErrorResult(pulseMessage)
: ResultBuilder.createGemFireErrorResult(CliStrings.START_PULSE__URL__NOTFOUND));
}
} else {
return ResultBuilder.createUserErrorResult(CliStrings
.format(CliStrings.GFSH_MUST_BE_CONNECTED_FOR_LAUNCHING_0, "GemFire Pulse"));
}
}
} catch (GemFireException e) {
return ResultBuilder.createShellClientErrorResult(e.getMessage());
} catch (Exception 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_PULSE__ERROR, toString(t, false)));
}
}
private void browse(URI uri) throws IOException {
assertState(Desktop.isDesktopSupported(),
String.format(CliStrings.DESKSTOP_APP_RUN_ERROR_MESSAGE, System.getProperty("os.name")));
Desktop.getDesktop().browse(uri);
}
@Deprecated
protected File readIntoTempFile(final String classpathResourceLocation) throws IOException {
String resourceName = classpathResourceLocation
.substring(classpathResourceLocation.lastIndexOf(File.separator) + 1);
File resourceFile = new File(System.getProperty("java.io.tmpdir"), resourceName);
if (!resourceFile.exists() && resourceFile.createNewFile()) {
BufferedReader resourceReader = new BufferedReader(new InputStreamReader(
ClassLoader.getSystemClassLoader().getResourceAsStream(classpathResourceLocation)));
BufferedWriter resourceFileWriter = new BufferedWriter(new FileWriter(resourceFile, false));
try {
for (String line = resourceReader.readLine(); line != null; line =
resourceReader.readLine()) {
resourceFileWriter.write(line);
resourceFileWriter.write(StringUtils.LINE_SEPARATOR);
}
resourceFileWriter.flush();
} finally {
IOUtils.close(resourceReader);
IOUtils.close(resourceFileWriter);
}
}
resourceFile.deleteOnExit();
return resourceFile;
}
@CliCommand(value = CliStrings.START_VSD, help = CliStrings.START_VSD__HELP)
@CliMetaData(shellOnly = true,
relatedTopic = {CliStrings.TOPIC_GEODE_M_AND_M, CliStrings.TOPIC_GEODE_STATISTICS})
public Result startVsd(@CliOption(key = CliStrings.START_VSD__FILE,
help = CliStrings.START_VSD__FILE__HELP) final String[] statisticsArchiveFilePathnames) {
try {
String geodeHome = System.getenv("GEODE_HOME");
assertState(!StringUtils.isBlank(geodeHome), CliStrings.GEODE_HOME_NOT_FOUND_ERROR_MESSAGE);
assertState(IOUtils.isExistingPathname(getPathToVsd()),
String.format(CliStrings.START_VSD__NOT_FOUND_ERROR_MESSAGE, geodeHome));
String[] vsdCommandLine = createdVsdCommandLine(statisticsArchiveFilePathnames);
if (isDebugging()) {
getGfsh().printAsInfo(
String.format("GemFire VSD command-line (%1$s)", Arrays.toString(vsdCommandLine)));
}
Process vsdProcess = Runtime.getRuntime().exec(vsdCommandLine);
getGfsh().printAsInfo(CliStrings.START_VSD__RUN);
String vsdProcessOutput = waitAndCaptureProcessStandardErrorStream(vsdProcess);
InfoResultData infoResultData = ResultBuilder.createInfoResultData();
if (!StringUtils.isBlank(vsdProcessOutput)) {
infoResultData.addLine(StringUtils.LINE_SEPARATOR);
infoResultData.addLine(vsdProcessOutput);
}
return ResultBuilder.buildResult(infoResultData);
} catch (GemFireException e) {
return ResultBuilder.createShellClientErrorResult(e.getMessage());
} catch (FileNotFoundException e) {
return ResultBuilder.createShellClientErrorResult(e.getMessage());
} catch (IllegalArgumentException e) {
return ResultBuilder.createShellClientErrorResult(e.getMessage());
} catch (IllegalStateException 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_VSD__ERROR_MESSAGE, toString(t, false)));
}
}
protected String[] createdVsdCommandLine(final String[] statisticsArchiveFilePathnames)
throws FileNotFoundException {
List<String> commandLine = new ArrayList<>();
commandLine.add(getPathToVsd());
commandLine.addAll(processStatisticsArchiveFiles(statisticsArchiveFilePathnames));
return commandLine.toArray(new String[commandLine.size()]);
}
protected String getPathToVsd() {
String vsdPathname =
IOUtils.appendToPath(System.getenv("GEODE_HOME"), "tools", "vsd", "bin", "vsd");
if (SystemUtils.isWindows()) {
vsdPathname += ".bat";
}
return vsdPathname;
}
protected Set<String> processStatisticsArchiveFiles(final String[] statisticsArchiveFilePathnames)
throws FileNotFoundException {
Set<String> statisticsArchiveFiles = new TreeSet<>();
if (statisticsArchiveFilePathnames != null) {
for (String pathname : statisticsArchiveFilePathnames) {
File path = new File(pathname);
if (path.exists()) {
if (path.isFile()) {
if (StatisticsArchiveFileFilter.INSTANCE.accept(path)) {
statisticsArchiveFiles.add(pathname);
} else {
throw new IllegalArgumentException(
"A Statistics Archive File must end with a .gfs file extension.");
}
} else { // the File (path) is a directory
processStatisticsArchiveFiles(path, statisticsArchiveFiles);
}
} else {
throw new FileNotFoundException(String.format(
"The pathname (%1$s) does not exist. Please check the path and try again.",
path.getAbsolutePath()));
}
}
}
return statisticsArchiveFiles;
}
@SuppressWarnings("null")
protected void processStatisticsArchiveFiles(final File path,
final Set<String> statisticsArchiveFiles) {
if (path != null && path.isDirectory()) {
for (File file : path.listFiles(StatisticsArchiveFileAndDirectoryFilter.INSTANCE)) {
if (file.isDirectory()) {
processStatisticsArchiveFiles(file, statisticsArchiveFiles);
} else if (StatisticsArchiveFileFilter.INSTANCE.accept(file)) {
statisticsArchiveFiles.add(file.getAbsolutePath());
}
}
}
}
// NOTE as of 8.0, this command is no more!
// @CliCommand(value=CliStrings.START_DATABROWSER, help=CliStrings.START_DATABROWSER__HELP)
@CliMetaData(shellOnly = true, relatedTopic = {CliStrings.TOPIC_GEODE_M_AND_M})
public Result startDataBrowser() {
try {
String geodeHome = System.getenv("GEODE_HOME");
assertState(!StringUtils.isBlank(geodeHome), CliStrings.GEODE_HOME_NOT_FOUND_ERROR_MESSAGE);
if (isConnectedAndReady()
&& (getGfsh().getOperationInvoker() instanceof JmxOperationInvoker)) {
String dataBrowserPath = getPathToDataBrowser();
assertState(IOUtils.isExistingPathname(dataBrowserPath),
String.format(CliStrings.START_DATABROWSER__NOT_FOUND_ERROR_MESSAGE, geodeHome));
JmxOperationInvoker operationInvoker =
(JmxOperationInvoker) getGfsh().getOperationInvoker();
String dataBrowserCommandLine = String.format("%1$s %2$s %3$d", getPathToDataBrowser(),
operationInvoker.getManagerHost(), operationInvoker.getManagerPort());
if (isDebugging()) {
getGfsh().printAsInfo(
String.format("GemFire DataBrowser command-line (%1$s)", dataBrowserCommandLine));
}
Process dataBrowserProcess = Runtime.getRuntime().exec(dataBrowserCommandLine);
getGfsh().printAsInfo(CliStrings.START_DATABROWSER__RUN);
String dataBrowserProcessOutput =
waitAndCaptureProcessStandardOutputStream(dataBrowserProcess);
InfoResultData infoResultData = ResultBuilder.createInfoResultData();
if (!StringUtils.isBlank(dataBrowserProcessOutput)) {
infoResultData.addLine(StringUtils.LINE_SEPARATOR);
infoResultData.addLine(dataBrowserProcessOutput);
}
return ResultBuilder.buildResult(infoResultData);
} else {
return ResultBuilder.createUserErrorResult(CliStrings.format(
CliStrings.GFSH_MUST_BE_CONNECTED_VIA_JMX_FOR_LAUNCHING_0, "GemFire DataBrowser"));
}
} 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(t.getMessage());
}
}
protected String getPathToDataBrowser() {
String dataBrowserPathName =
IOUtils.appendToPath(GEODE_HOME, "tools", "DataBrowser", "bin", "databrowser");
if (SystemUtils.isWindows()) {
dataBrowserPathName += ".bat";
}
return dataBrowserPathName;
}
protected String waitAndCaptureProcessStandardOutputStream(final Process process) {
return waitAndCaptureProcessStandardOutputStream(process,
DEFAULT_PROCESS_OUTPUT_WAIT_TIME_MILLISECONDS);
}
protected String waitAndCaptureProcessStandardOutputStream(final Process process,
final long waitTimeMilliseconds) {
return waitAndCaptureProcessStream(process, process.getInputStream(), waitTimeMilliseconds);
}
protected String waitAndCaptureProcessStandardErrorStream(final Process process) {
return waitAndCaptureProcessStandardErrorStream(process,
DEFAULT_PROCESS_OUTPUT_WAIT_TIME_MILLISECONDS);
}
protected String waitAndCaptureProcessStandardErrorStream(final Process process,
final long waitTimeMilliseconds) {
return waitAndCaptureProcessStream(process, process.getErrorStream(), waitTimeMilliseconds);
}
private String waitAndCaptureProcessStream(final Process process,
final InputStream processInputStream, long waitTimeMilliseconds) {
final StringBuffer buffer = new StringBuffer();
InputListener inputListener = new InputListener() {
@Override
public void notifyInputLine(final String line) {
buffer.append(line);
buffer.append(StringUtils.LINE_SEPARATOR);
}
};
ProcessStreamReader reader = new ProcessStreamReader.Builder(process)
.inputStream(processInputStream).inputListener(inputListener).build();
try {
reader.start();
final long endTime = (System.currentTimeMillis() + waitTimeMilliseconds);
while (System.currentTimeMillis() < endTime) {
try {
reader.join(waitTimeMilliseconds);
} catch (InterruptedException ignore) {
}
}
} finally {
reader.stop();
}
return buffer.toString();
}
@CliAvailabilityIndicator({CliStrings.START_LOCATOR, CliStrings.STOP_LOCATOR,
CliStrings.STATUS_LOCATOR, CliStrings.START_SERVER, CliStrings.STOP_SERVER,
CliStrings.STATUS_SERVER, CliStrings.START_MANAGER, CliStrings.START_PULSE,
CliStrings.START_VSD, CliStrings.START_DATABROWSER})
public boolean launcherCommandsAvailable() {
return true;
}
protected static final class LauncherSignalListener implements SignalListener {
private volatile boolean signaled = false;
public boolean isSignaled() {
return signaled;
}
public void handle(final SignalEvent event) {
// System.err.printf("Gfsh LauncherSignalListener Received Signal '%1$s' (%2$d)...%n",
// event.getSignal().getName(), event.getSignal().getNumber());
this.signaled = true;
}
}
protected static class StatisticsArchiveFileFilter implements FileFilter {
protected static final StatisticsArchiveFileFilter INSTANCE = new StatisticsArchiveFileFilter();
public boolean accept(final File pathname) {
return (pathname.isFile() && pathname.getAbsolutePath().endsWith(".gfs"));
}
}
protected static class StatisticsArchiveFileAndDirectoryFilter
extends StatisticsArchiveFileFilter {
protected static final StatisticsArchiveFileAndDirectoryFilter INSTANCE =
new StatisticsArchiveFileAndDirectoryFilter();
@Override
public boolean accept(final File pathname) {
return (pathname.isDirectory() || super.accept(pathname));
}
}
}