com.gemstone.gemfire.management.internal.cli.commands.LauncherLifecycleCommands Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gemfire-core Show documentation
Show all versions of gemfire-core Show documentation
SnappyData store based off Pivotal GemFireXD
The newest version!
/*
* Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
*
* Licensed 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. See accompanying
* LICENSE file.
*/
package com.gemstone.gemfire.management.internal.cli.commands;
import java.awt.Desktop;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EmptyStackException;
import java.util.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 javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.Query;
import javax.management.QueryExp;
import com.gemstone.gemfire.GemFireException;
import com.gemstone.gemfire.SystemFailure;
import com.gemstone.gemfire.cache.server.CacheServer;
import com.gemstone.gemfire.distributed.AbstractLauncher;
import com.gemstone.gemfire.distributed.AbstractLauncher.ServiceState;
import com.gemstone.gemfire.distributed.AbstractLauncher.Status;
import com.gemstone.gemfire.distributed.LocatorLauncher;
import com.gemstone.gemfire.distributed.LocatorLauncher.LocatorState;
import com.gemstone.gemfire.distributed.ServerLauncher;
import com.gemstone.gemfire.distributed.ServerLauncher.ServerState;
import com.gemstone.gemfire.distributed.internal.DistributionConfig;
import com.gemstone.gemfire.distributed.internal.tcpserver.TcpClient;
import com.gemstone.gemfire.internal.DistributionLocator;
import com.gemstone.gemfire.internal.SocketCreator;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
import com.gemstone.gemfire.internal.lang.ClassUtils;
import com.gemstone.gemfire.internal.lang.ObjectUtils;
import com.gemstone.gemfire.internal.lang.StringUtils;
import com.gemstone.gemfire.internal.lang.SystemUtils;
import com.gemstone.gemfire.internal.process.ProcessLauncherContext;
import com.gemstone.gemfire.internal.process.ProcessStreamReader;
import com.gemstone.gemfire.internal.process.ProcessStreamReader.InputListener;
import com.gemstone.gemfire.internal.process.ProcessType;
import com.gemstone.gemfire.internal.process.signal.SignalEvent;
import com.gemstone.gemfire.internal.process.signal.SignalListener;
import com.gemstone.gemfire.internal.util.IOUtils;
import com.gemstone.gemfire.lang.AttachAPINotFoundException;
import com.gemstone.gemfire.management.DistributedSystemMXBean;
import com.gemstone.gemfire.management.MemberMXBean;
import com.gemstone.gemfire.management.cli.CliMetaData;
import com.gemstone.gemfire.management.cli.ConverterHint;
import com.gemstone.gemfire.management.cli.Result;
import com.gemstone.gemfire.management.internal.ManagementConstants;
import com.gemstone.gemfire.management.internal.cli.CliUtil;
import com.gemstone.gemfire.management.internal.cli.LogWrapper;
import com.gemstone.gemfire.management.internal.cli.converters.ConnectionEndpointConverter;
import com.gemstone.gemfire.management.internal.cli.domain.ConnectToLocatorResult;
import com.gemstone.gemfire.management.internal.cli.i18n.CliStrings;
import com.gemstone.gemfire.management.internal.cli.result.InfoResultData;
import com.gemstone.gemfire.management.internal.cli.result.ResultBuilder;
import com.gemstone.gemfire.management.internal.cli.shell.Gfsh;
import com.gemstone.gemfire.management.internal.cli.shell.JmxOperationInvoker;
import com.gemstone.gemfire.management.internal.cli.shell.OperationInvoker;
import com.gemstone.gemfire.management.internal.cli.util.CauseFinder;
import com.gemstone.gemfire.management.internal.cli.util.CommandStringBuilder;
import com.gemstone.gemfire.management.internal.cli.util.ConnectionEndpoint;
import com.gemstone.gemfire.management.internal.cli.util.JConsoleNotFoundException;
import com.gemstone.gemfire.management.internal.cli.util.VisualVmNotFoundException;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.shell.core.annotation.CliOption;
/**
* The LauncherLifecycleCommands class encapsulates all GemFire launcher commands for GemFire tools (like starting
* GemFire Monitor (GFMon) and Visual Statistics Display (VSD)) as well external tools (like jconsole).
*
* @author John Blum
* @see com.gemstone.gemfire.management.internal.cli.commands.AbstractCommandsSupport
* @since 7.0
*/
@SuppressWarnings("unused")
public class LauncherLifecycleCommands extends AbstractCommandsSupport {
private static final String LOCATOR_TERM_NAME = "Locator";
private static final String SERVER_TERM_NAME = "Server";
protected static final int CMS_INITIAL_OCCUPANCY_FRACTION = 60;
protected static final int INVALID_PID = -1;
protected static final int MINIMUM_HEAP_FREE_RATIO = 10;
protected static final String ATTACH_API_CLASS_NAME = "com.sun.tools.attach.AttachNotSupportedException";
protected static final String GEMFIRE_HOME = System.getenv("GEMFIRE");
protected static final String JAVA_HOME = System.getProperty("java.home");
protected static final String LOCALHOST = "localhost";
protected static final String LOCATOR_DEPENDENCIES_JAR_PATHNAME =
IOUtils.appendToPath(GEMFIRE_HOME, "lib", "locator-dependencies.jar");
protected static final String SERVER_DEPENDENCIES_JAR_PATHNAME =
IOUtils.appendToPath(GEMFIRE_HOME, "lib", "server-dependencies.jar");
@CliCommand(value = CliStrings.START_LOCATOR, help = CliStrings.START_LOCATOR__HELP)
@CliMetaData(shellOnly = true, relatedTopic = { CliStrings.TOPIC_GEMFIRE_LOCATOR, CliStrings.TOPIC_GEMFIRE_LIFECYCLE })
public Result startLocator(@CliOption(key = CliStrings.START_LOCATOR__MEMBER_NAME,
mandatory = true,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.START_LOCATOR__MEMBER_NAME__HELP)
final String memberName,
@CliOption(key = CliStrings.START_LOCATOR__BIND_ADDRESS,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.START_LOCATOR__BIND_ADDRESS__HELP)
final String bindAddress,
@CliOption(key = CliStrings.START_LOCATOR__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__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 gfSecurityPropertiesPathname,
@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__CONNECT,
unspecifiedDefaultValue = "true",
specifiedDefaultValue = "true",
help = CliStrings.START_LOCATOR__CONNECT__HELP)
boolean connect,
@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)
{
try {
ClassUtils.forName(ATTACH_API_CLASS_NAME, new AttachAPINotFoundException(getAttachAPINotFoundMessage()));
if (workingDirectory == null) {
// attempt to use or make sub-directory using memberName...
final 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)) {
getGfsh().printAsSevere(CliStrings.format(CliStrings.GEMFIRE_0_PROPERTIES_1_NOT_FOUND_MESSAGE, "", gemfirePropertiesPathname));
}
gfSecurityPropertiesPathname = CliUtil.resolvePathname(gfSecurityPropertiesPathname);
if (!StringUtils.isBlank(gfSecurityPropertiesPathname) && !IOUtils.isExistingPathname(gfSecurityPropertiesPathname)) {
getGfsh().printAsSevere(CliStrings.format(CliStrings.GEMFIRE_0_PROPERTIES_1_NOT_FOUND_MESSAGE, "Security ", gfSecurityPropertiesPathname));
}
final File locatorPidFile = new File(workingDirectory, ProcessType.LOCATOR.getPidFileName());
final int oldPid = readPid(locatorPidFile);
final Properties gemfireProperties = new Properties();
gemfireProperties.setProperty(DistributionConfig.GROUPS_NAME, StringUtils.valueOf(group, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(DistributionConfig.LOCATORS_NAME, StringUtils.valueOf(locators, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(DistributionConfig.LOG_LEVEL_NAME, StringUtils.valueOf(logLevel, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(DistributionConfig.MCAST_ADDRESS_NAME, StringUtils.valueOf(mcastBindAddress, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(DistributionConfig.MCAST_PORT_NAME, StringUtils.valueOf(mcastPort, StringUtils.EMPTY_STRING));
final LocatorLauncher locatorLauncher = new LocatorLauncher.Builder()
.setBindAddress(bindAddress)
.setForce(force)
.setHostnameForClients(hostnameForClients)
.setMemberName(memberName)
.setPort(port)
.setRedirectOutput(true)
.setWorkingDirectory(workingDirectory)
.build();
final String[] locatorCommandLine = createStartLocatorCommandLine(locatorLauncher, gemfirePropertiesPathname,
gfSecurityPropertiesPathname, gemfireProperties, 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();
final StringBuffer message = new StringBuffer(); // need thread-safe StringBuffer
final ProcessStreamReader stderrReader = new ProcessStreamReader(locatorProcess.getErrorStream(),
new InputListener() {
@Override
public void notifyInputLine(String line) {
message.append(line).append(StringUtils.LINE_SEPARATOR);
}
}).start();
LocatorState locatorState;
String previousLocatorStatusMessage = null;
final 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(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 = locatorStatus(locatorPidFile, oldPid, memberName);
final 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.stop();
locatorProcess.getErrorStream().close();
getGfsh().getSignalHandler().unregisterListener(locatorSignalListener);
}
Gfsh.println();
final boolean asyncStart = isStartingNotRespondingOrNull(locatorState);
if (asyncStart) {
Gfsh.print(String.format(CliStrings.ASYNC_PROCESS_LAUNCH_MESSAGE, LOCATOR_TERM_NAME));
}
//Add the state of locator to the result and attempt to connect to the locator
//If the connect succeeds add the connected message to the result, else
//Asks the user to use the "connect" command to connect to the locator.
InfoResultData infoResultData = ResultBuilder.createInfoResultData();
if (!asyncStart) {
infoResultData.addLine(locatorState.toString());
}
infoResultData.addLine("\n");
Gfsh gfshInstance = getGfsh();
// should we connect implicitly when in headless mode (gfsh start locator ...)?
// With -e, there could be multiple commands which might presume that
// a prior "start locator" has formed the connection
if (connect && gfshInstance != null && !gfshInstance.isConnectedAndReady()) {
int locatorPort = locatorLauncher.getPort();
String locatorHostName = StringUtils.defaultIfBlank(locatorLauncher.getHostnameForClients(), getLocalHost());
boolean connectSuccess = false;
boolean jmxManagerAuthEnabled = false;
boolean jmxManagerSslEnabled = false;
String responseFailureMessage = null;
for (int i = 0; i < 10; i++) {
try {
ConnectToLocatorResult connectToLocatorResult = ShellCommands.connectToLocator(locatorHostName, locatorPort, ShellCommands.getConnectLocatorTimeoutInMS()/10, Collections. emptyMap());
ConnectionEndpoint memberEndpoint = connectToLocatorResult.getMemberEndpoint();
jmxManagerSslEnabled = connectToLocatorResult.isJmxManagerSslEnabled();
JmxOperationInvoker operationInvoker = new JmxOperationInvoker(memberEndpoint.getHost(), memberEndpoint.getPort(), null, null, Collections. emptyMap());
gfshInstance.setOperationInvoker(operationInvoker);
infoResultData.addLine(CliStrings.format(CliStrings.CONNECT__MSG__SUCCESS, memberEndpoint.toString(false)));
connectSuccess = true;
LogWrapper.getInstance().info(CliStrings.format(CliStrings.CONNECT__MSG__SUCCESS, memberEndpoint.toString(false)));
break;
} catch (IllegalStateException unexpected) {
if (CauseFinder.indexOfCause(unexpected, ClassCastException.class, false) != -1) {
responseFailureMessage = "Might require SSL Configuration.";
}
connectSuccess = false;
} catch (SecurityException ignore) {
if (LogWrapper.getInstance().fineEnabled()) {
LogWrapper.getInstance().fine(ignore.getMessage(), ignore);
}
connectSuccess = false;
jmxManagerAuthEnabled = true;
// no need to continue after SecurityException
break;
} catch (Exception ignore) {
if (LogWrapper.getInstance().fineEnabled()) {
LogWrapper.getInstance().fine(ignore.getMessage(), ignore);
}
connectSuccess = false;
}
}
if (!connectSuccess) {
CommandStringBuilder csb = new CommandStringBuilder(CliStrings.CONNECT);
csb.addOption(CliStrings.CONNECT__LOCATOR, locatorHostName + "[" + locatorPort + "]");
infoResultData.addLine(CliStrings.format(CliStrings.START_LOCATOR__USE__0__TO__CONNECT, csb.toString()));
StringBuilder additionalMessage = new StringBuilder();
if (jmxManagerAuthEnabled) {
additionalMessage.append(" Authentication");
}
if (jmxManagerSslEnabled) {
if (additionalMessage.length() != 0) {
additionalMessage.append(" and ");
}
additionalMessage.append("SSL configuration");
}
if (additionalMessage.length() != 0) {
additionalMessage.append(" required to connect to the manager.");
infoResultData.addLine(additionalMessage.toString());
}
if (responseFailureMessage != null) {
infoResultData.addLine(responseFailureMessage);
}
}
}
return ResultBuilder.buildResult(infoResultData);
}
catch (AttachAPINotFoundException e) {
return ResultBuilder.createUserErrorResult(e.getMessage());
}
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 gfSecurityPropertiesPathname,
final Properties gemfireProperties,
final String[] jvmArgsOpts,
final String initialHeap,
final String maxHeap)
throws MalformedObjectNameException
{
final List commandLine = new ArrayList();
commandLine.add(getJavaPath());
commandLine.add("-classpath");
commandLine.add(getLocatorClasspath(false));
addCurrentLocators(commandLine, gemfireProperties);
addGemFirePropertyFile(commandLine, gemfirePropertiesPathname);
addGemFireSecurityPropertyFile(commandLine, gfSecurityPropertiesPathname);
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("-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()]);
}
@CliCommand(value = CliStrings.STATUS_LOCATOR, help = CliStrings.STATUS_LOCATOR__HELP)
@CliMetaData(shellOnly = true, relatedTopic = { CliStrings.TOPIC_GEMFIRE_LOCATOR, CliStrings.TOPIC_GEMFIRE_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 {
ClassUtils.forName(ATTACH_API_CLASS_NAME, new AttachAPINotFoundException(getAttachAPINotFoundMessage()));
if (!StringUtils.isBlank(member)) {
if (isConnectedAndReady()) {
final MemberMXBean locatorProxy = getMemberMXBean(member);
if (locatorProxy != null) {
return ResultBuilder.createInfoResult(LocatorState.fromJson(locatorProxy.status()).toString());
}
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 status = locatorLauncher.status();
return ResultBuilder.createInfoResult(status.toString());
}
}
catch (AttachAPINotFoundException e) {
return ResultBuilder.createUserErrorResult(e.getMessage());
}
catch (IllegalArgumentException e) {
return ResultBuilder.createUserErrorResult(e.getMessage());
}
catch (IllegalStateException e) {
return ResultBuilder.createUserErrorResult(e.getMessage());
}
catch (VirtualMachineError e) {
SystemFailure.initiateFailure(e);
throw e;
}
catch (Throwable t) {
SystemFailure.checkFailure();
return ResultBuilder.createShellClientErrorResult(String.format(CliStrings.STATUS_LOCATOR__GENERAL_ERROR_MESSAGE,
getLocatorId(locatorHost, locatorPort), StringUtils.defaultIfBlank(workingDirectory, SystemUtils.CURRENT_DIRECTORY),
toString(t, getGfsh().getDebug())));
}
}
@CliCommand(value=CliStrings.STOP_LOCATOR, help=CliStrings.STOP_LOCATOR__HELP)
@CliMetaData(shellOnly=true, relatedTopic = {CliStrings.TOPIC_GEMFIRE_LOCATOR, CliStrings.TOPIC_GEMFIRE_LIFECYCLE})
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 {
ClassUtils.forName(ATTACH_API_CLASS_NAME, new AttachAPINotFoundException(getAttachAPINotFoundMessage()));
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);
while (isVmWithProcessIdRunning(locatorState.getPid())) {
Gfsh.print(".");
synchronized (this) {
TimeUnit.MILLISECONDS.timedWait(this, 500);
}
}
return ResultBuilder.createInfoResult(StringUtils.EMPTY_STRING);
}
else {
return ResultBuilder.createUserErrorResult(locatorState.toString());
}
}
catch (AttachAPINotFoundException e) {
return ResultBuilder.createUserErrorResult(e.getMessage());
}
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 evaluate whether a MalformedObjectNameException should be thrown here; just because we were not able to find
// the "current" Locators in order to conveniently add the new member to the GemFire cluster does not mean we should
// throw an Exception!
protected void addCurrentLocators(final List commandLine, final Properties gemfireProperties) throws MalformedObjectNameException {
if (StringUtils.isBlank(gemfireProperties.getProperty(DistributionConfig.LOCATORS_NAME))) {
final String currentLocators = getCurrentLocators();
if (!StringUtils.isBlank(currentLocators)) {
commandLine.add("-D".concat(ProcessLauncherContext.OVERRIDDEN_DEFAULTS_PREFIX)
.concat(DistributionConfig.LOCATORS_NAME).concat("=").concat(currentLocators));
}
}
}
protected void addGemFirePropertyFile(final List commandLine, final String gemfirePropertiesPathname) {
if (!StringUtils.isBlank(gemfirePropertiesPathname)) {
commandLine.add("-DgemfirePropertyFile=" + gemfirePropertiesPathname);
}
}
protected void addGemFireSecurityPropertyFile(final List commandLine, final String gfSecurityPropertiesPathname) {
if (!StringUtils.isBlank(gfSecurityPropertiesPathname)) {
commandLine.add("-DgemfireSecurityPropertyFile=" + gfSecurityPropertiesPathname);
}
}
protected void addGemFireSystemProperties(final List commandLine, final Properties gemfireProperties) {
for (final Object property : gemfireProperties.keySet()) {
final String propertyName = property.toString();
final String propertyValue = gemfireProperties.getProperty(propertyName);
if (!StringUtils.isBlank(propertyValue)) {
commandLine.add("-Dgemfire." + propertyName + "=" + propertyValue);
}
}
}
protected void addInitialHeap(final List commandLine, final String initialHeap) {
if (!StringUtils.isBlank(initialHeap)) {
commandLine.add("-Xms" + initialHeap);
}
}
protected void addJvmArgumentsAndOptions(final List commandLine, final String[] jvmArgsOpts) {
if (jvmArgsOpts != null) {
commandLine.addAll(Arrays.asList(jvmArgsOpts));
}
}
// Fix for Bug #47192 - "Causing the GemFire member (JVM process) to exit on OutOfMemoryErrors"
protected void addJvmOptionsForOutOfMemoryErrors(final List commandLine) {
if (SystemUtils.isHotSpotVM()) {
if (SystemUtils.isWindows()) {
// ProcessBuilder "on Windows" needs every word (space separated) to be
// a different element in the array/list. See #47312. Need to study why!
commandLine.add("-XX:OnOutOfMemoryError=\"taskkill");
commandLine.add("/F");
commandLine.add("/PID");
commandLine.add("%p\"");
}
else { // All other platforms (Linux, UNIX, etc)
commandLine.add("-XX:OnOutOfMemoryError=\"kill -9 %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()) {
commandLine.add("-XXexitOnOutOfMemory");
}
else {
// NOTE for all other JVMs, do nothing!
}
}
protected void addMaxHeap(final List commandLine, final String maxHeap) {
if (!StringUtils.isBlank(maxHeap)) {
commandLine.add("-Xmx" + maxHeap);
commandLine.add("-XX:+UseConcMarkSweepGC");
commandLine.add("-XX:CMSInitiatingOccupancyFraction=" + CMS_INITIAL_OCCUPANCY_FRACTION);
//commandLine.add("-XX:MinHeapFreeRatio=" + MINIMUM_HEAP_FREE_RATIO);
}
}
protected LocatorState locatorStatus(final File locatorPidFile, final int oldPid, final String memberName) {
final int newPid = readPid(locatorPidFile);
if (newPid != INVALID_PID && newPid != oldPid) {
final 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 String readErrorStream(final Process process) throws IOException {
final BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
final 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) {
}
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) {
final 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);
}
@Deprecated
protected String getClasspath(final String userClasspath) {
String classpath = getDefaultClasspath();
if (!StringUtils.isBlank(userClasspath)) {
classpath += (File.pathSeparator + userClasspath);
}
return classpath;
}
protected String getDefaultClasspath() {
return System.getProperty("java.class.path");
}
protected String getLocatorClasspath(final boolean includeDefaultClasspath) {
return toClasspath(includeDefaultClasspath, new String[] { LOCATOR_DEPENDENCIES_JAR_PATHNAME, getToolsJarPath() });
}
protected String getServerClasspath(final boolean includeDefaultClasspath, final String userClasspath) {
return toClasspath(includeDefaultClasspath, new String[] { SERVER_DEPENDENCIES_JAR_PATHNAME, getToolsJarPath() },
userClasspath);
}
String toClasspath(final boolean includeDefaultClasspath, String[] jarFilePathnames, String... userClasspaths) {
String classpath = (includeDefaultClasspath ? getDefaultClasspath() : StringUtils.EMPTY_STRING);
jarFilePathnames = (jarFilePathnames != null ? jarFilePathnames : StringUtils.EMPTY_STRING_ARRAY);
for (final String jarFilePathname : jarFilePathnames) {
if (!StringUtils.isBlank(jarFilePathname)) {
classpath += (classpath.isEmpty() ? StringUtils.EMPTY_STRING : File.pathSeparator);
classpath += jarFilePathname;
}
}
userClasspaths = (userClasspaths != null ? userClasspaths : StringUtils.EMPTY_STRING_ARRAY);
for (final String userClasspath : userClasspaths) {
if (!StringUtils.isBlank(userClasspath)) {
classpath += (classpath.isEmpty() ? StringUtils.EMPTY_STRING : File.pathSeparator);
classpath += userClasspath;
}
}
return classpath;
}
protected String getJavaPath() {
return new File(new File(JAVA_HOME, "bin"), "java").getPath();
}
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)...
final 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() ? "classes.jar" : "tools.jar"));
}
protected String getLocatorId(final String host, final Integer port) {
final String locatorHost = (host != null ? host : getLocalHost());
final String locatorPort = StringUtils.valueOf(port, String.valueOf(DistributionLocator.DEFAULT_LOCATOR_PORT));
return locatorHost.concat("[").concat(locatorPort).concat("]");
}
/**
* Gets a proxy to the DistributedSystemMXBean from the GemFire Manager's MBeanServer, or null if unable to find
* the DistributedSystemMXBean.
*
* @return a proxy to the DistributedSystemMXBean from the GemFire Manager's MBeanServer, or null if unable to find
* the DistributedSystemMXBean.
*/
protected DistributedSystemMXBean getDistributedSystemMXBean() throws IOException, MalformedObjectNameException {
assertState(isConnectedAndReady(), "Gfsh must be connected in order to get proxy to a GemFire DistributedSystemMXBean.");
return getGfsh().getOperationInvoker().getDistributedSystemMXBean();
}
/**
* Gets a proxy to the MemberMXBean for the GemFire member specified by member name or ID from the GemFire Manager's
* MBeanServer.
*
* @param member a String indicating the GemFire member's name or ID.
* @return a proxy to the MemberMXBean having the specified GemFire member's name or ID from the GemFire Manager's
* MBeanServer, or null if no GemFire member could be found with the specified member name or ID.
* @see #getMemberMXBean(String, String)
*/
protected MemberMXBean getMemberMXBean(final String member) throws IOException {
return getMemberMXBean(null, member);
}
protected MemberMXBean getMemberMXBean(final String serviceName, final String member) throws IOException {
assertState(isConnectedAndReady(), "Gfsh must be connected in order to get proxy to a GemFire Member MBean.");
MemberMXBean memberBean = null;
try {
String objectNamePattern = ManagementConstants.OBJECTNAME__PREFIX;
objectNamePattern += (StringUtils.isBlank(serviceName) ? StringUtils.EMPTY_STRING
: "service=" + serviceName + StringUtils.COMMA_DELIMITER);
objectNamePattern += "type=Member,*";
// NOTE throws a MalformedObjectNameException, however, this should not happen since the ObjectName is constructed
// here in a conforming pattern
final ObjectName objectName = ObjectName.getInstance(objectNamePattern);
final QueryExp query = Query.or(
Query.eq(Query.attr("Name"), Query.value(member)),
Query.eq(Query.attr("Id"), Query.value(member))
);
final Set memberObjectNames = getGfsh().getOperationInvoker().queryNames(objectName, query);
if (!memberObjectNames.isEmpty()) {
memberBean = getGfsh().getOperationInvoker().getMBeanProxy(memberObjectNames.iterator().next(), MemberMXBean.class);
}
}
catch (MalformedObjectNameException e) {
getGfsh().logSevere(e.getMessage(), e);
}
return memberBean;
}
protected String getServerId(final String host, final Integer port) {
final String serverHost = (host != null ? host : getLocalHost());
final 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) {
for (final VirtualMachineDescriptor vm : VirtualMachine.list()) {
if (String.valueOf(pid).equals(vm.id())) {
return true;
}
}
return false;
}
@CliCommand(value = CliStrings.START_SERVER, help = CliStrings.START_SERVER__HELP)
@CliMetaData(shellOnly = true, relatedTopic = { CliStrings.TOPIC_GEMFIRE_SERVER, CliStrings.TOPIC_GEMFIRE_LIFECYCLE })
public Result startServer(@CliOption(key = CliStrings.START_SERVER__ASSIGN_BUCKETS,
unspecifiedDefaultValue = "false",
specifiedDefaultValue = "true",
help = CliStrings.START_SERVER__ASSIGN_BUCKETS__HELP)
final Boolean assignBuckets,
@CliOption(key = CliStrings.START_SERVER__BIND_ADDRESS,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.START_SERVER__BIND_ADDRESS__HELP)
final String bindAddress,
@CliOption(key = CliStrings.START_SERVER__CACHE_XML_FILE,
optionContext = ConverterHint.FILE_PATHSTRING,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.START_SERVER__CACHE_XML_FILE__HELP)
String cacheXmlPathname,
@CliOption(key = CliStrings.START_SERVER__CLASSPATH,
/*optionContext = ConverterHint.FILE_PATHSTRING, // there's an issue with TAB here*/
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.START_SERVER__CLASSPATH__HELP)
final String classpath,
@CliOption(key = CliStrings.START_SERVER__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__FORCE,
unspecifiedDefaultValue = "false",
specifiedDefaultValue = "true",
help = CliStrings.START_SERVER__FORCE__HELP)
final Boolean force,
@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__SECURITY_PROPERTIES,
optionContext = ConverterHint.FILE_PATHSTRING,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.START_SERVER__SECURITY_PROPERTIES__HELP)
String gfSecurityPropertiesPathname,
@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__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__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__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__MEMBER_NAME,
mandatory = true,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.START_SERVER__MEMBER_NAME__HELP)
final String memberName,
@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__REBALANCE,
unspecifiedDefaultValue = "false",
specifiedDefaultValue = "true",
help = CliStrings.START_SERVER__REBALANCE__HELP)
final Boolean rebalance,
@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__STATISTIC_ARCHIVE_FILE,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.START_SERVER__STATISTIC_ARCHIVE_FILE__HELP)
final String statisticsArchivePathname,
@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__INITIAL_HEAP,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.START_SERVER__INITIAL_HEAP__HELP)
final String initialHeap,
@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__J,
optionContext = ConverterHint.STRING_LIST,
unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
help = CliStrings.START_SERVER__J__HELP)
@CliMetaData(valueSeparator = ",")
final String[] jvmArgsOpts)
{
try {
ClassUtils.forName(ATTACH_API_CLASS_NAME, new AttachAPINotFoundException(getAttachAPINotFoundMessage()));
if (workingDirectory == null) {
// attempt to use or make sub-directory using memberName...
final 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)) {
getGfsh().printAsSevere(CliStrings.format(CliStrings.CACHE_XML_NOT_FOUND_MESSAGE, cacheXmlPathname));
}
gemfirePropertiesPathname = CliUtil.resolvePathname(gemfirePropertiesPathname);
if (!StringUtils.isBlank(gemfirePropertiesPathname) && !IOUtils.isExistingPathname(gemfirePropertiesPathname)) {
getGfsh().printAsSevere(CliStrings.format(CliStrings.GEMFIRE_0_PROPERTIES_1_NOT_FOUND_MESSAGE, "", gemfirePropertiesPathname));
}
gfSecurityPropertiesPathname = CliUtil.resolvePathname(gfSecurityPropertiesPathname);
if (!StringUtils.isBlank(gfSecurityPropertiesPathname) && !IOUtils.isExistingPathname(gfSecurityPropertiesPathname)) {
getGfsh().printAsSevere(CliStrings.format(CliStrings.GEMFIRE_0_PROPERTIES_1_NOT_FOUND_MESSAGE, "Security ", gfSecurityPropertiesPathname));
}
final File serverPidFile = new File(workingDirectory, ProcessType.SERVER.getPidFileName());
final int oldPid = readPid(serverPidFile);
final Properties gemfireProperties = new Properties();
gemfireProperties.setProperty(DistributionConfig.BIND_ADDRESS_NAME, StringUtils.valueOf(bindAddress, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(DistributionConfig.CACHE_XML_FILE_NAME, StringUtils.valueOf(cacheXmlPathname, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(DistributionConfig.ENABLE_TIME_STATISTICS_NAME, StringUtils.valueOf(enableTimeStatistics, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(DistributionConfig.GROUPS_NAME, StringUtils.valueOf(group, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(DistributionConfig.LOCATORS_NAME, StringUtils.valueOf(locators, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(DistributionConfig.LOG_LEVEL_NAME, StringUtils.valueOf(logLevel, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(DistributionConfig.MCAST_ADDRESS_NAME, StringUtils.valueOf(mcastBindAddress, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(DistributionConfig.MCAST_PORT_NAME, StringUtils.valueOf(mcastPort, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(DistributionConfig.MEMCACHED_PORT_NAME, StringUtils.valueOf(memcachedPort, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(DistributionConfig.MEMCACHED_PROTOCOL_NAME, StringUtils.valueOf(memcachedProtocol, StringUtils.EMPTY_STRING));
gemfireProperties.setProperty(DistributionConfig.STATISTIC_ARCHIVE_FILE_NAME, StringUtils.valueOf(statisticsArchivePathname, StringUtils.EMPTY_STRING));
final ServerLauncher serverLauncher = new ServerLauncher.Builder()
.setAssignBuckets(assignBuckets)
.setDisableDefaultServer(disableDefaultServer)
.setForce(force)
.setMemberName(memberName)
.setRebalance(rebalance)
.setRedirectOutput(true)
.setServerBindAddress(serverBindAddress)
.setServerPort(serverPort)
.setWorkingDirectory(workingDirectory)
.build();
final String[] serverCommandLine = createStartServerCommandLine(serverLauncher, gemfirePropertiesPathname,
gfSecurityPropertiesPathname, gemfireProperties, classpath, jvmArgsOpts, disableExitWhenOutOfMemory, initialHeap, maxHeap);
//getGfsh().logInfo(StringUtils.concat(serverCommandLine, " "), null);
final Process serverProcess = new ProcessBuilder(serverCommandLine)
.directory(new File(serverLauncher.getWorkingDirectory()))
.start();
serverProcess.getInputStream().close();
serverProcess.getOutputStream().close();
final StringBuffer message = new StringBuffer(); // need thread-safe StringBuffer
final ProcessStreamReader stderrReader = new ProcessStreamReader(serverProcess.getErrorStream(),
new InputListener() {
@Override
public void notifyInputLine(String line) {
message.append(line).append(StringUtils.LINE_SEPARATOR);
}
}).start();
ServerState serverState;
String previousServerStatusMessage = null;
final 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(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 = serverStatus(serverPidFile, oldPid, memberName);
final 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.stop();
serverProcess.getErrorStream().close();
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 (AttachAPINotFoundException e) {
return ResultBuilder.createUserErrorResult(e.getMessage());
}
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 (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 gfSecurityPropertiesPath,
final Properties gemfireProperties,
final String userClasspath,
final String[] jvmArgsOpts,
final Boolean disableExitWhenOutOfMemory,
final String initialHeap,
final String maxHeap)
throws MalformedObjectNameException
{
final List commandLine = new ArrayList();
commandLine.add(getJavaPath());
commandLine.add("-classpath");
commandLine.add(getServerClasspath(false, userClasspath));
addCurrentLocators(commandLine, gemfireProperties);
addGemFirePropertyFile(commandLine, gemfirePropertiesPathname);
addGemFireSecurityPropertyFile(commandLine, gfSecurityPropertiesPath);
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("-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());
}
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_GEMFIRE_SERVER, CliStrings.TOPIC_GEMFIRE_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 {
ClassUtils.forName(ATTACH_API_CLASS_NAME, new AttachAPINotFoundException(getAttachAPINotFoundMessage()));
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 (AttachAPINotFoundException e) {
return ResultBuilder.createUserErrorResult(e.getMessage());
}
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_GEMFIRE_SERVER, CliStrings.TOPIC_GEMFIRE_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 {
ClassUtils.forName(ATTACH_API_CLASS_NAME, new AttachAPINotFoundException(getAttachAPINotFoundMessage()));
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);
while (isVmWithProcessIdRunning(serverState.getPid())) {
Gfsh.print(".");
synchronized (this) {
TimeUnit.MILLISECONDS.timedWait(this, 500);
}
}
return ResultBuilder.createInfoResult(StringUtils.EMPTY_STRING);
}
else {
return ResultBuilder.createUserErrorResult(serverState.toString());
}
}
catch (AttachAPINotFoundException e) {
return ResultBuilder.createUserErrorResult(e.getMessage());
}
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_GEMFIRE_MANAGER, CliStrings.TOPIC_GEMFIRE_JMX, CliStrings.TOPIC_GEMFIRE_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 systepProps,
@CliOption(key=CliStrings.START_MANAGER__GEMFIREPROPS,
unspecifiedDefaultValue=CliMetaData.ANNOTATION_NULL_VALUE,
help=CliStrings.START_MANAGER__GEMFIREPROPS__HELP)
Map gemfireProps)
{
//TODO - Abhishek investigate passing gemfireProps
return ResultBuilder.createInfoResult("Not-implemented");
}
@CliCommand(value = CliStrings.START_JCONSOLE, help = CliStrings.START_JCONSOLE__HELP)
@CliMetaData(shellOnly = true, relatedTopic = { CliStrings.TOPIC_GEMFIRE_MANAGER, CliStrings.TOPIC_GEMFIRE_JMX, CliStrings.TOPIC_GEMFIRE_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 jvmArgs)
{
try {
// Runtime.getRuntime().exec("nohup jconsole &"); // TODO: is this needed
final Process process = Runtime.getRuntime().exec(createJConsoleCommandLine(null, interval, notile, pluginpath,
version, jvmArgs));
final StringBuilder message = new StringBuilder();
if (version) {
process.waitFor();
final BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
message.append(line);
message.append(StringUtils.LINE_SEPARATOR);
}
IOUtils.close(reader);
}
else {
message.append(CliStrings.START_JCONSOLE__RUN);
}
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 jvmArgs)
{
final List 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);
}
}
final 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!");
final Stack 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 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)) {
final ConnectionEndpointConverter converter = new ConnectionEndpointConverter();
try {
final 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)) {
final 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_GEMFIRE_MANAGER, CliStrings.TOPIC_GEMFIRE_JMX, CliStrings.TOPIC_GEMFIRE_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 jvmArgs)
{
try {
Runtime.getRuntime().exec(createJVisualVMCommandLine(jvmArgs));
return ResultBuilder.createInfoResult(CliStrings.START_JVISUALVM__RUN);
}
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 jvmArgs) {
final List 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_GEMFIRE_MANAGER, CliStrings.TOPIC_GEMFIRE_JMX, CliStrings.TOPIC_GEMFIRE_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:8080/pulse",
help = CliStrings.START_PULSE__URL__HELP)
final String url) {
try {
// NOTE try loading the gfmon.html web page from the gemfire.jar file
//desktop.browse(getClass().getResource(GFMON_START_PAGE).toURI());
if (url != null && url.isEmpty()) {
browse(URI.create(url));
} else {
Gfsh gfsh = Gfsh.getCurrentInstance();
if (gfsh != null && gfsh.isConnectedAndReady()) {
OperationInvoker operationInvoker = gfsh.getOperationInvoker();
ObjectName managerObjectName = (ObjectName) operationInvoker.getAttribute(ManagementConstants.OBJECTNAME__DISTRIBUTEDSYSTEM_MXBEAN, "ManagerObjectName");
String pulseURL = (String)operationInvoker.getAttribute(managerObjectName.toString(), "PulseURL");
if (pulseURL != null && !pulseURL.isEmpty()) {
browse(URI.create(pulseURL));
return ResultBuilder.createInfoResult(CliStrings.START_PULSE__RUN + " Pulse URL : " + pulseURL);
} else {
String pulseMessage = (String)operationInvoker.getAttribute(managerObjectName.toString(), "StatusMessage");
if (pulseMessage != null && !pulseMessage.isEmpty()) {
return ResultBuilder.createGemFireErrorResult(pulseMessage);
} else {
return ResultBuilder.createGemFireErrorResult(CliStrings.START_PULSE__URL__NOTFOUND);
}
}
} else {
return ResultBuilder.createUserErrorResult(CliStrings.format(CliStrings.GFSH_MUST_BE_CONNECTED_FOR_LAUNCHING_0, "GemFire Pulse"));
}
}
return ResultBuilder.createInfoResult(CliStrings.START_PULSE__RUN);
}
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 {
final String resourceName = classpathResourceLocation.substring(
classpathResourceLocation.lastIndexOf(File.separator) + 1);
final File resourceFile = new File(System.getProperty("java.io.tmpdir"), resourceName);
if (!resourceFile.exists() && resourceFile.createNewFile()) {
final BufferedReader resourceReader = new BufferedReader(new InputStreamReader(
ClassLoader.getSystemClassLoader().getResourceAsStream(classpathResourceLocation)));
final BufferedWriter resourceFileWriter = new BufferedWriter(new FileWriter(resourceFile, false));
String line;
while ((line = resourceReader.readLine()) != null) {
resourceFileWriter.write(line);
resourceFileWriter.write(StringUtils.LINE_SEPARATOR);
}
resourceFileWriter.flush();
}
resourceFile.deleteOnExit();
return resourceFile;
}
@CliCommand(value=CliStrings.START_VSD, help=CliStrings.START_VSD__HELP)
@CliMetaData(shellOnly=true, relatedTopic = { CliStrings.TOPIC_GEMFIRE_M_AND_M, CliStrings.TOPIC_GEMFIRE_STATISTICS })
public Result startVsd(@CliOption(key=CliStrings.START_VSD__FILE, help=CliStrings.START_VSD__FILE__HELP)
final String[] statisticsArchiveFilePathnames)
{
try {
final String gemfireHome = System.getenv("GEMFIRE");
assertNotNull(gemfireHome, CliStrings.GEMFIRE_HOME_NOT_FOUND_ERROR_MESSAGE);
assertState(new File(getPathToVsd()).exists(), String.format(CliStrings.START_VSD__NOT_FOUND_ERROR_MESSAGE,
gemfireHome));
Runtime.getRuntime().exec(createdVsdCommandLine(statisticsArchiveFilePathnames));
return ResultBuilder.createInfoResult(CliStrings.START_VSD__RUN);
}
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 {
final List 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("GEMFIRE"), "tools", "vsd", "bin", "vsd");
if (SystemUtils.isWindows()) {
vsdPathname += ".bat";
}
return vsdPathname;
}
protected Set processStatisticsArchiveFiles(final String[] statisticsArchiveFilePathnames) throws FileNotFoundException {
final Set statisticsArchiveFiles = new TreeSet();
if (statisticsArchiveFilePathnames != null) {
for (String pathname : statisticsArchiveFilePathnames) {
final File path = new File(pathname);
if (path.exists()) {
if (path.isFile()) {
if (getStatisticsArchiveFileFilter().accept(path)) {
statisticsArchiveFiles.add(pathname);
}
else {
throw new IllegalArgumentException("A Statistics Archive File must end with a .gfs file extension.");
}
}
else { // the File 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;
}
protected void processStatisticsArchiveFiles(final File path, final Set statisticsArchiveFiles) {
if (path != null && path.isDirectory()) {
for (File file : path.listFiles()) {
if (file.isDirectory()) {
processStatisticsArchiveFiles(file, statisticsArchiveFiles);
}
else if (getStatisticsArchiveFileFilter().accept(file)) {
statisticsArchiveFiles.add(file.getAbsolutePath());
}
}
}
}
protected FileFilter getStatisticsArchiveFileFilter() {
return StatisticsArchiveFileFilter.INSTANCE;
}
@CliCommand(value=CliStrings.START_DATABROWSER, help=CliStrings.START_DATABROWSER__HELP)
@CliMetaData(shellOnly=true, relatedTopic={CliStrings.TOPIC_GEMFIRE_M_AND_M})
public Result startDataBrowser()
{
try {
final String gemfireHome = System.getenv("GEMFIRE");
assertState(!StringUtils.isBlank(gemfireHome), CliStrings.GEMFIRE_HOME_NOT_FOUND_ERROR_MESSAGE);
if (isConnectedAndReady() && (getGfsh().getOperationInvoker() instanceof JmxOperationInvoker)) {
final JmxOperationInvoker operationInvoker = (JmxOperationInvoker) getGfsh().getOperationInvoker();
final String dataBrowserPath = getPathToDataBrowser();
assertState(IOUtils.isExistingPathname(dataBrowserPath), String.format(CliStrings.START_DATABROWSER__NOT_FOUND_ERROR_MESSAGE, gemfireHome));
final String commandLine = String.format("%1$s %2$s %3$d", getPathToDataBrowser(),
operationInvoker.getManagerHost(), operationInvoker.getManagerPort());
if (isDebugging()) {
getGfsh().printAsInfo(String.format("GemFire Data Browser Command-line: %1$s", commandLine));
}
Runtime.getRuntime().exec(commandLine);
return ResultBuilder.createInfoResult(CliStrings.START_DATABROWSER__RUN);
}
else {
return ResultBuilder.createUserErrorResult(CliStrings.format(CliStrings.GFSH_MUST_BE_CONNECTED_VIA_JMX_FOR_LAUNCHING_0, "GemFire Data Browser"));
}
}
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(GEMFIRE_HOME, "tools", "DataBrowser", "bin", "databrowser");
if (SystemUtils.isWindows()) {
dataBrowserPathName += ".bat";
}
return dataBrowserPathName;
}
@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() {
final boolean localSignaled = this.signaled;
this.signaled = false;
return localSignaled;
}
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 final class StatisticsArchiveFileFilter implements FileFilter {
protected static final StatisticsArchiveFileFilter INSTANCE = new StatisticsArchiveFileFilter();
public boolean accept(final File pathname) {
return (pathname.isFile() && pathname.getAbsolutePath().endsWith(".gfs"));
}
}
}