| /* |
| * ========================================================================= |
| * Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved. |
| * This product is protected by U.S. and international copyright |
| * and intellectual property laws. Pivotal products are covered by |
| * more patents listed at http://www.pivotal.io/patents. |
| * ======================================================================== |
| */ |
| |
| package com.gemstone.gemfire.distributed; |
| |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.lang.management.ManagementFactory; |
| import java.net.ConnectException; |
| import java.net.InetAddress; |
| import java.net.UnknownHostException; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.TreeMap; |
| import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.TimeoutException; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| import java.util.concurrent.atomic.AtomicReference; |
| import javax.management.MalformedObjectNameException; |
| import javax.management.ObjectName; |
| |
| import com.gemstone.gemfire.cache.client.internal.locator.LocatorStatusResponse; |
| import com.gemstone.gemfire.distributed.internal.DistributionConfig; |
| import com.gemstone.gemfire.distributed.internal.InternalLocator; |
| import com.gemstone.gemfire.internal.DistributionLocator; |
| import com.gemstone.gemfire.internal.GemFireVersion; |
| import com.gemstone.gemfire.internal.SocketCreator; |
| import com.gemstone.gemfire.internal.i18n.LocalizedStrings; |
| 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.ConnectionFailedException; |
| import com.gemstone.gemfire.internal.process.ControlNotificationHandler; |
| import com.gemstone.gemfire.internal.process.ControllableProcess; |
| import com.gemstone.gemfire.internal.process.FileAlreadyExistsException; |
| import com.gemstone.gemfire.internal.process.MBeanInvocationFailedException; |
| import com.gemstone.gemfire.internal.process.PidUnavailableException; |
| import com.gemstone.gemfire.internal.process.ProcessController; |
| import com.gemstone.gemfire.internal.process.ProcessControllerFactory; |
| import com.gemstone.gemfire.internal.process.ProcessControllerParameters; |
| import com.gemstone.gemfire.internal.process.ProcessLauncherContext; |
| import com.gemstone.gemfire.internal.process.ProcessType; |
| import com.gemstone.gemfire.internal.process.ProcessUtils; |
| import com.gemstone.gemfire.internal.process.StartupStatusListener; |
| import com.gemstone.gemfire.internal.process.UnableToControlProcessException; |
| import com.gemstone.gemfire.internal.util.IOUtils; |
| import com.gemstone.gemfire.lang.AttachAPINotFoundException; |
| import com.gemstone.gemfire.management.internal.cli.json.GfJsonArray; |
| import com.gemstone.gemfire.management.internal.cli.json.GfJsonException; |
| import com.gemstone.gemfire.management.internal.cli.json.GfJsonObject; |
| import joptsimple.OptionException; |
| import joptsimple.OptionParser; |
| import joptsimple.OptionSet; |
| |
| /** |
| * The LocatorLauncher class is a launcher for a GemFire Locator. |
| * |
| * @author John Blum |
| * @author Kirk Lund |
| * @see com.gemstone.gemfire.distributed.AbstractLauncher |
| * @see com.gemstone.gemfire.distributed.ServerLauncher |
| * @since 7.0 |
| */ |
| @SuppressWarnings({ "unused" }) |
| public final class LocatorLauncher extends AbstractLauncher<String> { |
| |
| /** |
| * @deprecated This is specific to the internal implementation and may go away in a future release. |
| */ |
| public static final Integer DEFAULT_LOCATOR_PORT = getDefaultLocatorPort(); |
| |
| private static final Boolean DEFAULT_LOAD_SHARED_CONFIG_FROM_DIR = Boolean.FALSE; |
| |
| private static final Map<String, String> helpMap = new HashMap<>(); |
| |
| static { |
| helpMap.put("launcher", LocalizedStrings.LocatorLauncher_LOCATOR_LAUNCHER_HELP.toLocalizedString()); |
| helpMap.put(Command.START.getName(), LocalizedStrings.LocatorLauncher_START_LOCATOR_HELP.toLocalizedString(String.valueOf( |
| getDefaultLocatorPort()))); |
| helpMap.put(Command.STATUS.getName(), LocalizedStrings.LocatorLauncher_STATUS_LOCATOR_HELP.toLocalizedString()); |
| helpMap.put(Command.STOP.getName(),LocalizedStrings.LocatorLauncher_STOP_LOCATOR_HELP.toLocalizedString()); |
| helpMap.put(Command.VERSION.getName(), LocalizedStrings.LocatorLauncher_VERSION_LOCATOR_HELP.toLocalizedString()); |
| helpMap.put("bind-address", LocalizedStrings.LocatorLauncher_LOCATOR_BIND_ADDRESS_HELP.toLocalizedString()); |
| helpMap.put("debug",LocalizedStrings.LocatorLauncher_LOCATOR_DEBUG_HELP.toLocalizedString()); |
| helpMap.put("dir",LocalizedStrings.LocatorLauncher_LOCATOR_DIR_HELP.toLocalizedString()); |
| helpMap.put("force", LocalizedStrings.LocatorLauncher_LOCATOR_FORCE_HELP.toLocalizedString()); |
| helpMap.put("help", LocalizedStrings.SystemAdmin_CAUSES_GEMFIRE_TO_PRINT_OUT_INFORMATION_INSTEAD_OF_PERFORMING_THE_COMMAND_THIS_OPTION_IS_SUPPORTED_BY_ALL_COMMANDS.toLocalizedString()); |
| helpMap.put("hostname-for-clients", LocalizedStrings.LocatorLauncher_LOCATOR_HOSTNAME_FOR_CLIENTS_HELP.toLocalizedString()); |
| helpMap.put("member", LocalizedStrings.LocatorLauncher_LOCATOR_MEMBER_HELP.toLocalizedString()); |
| helpMap.put("pid", LocalizedStrings.LocatorLauncher_LOCATOR_PID_HELP.toLocalizedString()); |
| helpMap.put("port", LocalizedStrings.LocatorLauncher_LOCATOR_PORT_HELP.toLocalizedString(String.valueOf( |
| getDefaultLocatorPort()))); |
| helpMap.put("redirect-output", LocalizedStrings.LocatorLauncher_LOCATOR_REDIRECT_OUTPUT_HELP.toLocalizedString()); |
| } |
| |
| private static final Map<Command, String> usageMap = new TreeMap<>(); |
| |
| static { |
| usageMap.put(Command.START, "start <member-name> [--bind-address=<IP-address>] [--hostname-for-clients=<IP-address>] [--port=<port>] [--dir=<Locator-working-directory>] [--force] [--debug] [--help]"); |
| usageMap.put(Command.STATUS, "status [--bind-address=<IP-address>] [--port=<port>] [--member=<member-ID/Name>] [--pid=<process-ID>] [--dir=<Locator-working-directory>] [--debug] [--help]"); |
| usageMap.put(Command.STOP, "stop [--member=<member-ID/Name>] [--pid=<process-ID>] [--dir=<Locator-working-directory>] [--debug] [--help]"); |
| usageMap.put(Command.VERSION, "version"); |
| } |
| |
| /** |
| * @deprecated This is specific to the internal implementation and may go away in a future release. |
| */ |
| public static final boolean DEFAULT_ENABLE_PEER_LOCATION = true; |
| |
| /** |
| * @deprecated This is specific to the internal implementation and may go away in a future release. |
| */ |
| public static final boolean DEFAULT_ENABLE_SERVER_LOCATION = true; |
| |
| /** |
| * @deprecated This is specific to the internal implementation and may go away in a future release. |
| */ |
| public static final String DEFAULT_LOCATOR_PID_FILE = "vf.gf.locator.pid"; |
| |
| private static final String DEFAULT_LOCATOR_LOG_EXT = ".log"; |
| private static final String DEFAULT_LOCATOR_LOG_NAME = "locator"; |
| private static final String LOCATOR_SERVICE_NAME = "Locator"; |
| |
| private static final AtomicReference<LocatorLauncher> INSTANCE = new AtomicReference<>(); |
| |
| //private volatile transient boolean debug; |
| |
| private final transient ControlNotificationHandler controlHandler; |
| |
| private final AtomicBoolean starting = new AtomicBoolean(false); |
| |
| private final boolean force; |
| private final boolean help; |
| private final boolean redirectOutput; |
| |
| private final Command command; |
| |
| private final boolean bindAddressSpecified; |
| private final boolean portSpecified; |
| private final boolean workingDirectorySpecified; |
| |
| private final InetAddress bindAddress; |
| |
| private final Integer pid; |
| private final Integer port; |
| |
| private volatile transient InternalLocator locator; |
| |
| private final Properties distributedSystemProperties; |
| |
| private final String hostnameForClients; |
| private final String memberName; |
| private final String workingDirectory; |
| |
| // NOTE in addition to debug and locator, the other shared, mutable state |
| private volatile transient String statusMessage; |
| |
| private volatile transient ControllableProcess process; |
| |
| private final transient LocatorControllerParameters controllerParameters; |
| |
| /** |
| * Launches a GemFire Locator from the command-line configured with the given arguments. |
| * |
| * @param args the command-line arguments used to configure the GemFire Locator at runtime. |
| */ |
| public static void main(final String... args) { |
| try { |
| new Builder(args).build().run(); |
| } |
| catch (AttachAPINotFoundException e) { |
| System.err.println(e.getMessage()); |
| } |
| } |
| |
| private static Integer getDefaultLocatorPort() { |
| return Integer.getInteger(DistributionLocator.TEST_OVERRIDE_DEFAULT_PORT_PROPERTY, |
| DistributionLocator.DEFAULT_LOCATOR_PORT); |
| } |
| |
| /** |
| * Gets the instance of the LocatorLauncher used to launch the GemFire Locator, or null if this VM does not |
| * have an instance of LocatorLauncher indicating no GemFire Locator is running. |
| * |
| * @return the instance of LocatorLauncher used to launcher a GemFire Locator in this VM. |
| */ |
| public static LocatorLauncher getInstance() { |
| return INSTANCE.get(); |
| } |
| |
| /** |
| * Gets the LocatorState for this process or null if this process was not launched using this VM's |
| * LocatorLauncher reference. |
| * |
| * @return the LocatorState for this process or null. |
| */ |
| public static LocatorState getLocatorState() { |
| return (getInstance() != null ? getInstance().status() : null); |
| } |
| |
| /** |
| * Private constructor used to properly construct an immutable instance of the LocatorLauncher using a Builder. |
| * The Builder is used to configure a LocatorLauncher instance. The Builder can process user input from the |
| * command-line or be used to properly construct an instance of the LocatorLauncher programmatically using the API. |
| * |
| * @param builder an instance of LocatorLauncher.Builder for configuring and constructing an instance of the |
| * LocatorLauncher. |
| * @see com.gemstone.gemfire.distributed.LocatorLauncher.Builder |
| */ |
| private LocatorLauncher(final Builder builder) { |
| this.command = builder.getCommand(); |
| setDebug(Boolean.TRUE.equals(builder.getDebug())); |
| this.force = Boolean.TRUE.equals(builder.getForce()); |
| this.help = Boolean.TRUE.equals(builder.getHelp()); |
| this.bindAddressSpecified = builder.isBindAddressSpecified(); |
| this.bindAddress = builder.getBindAddress(); |
| this.distributedSystemProperties = builder.getDistributedSystemProperties(); |
| this.hostnameForClients = builder.getHostnameForClients(); |
| this.memberName = builder.getMemberName(); |
| // TODO:KIRK: set ThreadLocal for LogService with getLogFile or getLogFileName |
| this.pid = builder.getPid(); |
| this.portSpecified = builder.isPortSpecified(); |
| this.port = builder.getPort(); |
| this.redirectOutput = Boolean.TRUE.equals(builder.getRedirectOutput()); |
| this.workingDirectorySpecified = builder.isWorkingDirectorySpecified(); |
| this.workingDirectory = builder.getWorkingDirectory(); |
| this.controllerParameters = new LocatorControllerParameters(); |
| this.controlHandler = new ControlNotificationHandler() { |
| @Override |
| public void handleStop() { |
| if (isStoppable()) { |
| stopInProcess(); |
| } |
| } |
| @Override |
| public ServiceState<?> handleStatus() { |
| return statusInProcess(); |
| } |
| }; |
| } |
| |
| /** |
| * Gets the reference to the Locator object representing the running GemFire Locator. |
| * |
| * @return a reference to the Locator. |
| */ |
| final InternalLocator getLocator() { |
| return this.locator; |
| } |
| |
| /** |
| * Gets an identifier that uniquely identifies and represents the Locator associated with this launcher. |
| * |
| * @return a String value identifier to uniquely identify the Locator and it's launcher. |
| * @see #getBindAddressAsString() |
| * @see #getPortAsString() |
| */ |
| public final String getId() { |
| return LocatorState.getBindAddressAsString(this).concat("[").concat(LocatorState.getPortAsString(this)).concat("]"); |
| } |
| |
| /** |
| * Get the Locator launcher command used to invoke the Locator. |
| * |
| * @return the Locator launcher command used to invoke the Locator. |
| * @see com.gemstone.gemfire.distributed.LocatorLauncher.Command |
| */ |
| public Command getCommand() { |
| return this.command; |
| } |
| |
| /** |
| * Determines whether the PID file is allowed to be overwritten when the Locator is started and a PID file |
| * already exists in the Locator's specified working directory. |
| * |
| * @return boolean indicating if force has been enabled. |
| */ |
| public boolean isForcing() { |
| return this.force; |
| } |
| |
| /** |
| * Determines whether this launcher will be used to display help information. If so, then none of the standard |
| * Locator launcher commands will be used to affect the state of the Locator. A launcher is said to be 'helping' |
| * if the user entered the "--help" option (switch) on the command-line. |
| * |
| * @return a boolean value indicating if this launcher is used for displaying help information. |
| * @see com.gemstone.gemfire.distributed.LocatorLauncher.Command |
| */ |
| public boolean isHelping() { |
| return this.help; |
| } |
| |
| /** |
| * Determines whether this launcher will redirect output to system logs when |
| * starting a new Locator process. |
| * |
| * @return a boolean value indicating if this launcher will redirect output |
| * to system logs when starting a new Locator process |
| */ |
| public boolean isRedirectingOutput() { |
| return this.redirectOutput; |
| } |
| |
| /** |
| * Gets the IP address of the NIC to which the Locator has bound itself listening for client requests. |
| * |
| * @return an InetAddress object representing the configured bind address for the Locator. |
| * @see java.net.InetAddress |
| */ |
| public InetAddress getBindAddress() { |
| return this.bindAddress; |
| } |
| |
| /** |
| * Gets the host, as either hostname or IP address, on which the Locator was bound and running. An attempt is made |
| * to get the canonical hostname for IP address to which the Locator was bound for accepting client requests. If |
| * the bind address is null or localhost is unknown, then a default String value of "localhost/127.0.0.1" is returned. |
| * |
| * Note, this information is purely information and should not be used to re-construct state or for |
| * other purposes. |
| * |
| * @return the hostname or IP address of the host running the Locator, based on the bind-address, or |
| * 'localhost/127.0.0.1' if the bind address is null and localhost is unknown. |
| * @see java.net.InetAddress |
| * @see #getBindAddress() |
| */ |
| protected String getBindAddressAsString() { |
| try { |
| if (getBindAddress() != null) { |
| return getBindAddress().getCanonicalHostName(); |
| } |
| |
| InetAddress localhost = SocketCreator.getLocalHost(); |
| |
| return localhost.getCanonicalHostName(); |
| } |
| catch (UnknownHostException ignore) { |
| // TODO determine a better value for the host on which the Locator is running to return here... |
| // NOTE returning localhost/127.0.0.1 implies the bindAddress was null and no IP address for localhost |
| // could be found |
| return "localhost/127.0.0.1"; |
| } |
| } |
| |
| /** |
| * Gets the hostname that clients will use to lookup the running Locator. |
| * |
| * @return a String indicating the hostname used by clients to lookup the Locator. |
| */ |
| public String getHostnameForClients() { |
| return this.hostnameForClients; |
| } |
| |
| /** |
| * Gets the name of the log file used to log information about this Locator. |
| * |
| * @return a String value indicating the name of this Locator's log file. |
| */ |
| public String getLogFileName() { |
| return StringUtils.defaultIfBlank(getMemberName(), DEFAULT_LOCATOR_LOG_NAME).concat(DEFAULT_LOCATOR_LOG_EXT); |
| } |
| |
| /** |
| * Gets the name of this member (this Locator) in the GemFire distributed system and determined by the 'name' GemFire |
| * property. |
| * |
| * @return a String indicating the name of the member (this Locator) in the GemFire distributed system. |
| * @see AbstractLauncher#getMemberName() |
| */ |
| public String getMemberName() { |
| return StringUtils.defaultIfBlank(this.memberName, super.getMemberName()); |
| } |
| |
| /** |
| * Gets the user-specified process ID (PID) of the running Locator that LocatorLauncher uses to issue status and |
| * stop commands to the Locator. |
| * |
| * @return an Integer value indicating the process ID (PID) of the running Locator. |
| */ |
| @Override |
| public Integer getPid() { |
| return this.pid; |
| } |
| |
| /** |
| * Gets the port number on which the Locator listens for client requests. |
| * |
| * @return an Integer value indicating the port number on which the Locator is listening for client requests. |
| */ |
| public Integer getPort() { |
| return this.port; |
| } |
| |
| /** |
| * Gets the port number represented as a String value. If the port number is null, the the default Locator port |
| * (10334) is returned; |
| * |
| * @return the port number as a String value. |
| * @see #getPort() |
| */ |
| public String getPortAsString() { |
| return ObjectUtils.defaultIfNull(getPort(), getDefaultLocatorPort()).toString(); |
| } |
| |
| /** |
| * Gets the GemFire Distributed System (cluster) Properties. |
| * |
| * @return a Properties object containing the configuration settings for the GemFire Distributed System (cluster). |
| * @see java.util.Properties |
| */ |
| public Properties getProperties() { |
| return (Properties) this.distributedSystemProperties.clone(); |
| } |
| |
| /** |
| * Gets the name for a GemFire Locator. |
| * |
| * @return a String indicating the name for a GemFire Locator. |
| */ |
| public String getServiceName() { |
| return LOCATOR_SERVICE_NAME; |
| } |
| |
| /** |
| * Gets the working directory pathname in which the Locator will be run. |
| * |
| * @return a String value indicating the pathname of the Locator's working directory. |
| */ |
| @Override |
| public String getWorkingDirectory() { |
| return this.workingDirectory; |
| } |
| |
| /** |
| * Displays help for the specified Locator launcher command to standard err. If the Locator launcher command |
| * is unspecified, then usage information is displayed instead. |
| * |
| * @param command the Locator launcher command in which to display help information. |
| * @see #usage() |
| */ |
| public void help(final Command command) { |
| if (Command.isUnspecified(command)) { |
| usage(); |
| } |
| else { |
| info(StringUtils.wrap(helpMap.get(command.getName()), 80, "")); |
| info("\n\nusage: \n\n"); |
| info(StringUtils.wrap("> java ... " + getClass().getName() + " " + usageMap.get(command), 80, "\t\t")); |
| info("\n\noptions: \n\n"); |
| |
| for (String option : command.getOptions()) { |
| info(StringUtils.wrap("--" + option + ": " + helpMap.get(option) + "\n", 80, "\t")); |
| } |
| |
| info("\n\n"); |
| } |
| } |
| |
| /** |
| * Displays usage information on the proper invocation of the LocatorLauncher from the command-line to standard err. |
| * |
| * @see #help(com.gemstone.gemfire.distributed.LocatorLauncher.Command) |
| */ |
| public void usage() { |
| info(StringUtils.wrap(helpMap.get("launcher"), 80, "\t")); |
| info("\n\nSTART\n\n"); |
| help(Command.START); |
| info("STATUS\n\n"); |
| help(Command.STATUS); |
| info("STOP\n\n"); |
| help(Command.STOP); |
| } |
| |
| /** |
| * The Runnable method used to launch the Locator with the specified command. If 'start' has been issued, then run |
| * will block as expected for the Locator to stop. The 'start' command is implemented with a call to start() |
| * followed by a call to waitOnLocator(). |
| * |
| * @see java.lang.Runnable |
| * @see LocatorLauncher.Command |
| * @see LocatorLauncher#start() |
| * @see LocatorLauncher#waitOnLocator() |
| * @see LocatorLauncher#status() |
| * @see LocatorLauncher#stop() |
| * @see LocatorLauncher#version() |
| * @see LocatorLauncher#help(com.gemstone.gemfire.distributed.LocatorLauncher.Command) |
| * @see LocatorLauncher#usage() |
| */ |
| public void run() { |
| if (!isHelping()) { |
| switch (getCommand()) { |
| case START: |
| info(start()); |
| waitOnLocator(); |
| break; |
| case STATUS: |
| info(status()); |
| break; |
| case STOP: |
| info(stop()); |
| break; |
| case VERSION: |
| info(version()); |
| break; |
| default: |
| usage(); |
| } |
| } |
| else { |
| help(getCommand()); |
| } |
| } |
| |
| /** |
| * Gets a File reference with the path to the PID file for the Locator. |
| * |
| * @return a File reference to the path of the Locator's PID file. |
| */ |
| protected File getLocatorPidFile() { |
| return new File(getWorkingDirectory(), ProcessType.LOCATOR.getPidFileName()); |
| } |
| |
| /** |
| * Determines whether a GemFire Locator can be started with this instance of LocatorLauncher. |
| * |
| * @return a boolean indicating whether a GemFire Locator can be started with this instance of LocatorLauncher, |
| * which is true if the LocatorLauncher has not already started a Locator or a Locator is not already running. |
| * @see #start() |
| */ |
| private boolean isStartable() { |
| return (!isRunning() && this.starting.compareAndSet(false, true)); |
| } |
| |
| /** |
| * Starts a Locator running on the specified port and bind address, as determined by getPort and getBindAddress |
| * respectively, defaulting to 10334 and 'localhost' if not specified, with both peer and server location enabled. |
| * |
| * 'start' is an asynchronous invocation of the Locator. As such, this method makes no guarantees whether the |
| * Locator's location services (peer and server) are actually running before it returns. The Locator's |
| * location-based services are initiated in separate, daemon Threads and depends on the relative timing |
| * and scheduling of those Threads by the JVM. If the application using this API wishes for the Locator to continue |
| * running after normal application processing completes, then one must call <code>waitOnLocator</code>. |
| * |
| * Given the nature of start, the Locator's status will be in either 1 of 2 possible states. If the 'request' to |
| * start the Locator proceeds without exception, the status will be 'STARTED'. However, if any exception is |
| * encountered during the normal startup sequence, then a RuntimeException is thrown and the status is set to |
| * 'STOPPED'. |
| * |
| * @return a LocatorState to reflect the state of the Locator after start. |
| * @throws RuntimeException if the Locator failed to start for any reason. |
| * @throws IllegalStateException if the Locator is already running. |
| * @see #failOnStart(Throwable) |
| * @see #getBindAddress() |
| * @see #getDistributedSystemProperties() |
| * @see #isForcing() |
| * @see #getLogFile() |
| * @see #getLocatorPidFile |
| * @see #getPort() |
| * @see #status() |
| * @see #stop() |
| * @see #waitOnLocator() |
| * @see #waitOnStatusResponse(long, long, java.util.concurrent.TimeUnit) |
| * @see com.gemstone.gemfire.distributed.LocatorLauncher.LocatorState |
| * @see com.gemstone.gemfire.distributed.AbstractLauncher.Status#NOT_RESPONDING |
| * @see com.gemstone.gemfire.distributed.AbstractLauncher.Status#ONLINE |
| * @see com.gemstone.gemfire.distributed.AbstractLauncher.Status#STARTING |
| */ |
| @SuppressWarnings("deprecation") |
| public LocatorState start() { |
| if (isStartable()) { |
| INSTANCE.compareAndSet(null, this); |
| |
| try { |
| this.process = new ControllableProcess(this.controlHandler, new File(getWorkingDirectory()), ProcessType.LOCATOR, isForcing()); |
| |
| assertPortAvailable(getBindAddress(), getPort()); |
| |
| ProcessLauncherContext.set(isRedirectingOutput(), getOverriddenDefaults(), new StartupStatusListener() { |
| @Override |
| public void setStatus(final String statusMessage) { |
| LocatorLauncher.this.statusMessage = statusMessage; |
| } |
| }); |
| |
| //TODO : remove the extra param for loadFromSharedConfigDir |
| try { |
| this.locator = InternalLocator.startLocator(getPort(), getLogFile(), null, null, null, getBindAddress(), |
| getDistributedSystemProperties(), DEFAULT_ENABLE_PEER_LOCATION, DEFAULT_ENABLE_SERVER_LOCATION, |
| getHostnameForClients(), false); |
| } |
| finally { |
| ProcessLauncherContext.remove(); |
| } |
| |
| debug("Running Locator on (%1$s) in (%2$s) as (%2$s)...", getId(), getWorkingDirectory(), getMember()); |
| running.set(true); |
| |
| return new LocatorState(this, Status.ONLINE); |
| } |
| catch (IOException e) { |
| failOnStart(e); |
| throw new RuntimeException(LocalizedStrings.Launcher_Command_START_IO_ERROR_MESSAGE.toLocalizedString( |
| getServiceName(), getWorkingDirectory(), getId(), e.getMessage()), e); |
| } |
| catch (FileAlreadyExistsException e) { |
| failOnStart(e); |
| throw new RuntimeException(LocalizedStrings.Launcher_Command_START_PID_FILE_ALREADY_EXISTS_ERROR_MESSAGE |
| .toLocalizedString(getServiceName(), getWorkingDirectory(), getId()), e); |
| } |
| catch (PidUnavailableException e) { |
| failOnStart(e); |
| throw new RuntimeException(LocalizedStrings.Launcher_Command_START_PID_UNAVAILABLE_ERROR_MESSAGE |
| .toLocalizedString(getServiceName(), getId(), getWorkingDirectory(), e.getMessage()), e); |
| } |
| catch (Error e) { |
| failOnStart(e); |
| throw e; |
| } |
| catch (RuntimeException e) { |
| failOnStart(e); |
| throw e; |
| } |
| catch (Exception e) { |
| failOnStart(e); |
| throw new RuntimeException(e); |
| } |
| finally { |
| this.starting.set(false); |
| } |
| } |
| else { |
| throw new IllegalStateException(LocalizedStrings.Launcher_Command_START_SERVICE_ALREADY_RUNNING_ERROR_MESSAGE |
| .toLocalizedString(getServiceName(), getWorkingDirectory(), getId())); |
| } |
| } |
| |
| @Override |
| protected Properties getDistributedSystemProperties() { |
| Properties properties = super.getDistributedSystemProperties(getProperties()); |
| return properties; |
| } |
| |
| /** |
| * A helper method to ensure the same sequence of actions are taken when the Locator fails to start |
| * caused by some exception. |
| * |
| * @param cause the Throwable thrown during the startup or wait operation on the Locator. |
| */ |
| private void failOnStart(final Throwable cause) { |
| if (this.locator != null) { |
| this.locator.stop(); |
| this.locator = null; |
| } |
| if (this.process != null) { |
| this.process.stop(); |
| this.process = null; |
| } |
| |
| INSTANCE.compareAndSet(this, null); |
| |
| this.running.set(false); |
| } |
| |
| /** |
| * Waits on the Locator to stop causing the calling Thread to join with the Locator's location-based services Thread. |
| * |
| * @return the Locator's status once it stops. |
| * @throws AssertionError if the Locator has not been started and the reference is null (assertions must be enabled |
| * for the error to be thrown). |
| * @see #failOnStart(Throwable) |
| * @see com.gemstone.gemfire.distributed.AbstractLauncher.Status |
| * @see com.gemstone.gemfire.distributed.LocatorLauncher.LocatorState |
| */ |
| public LocatorState waitOnLocator() { |
| Throwable t = null; |
| |
| try { |
| // make sure the Locator was started and the reference was set |
| assert getLocator() != null : "The Locator must first be started with a call to start!"; |
| |
| debug("Waiting on Locator (%1$s) to stop...", getId()); |
| |
| // prevent the JVM from exiting by joining the Locator Thread |
| getLocator().waitToStop(); |
| } |
| catch (InterruptedException e) { |
| Thread.currentThread().interrupt(); |
| t = e; |
| debug(e); |
| } |
| catch (RuntimeException e) { |
| t = e; |
| throw e; |
| } |
| finally { |
| failOnStart(t); |
| } |
| |
| return new LocatorState(this, Status.STOPPED); |
| } |
| |
| /** |
| * Waits for a Locator status request response to be returned up to the specified timeout in the given unit of time. |
| * This call will send status requests at fixed intervals in the given unit of time until the timeout expires. If |
| * the request to determine the Locator's status is successful, then the Locator is considered to be 'ONLINE'. |
| * Otherwise, the Locator is considered to be unresponsive to the status request. |
| * |
| * However, this does not necessarily imply the Locator start was unsuccessful, only that a response was not received |
| * in the given time period. |
| * |
| * Note, this method does not block or cause the Locator's location-based services (daemon Threads) to continue |
| * running in anyway if the main application Thread terminates when running the Locator in-process. If the caller |
| * wishes to start a Locator in an asynchronous manner within the application process, then a call should be made to |
| * <code>waitOnLocator</code>. |
| * |
| * @param timeout a long value in time unit indicating when the period of time should expire in attempting |
| * to determine the Locator's status. |
| * @param interval a long value in time unit for how frequent the requests should be sent to the Locator. |
| * @param timeUnit the unit of time in which the timeout and interval are measured. |
| * @return the state of the Locator, which will either be 'ONLINE' or "NOT RESPONDING'. If the status returned is |
| * 'NOT RESPONDING', it just means the Locator did not respond to the status request within the given time period. |
| * It should not be taken as the Locator failed to start. |
| * @see #waitOnLocator() |
| */ |
| public LocatorState waitOnStatusResponse(final long timeout, final long interval, final TimeUnit timeUnit) { |
| final long endTimeInMilliseconds = (System.currentTimeMillis() + timeUnit.toMillis(timeout)); |
| |
| while (System.currentTimeMillis() < endTimeInMilliseconds) { |
| try { |
| LocatorStatusResponse response = InternalLocator.statusLocator(getPort(), getBindAddress()); |
| return new LocatorState(this, Status.ONLINE, response); |
| } |
| catch (Exception ignore) { |
| try { |
| synchronized (this) { |
| timeUnit.timedWait(this, interval); |
| } |
| } |
| catch (InterruptedException ignoreInterrupt) { |
| // NOTE just go and send another status request to the Locator... |
| } |
| } |
| } |
| |
| // NOTE just because we were not able to communicate with the Locator in the given amount of time does not mean |
| // the Locator is having problems. The Locator could be slow in starting up and the timeout may not be |
| // long enough. |
| return new LocatorState(this, Status.NOT_RESPONDING); |
| } |
| |
| /** |
| * Attempts to determine the state of the Locator. The Locator's status will be in only 1 of 2 possible states, |
| * either ONLINE or OFFLINE. This method behaves differently depending on which parameters were specified when |
| * the LocatorLauncher was constructed with an instance of Builder. If either the 'dir' or the 'pid' command-line |
| * option were specified, then an attempt is made to determine the Locator's status by using the dir or pid to |
| * correctly identify the Locator's MemberMXBean registered in the MBeanServer of the Locator's JVM, and invoking |
| * the 'status' operation. The same behavior occurs if the caller specified the Locator's GemFire member name or ID. |
| * |
| * However, if 'dir' or 'pid' were not specified, then determining the Locator's status defaults to using the |
| * configured bind address and port. If the bind address or port was not specified when using the Builder to |
| * construct a LocatorLauncher instance, then the defaults for both bind address and port are used. In either case, |
| * an actual TCP/IP request is made to the Locator's ServerSocket to ensure it is listening for client requests. |
| * This is true even when the LocatorLauncher is used in-process by calling the API. |
| * |
| * If the conditions above hold, then the Locator is deemed to be 'ONLINE', otherwise, the Locator is considered |
| * 'OFFLINE'. |
| * |
| * @return the Locator's state. |
| * @see #start() |
| * @see #stop() |
| * @see com.gemstone.gemfire.distributed.AbstractLauncher.Status |
| * @see com.gemstone.gemfire.distributed.LocatorLauncher.LocatorState |
| */ |
| public LocatorState status() { |
| final LocatorLauncher launcher = getInstance(); |
| // if this instance is starting then return local status |
| if (this.starting.get()) { |
| debug("Getting status from the LocatorLauncher instance that actually launched the GemFire Locator.%n"); |
| return new LocatorState(this, Status.STARTING); |
| } |
| // if this instance is running then return local status |
| else if (isRunning()) { |
| debug("Getting Locator status using host (%1$s) and port (%2$s)%n", getBindAddressAsString(), getPortAsString()); |
| return statusWithPort(); |
| } |
| // if in-process do not use ProcessController |
| else if (isPidInProcess() && launcher != null) { |
| return launcher.statusInProcess(); |
| } |
| // attempt to get status using pid if provided |
| else if (getPid() != null) { |
| debug("Getting Locator status using process ID (%1$s)%n", getPid()); |
| return statusWithPid(); |
| } |
| // attempt to get status using workingDirectory unless port was specified |
| else if (!(this.bindAddressSpecified || this.portSpecified)) { |
| debug("Getting Locator status using working directory (%1$s)%n", getWorkingDirectory()); |
| return statusWithWorkingDirectory(); |
| } |
| // attempt to get status using host and port (Note, bind address doubles as host when the launcher |
| // is used to get the Locator's status). |
| else { |
| debug("Getting Locator status using host (%1$s) and port (%2$s)%n", getBindAddressAsString(), getPortAsString()); |
| return statusWithPort(); |
| } |
| } |
| |
| private LocatorState statusInProcess() { |
| if (this.starting.get()) { |
| debug("Getting status from the LocatorLauncher instance that actually launched the GemFire Locator.%n"); |
| return new LocatorState(this, Status.STARTING); |
| } |
| else { |
| debug("Getting Locator status using host (%1$s) and port (%2$s)%n", getBindAddressAsString(), getPortAsString()); |
| return statusWithPort(); |
| } |
| |
| } |
| |
| private LocatorState statusWithPid() { |
| try { |
| final ProcessController controller = new ProcessControllerFactory().createProcessController(this.controllerParameters, getPid()); |
| controller.checkPidSupport(); |
| final String statusJson = controller.status(); |
| return LocatorState.fromJson(statusJson); |
| } |
| catch (ConnectionFailedException e) { |
| // failed to attach to locator JVM |
| return createNoResponseState(e, "Failed to connect to locator with process id " + getPid()); |
| } |
| catch (IOException e) { |
| // failed to open or read file or dir |
| return createNoResponseState(e, "Failed to communicate with locator with process id " + getPid()); |
| } |
| catch (MBeanInvocationFailedException e) { |
| // MBean either doesn't exist or method or attribute don't exist |
| return createNoResponseState(e, "Failed to communicate with locator with process id " + getPid()); |
| } |
| catch (UnableToControlProcessException e) { |
| return createNoResponseState(e, "Failed to communicate with locator with process id " + getPid()); |
| } |
| catch (InterruptedException e) { |
| Thread.currentThread().interrupt(); |
| return createNoResponseState(e, "Interrupted while trying to communicate with locator with process id " + getPid()); |
| } |
| catch (TimeoutException e) { |
| return createNoResponseState(e, "Failed to communicate with locator with process id " + getPid()); |
| } |
| } |
| |
| private LocatorState statusWithPort() { |
| try { |
| LocatorStatusResponse response = InternalLocator.statusLocator(getPort(), getBindAddress()); |
| return new LocatorState(this, Status.ONLINE, response); |
| } |
| catch (Exception e) { |
| return createNoResponseState(e, "Failed to connect to locator " + getId()); |
| } |
| } |
| |
| private LocatorState statusWithWorkingDirectory() { |
| int parsedPid = 0; |
| try { |
| final ProcessController controller = new ProcessControllerFactory().createProcessController(this.controllerParameters, new File(getWorkingDirectory()), ProcessType.LOCATOR.getPidFileName(), READ_PID_FILE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); |
| parsedPid = controller.getProcessId(); |
| |
| // note: in-process request will go infinite loop unless we do the following |
| if (parsedPid == ProcessUtils.identifyPid()) { |
| LocatorLauncher runningLauncher = getInstance(); |
| if (runningLauncher != null) { |
| return runningLauncher.status(); |
| } |
| } |
| |
| final String statusJson = controller.status(); |
| return LocatorState.fromJson(statusJson); |
| } |
| catch (ConnectionFailedException e) { |
| // failed to attach to locator JVM |
| return createNoResponseState(e, "Failed to connect to locator with process id " + parsedPid); |
| } |
| catch (FileNotFoundException e) { |
| // could not find pid file |
| return createNoResponseState(e, "Failed to find process file " + ProcessType.LOCATOR.getPidFileName() + " in " + getWorkingDirectory()); |
| } |
| catch (IOException e) { |
| // failed to open or read file or dir |
| return createNoResponseState(e, "Failed to communicate with locator with process id " + parsedPid); |
| } |
| catch (MBeanInvocationFailedException e) { |
| // MBean either doesn't exist or method or attribute don't exist |
| return createNoResponseState(e, "Failed to communicate with locator with process id " + parsedPid); |
| } |
| catch (PidUnavailableException e) { |
| // couldn't determine pid from within locator JVM |
| return createNoResponseState(e, "Failed to find usable process id within file " + ProcessType.LOCATOR.getPidFileName() + " in " + getWorkingDirectory()); |
| } |
| catch (UnableToControlProcessException e) { |
| return createNoResponseState(e, "Failed to communicate with locator with process id " + parsedPid); |
| } |
| catch (InterruptedException e) { |
| Thread.currentThread().interrupt(); |
| return createNoResponseState(e, "Interrupted while trying to communicate with locator with process id " + parsedPid); |
| } |
| catch (TimeoutException e) { |
| return createNoResponseState(e, "Failed to communicate with locator with process id " + parsedPid); |
| } |
| } |
| |
| /** |
| * Determines whether the Locator can be stopped in-process, such as when a Locator is embedded in an application |
| * and the LocatorLauncher API is being used. |
| * |
| * @return a boolean indicating whether the Locator can be stopped in-process (the application's process with |
| * an embedded Locator). |
| */ |
| protected boolean isStoppable() { |
| return (isRunning() && getLocator() != null); |
| } |
| |
| /** |
| * Stop shuts the running Locator down. Using the API, the Locator is requested to stop by calling the Locator |
| * object's 'stop' method. Internally, this method is no different than using the LocatorLauncher class from the |
| * command-line or from within GemFire shell (Gfsh). In every single case, stop sends a TCP/IP 'shutdown' request |
| * on the configured address/port to which the Locator is bound and listening. |
| * |
| * If the "shutdown" request is successful, then the Locator will be 'STOPPED'. Otherwise, the Locator is considered |
| * 'OFFLINE' since the actual state cannot be fully assessed (as in the application process in which the Locator was |
| * hosted may still be running and the Locator object may still exist even though it is no longer responding to |
| * location-based requests). The later is particularly important in cases where the system resources (such as |
| * Sockets) may not have been cleaned up yet. Therefore, by returning a status of 'OFFLINE', the value is meant to |
| * reflect this in-deterministic state. |
| * |
| * @return a LocatorState indicating the state of the Locator after stop has been requested. |
| * @see #start() |
| * @see #status() |
| * @see com.gemstone.gemfire.distributed.LocatorLauncher.LocatorState |
| * @see com.gemstone.gemfire.distributed.AbstractLauncher.Status#NOT_RESPONDING |
| * @see com.gemstone.gemfire.distributed.AbstractLauncher.Status#STOPPED |
| */ |
| public LocatorState stop() { |
| final LocatorLauncher launcher = getInstance(); |
| // if this instance is running then stop it |
| if (isStoppable()) { |
| return stopInProcess(); |
| } |
| // if in-process but difference instance of LocatorLauncher |
| else if (isPidInProcess() && launcher != null) { |
| return launcher.stopInProcess(); |
| } |
| // attempt to stop Locator using pid... |
| else if (getPid() != null) { |
| return stopWithPid(); |
| } |
| // attempt to stop Locator using the working directory... |
| //else if (this.workingDirectorySpecified) { |
| else if (getWorkingDirectory() != null) { |
| return stopWithWorkingDirectory(); |
| } |
| else { |
| return new LocatorState(this, Status.NOT_RESPONDING); |
| } |
| } |
| |
| private LocatorState stopInProcess() { |
| if (isStoppable()) { |
| this.locator.stop(); |
| this.locator = null; |
| this.process.stop(); |
| this.process = null; |
| INSTANCE.compareAndSet(this, null); // note: other thread may return Status.NOT_RESPONDING now |
| this.running.set(false); |
| return new LocatorState(this, Status.STOPPED); |
| } else { |
| return new LocatorState(this, Status.NOT_RESPONDING); |
| } |
| } |
| |
| private LocatorState stopWithPid() { |
| try { |
| final ProcessController controller = new ProcessControllerFactory().createProcessController(new LocatorControllerParameters(), getPid()); |
| controller.checkPidSupport(); |
| controller.stop(); |
| return new LocatorState(this, Status.STOPPED); |
| } |
| catch (ConnectionFailedException e) { |
| // failed to attach to locator JVM |
| return createNoResponseState(e, "Failed to connect to locator with process id " + getPid()); |
| } |
| catch (IOException e) { |
| // failed to open or read file or dir |
| return createNoResponseState(e, "Failed to communicate with locator with process id " + getPid()); |
| } |
| catch (MBeanInvocationFailedException e) { |
| // MBean either doesn't exist or method or attribute don't exist |
| return createNoResponseState(e, "Failed to communicate with locator with process id " + getPid()); |
| } |
| catch (UnableToControlProcessException e) { |
| return createNoResponseState(e, "Failed to communicate with locator with process id " + getPid()); |
| } |
| } |
| |
| @Deprecated |
| private LocatorState stopWithPort() { |
| try { |
| InternalLocator.stopLocator(getPort(), getBindAddress()); |
| return new LocatorState(this, Status.STOPPED); |
| } |
| catch (ConnectException e) { |
| if (getBindAddress() == null) { |
| return createNoResponseState(e, "Failed to connect to locator on port " + getPort()); |
| } |
| else { |
| return createNoResponseState(e, "Failed to connect to locator on " + getId()); |
| } |
| } |
| } |
| |
| private LocatorState stopWithWorkingDirectory() { |
| int parsedPid = 0; |
| try { |
| final ProcessController controller = new ProcessControllerFactory().createProcessController(this.controllerParameters, new File(getWorkingDirectory()), ProcessType.LOCATOR.getPidFileName(), READ_PID_FILE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); |
| parsedPid = controller.getProcessId(); |
| |
| // NOTE in-process request will go infinite loop unless we do the following |
| if (parsedPid == ProcessUtils.identifyPid()) { |
| final LocatorLauncher runningLauncher = getInstance(); |
| if (runningLauncher != null) { |
| return runningLauncher.stopInProcess(); |
| } |
| } |
| |
| controller.stop(); |
| return new LocatorState(this, Status.STOPPED); |
| } |
| catch (ConnectionFailedException e) { |
| // failed to attach to locator JVM |
| return createNoResponseState(e, "Failed to connect to locator with process id " + parsedPid); |
| } |
| catch (FileNotFoundException e) { |
| // could not find pid file |
| return createNoResponseState(e, "Failed to find process file " + ProcessType.LOCATOR.getPidFileName() + " in " + getWorkingDirectory()); |
| } |
| catch (IOException e) { |
| // failed to open or read file or dir |
| return createNoResponseState(e, "Failed to communicate with locator with process id " + parsedPid); |
| } |
| catch (InterruptedException e) { |
| Thread.currentThread().interrupt(); |
| return createNoResponseState(e, "Interrupted while trying to communicate with locator with process id " + parsedPid); |
| } |
| catch (MBeanInvocationFailedException e) { |
| // MBean either doesn't exist or method or attribute don't exist |
| return createNoResponseState(e, "Failed to communicate with locator with process id " + parsedPid); |
| } |
| catch (PidUnavailableException e) { |
| // couldn't determine pid from within locator JVM |
| return createNoResponseState(e, "Failed to find usable process id within file " + ProcessType.LOCATOR.getPidFileName() + " in " + getWorkingDirectory()); |
| } |
| catch (TimeoutException e) { |
| return createNoResponseState(e, "Timed out trying to find usable process id within file " + ProcessType.LOCATOR.getPidFileName() + " in " + getWorkingDirectory()); |
| } |
| catch (UnableToControlProcessException e) { |
| return createNoResponseState(e, "Failed to communicate with locator with process id " + parsedPid); |
| } |
| } |
| |
| private LocatorState createNoResponseState(final Exception cause, final String errorMessage) { |
| debug(cause); |
| //info(errorMessage); |
| return new LocatorState(this, Status.NOT_RESPONDING, errorMessage); |
| } |
| |
| private Properties getOverriddenDefaults() { |
| Properties overriddenDefaults = new Properties(); |
| |
| overriddenDefaults.put(ProcessLauncherContext.OVERRIDDEN_DEFAULTS_PREFIX.concat(DistributionConfig.LOG_FILE_NAME), |
| getLogFileName()); |
| |
| for (String key : System.getProperties().stringPropertyNames()) { |
| if (key.startsWith(ProcessLauncherContext.OVERRIDDEN_DEFAULTS_PREFIX)) { |
| overriddenDefaults.put(key, System.getProperty(key)); |
| } |
| } |
| |
| return overriddenDefaults; |
| } |
| |
| private class LocatorControllerParameters implements ProcessControllerParameters { |
| @Override |
| public File getPidFile() { |
| return getLocatorPidFile(); |
| } |
| |
| @Override |
| public File getWorkingDirectory() { |
| return new File(LocatorLauncher.this.getWorkingDirectory()); |
| } |
| |
| @Override |
| public int getProcessId() { |
| return getPid(); |
| } |
| |
| @Override |
| public ProcessType getProcessType() { |
| return ProcessType.LOCATOR; |
| } |
| |
| @Override |
| public ObjectName getNamePattern() { |
| try { |
| return ObjectName.getInstance("GemFire:type=Member,*"); |
| } catch (MalformedObjectNameException e) { |
| return null; |
| } catch (NullPointerException e) { |
| return null; |
| } |
| } |
| |
| @Override |
| public String getPidAttribute() { |
| return "ProcessId"; |
| } |
| |
| @Override |
| public String getStopMethod() { |
| return "shutDownMember"; |
| } |
| |
| @Override |
| public String getStatusMethod() { |
| return "status"; |
| } |
| |
| @Override |
| public String[] getAttributes() { |
| return new String[] {"Locator", "Server"}; |
| } |
| |
| @Override |
| public Object[] getValues() { |
| return new Object[] {Boolean.TRUE, Boolean.FALSE}; |
| } |
| } |
| |
| /** |
| * Following the Builder design pattern, the LocatorLauncher Builder is used to configure and create a properly |
| * initialized instance of the LocatorLauncher class for running the Locator and performing other Locator |
| * operations. |
| */ |
| public static class Builder { |
| |
| protected static final Command DEFAULT_COMMAND = Command.UNSPECIFIED; |
| |
| private Boolean debug; |
| private Boolean force; |
| private Boolean help; |
| private Boolean redirectOutput; |
| private Boolean loadSharedConfigFromDir; |
| private Command command; |
| |
| private InetAddress bindAddress; |
| |
| private Integer pid; |
| private Integer port; |
| |
| private final Properties distributedSystemProperties = new Properties(); |
| |
| private String hostnameForClients; |
| private String memberName; |
| private String workingDirectory; |
| |
| /** |
| * Default constructor used to create an instance of the Builder class for programmatical access. |
| */ |
| public Builder() { |
| } |
| |
| /** |
| * Constructor used to create and configure an instance of the Builder class with the specified arguments, often |
| * passed from the command-line when launching an instance of this class from the command-line using the Java |
| * launcher. |
| * |
| * @param args the array of arguments used to configure the Builder. |
| */ |
| public Builder(final String... args) { |
| parseArguments(args != null ? args : new String[0]); |
| } |
| |
| /** |
| * Gets an instance of the JOpt Simple OptionParser to parse the command-line arguments. |
| * |
| * @return an instance of the JOpt Simple OptionParser configured with the command-line options used by the Locator. |
| */ |
| private OptionParser getParser() { |
| final OptionParser parser = new OptionParser(true); |
| |
| parser.accepts("bind-address").withRequiredArg().ofType(String.class); |
| parser.accepts("debug"); |
| parser.accepts("dir").withRequiredArg().ofType(String.class); |
| parser.accepts("force"); |
| parser.accepts("help"); |
| parser.accepts("hostname-for-clients").withRequiredArg().ofType(String.class); |
| parser.accepts("pid").withRequiredArg().ofType(Integer.class); |
| parser.accepts("port").withRequiredArg().ofType(Integer.class); |
| parser.accepts("redirect-output"); |
| parser.accepts("version"); |
| |
| return parser; |
| } |
| |
| /** |
| * Parses an array of arguments to configure this Builder with the intent of constructing a Locator launcher to |
| * invoke a Locator. This method is called to parse the arguments specified by the user on the command-line. |
| * |
| * @param args the array of arguments used to configure this Builder and create an instance of LocatorLauncher. |
| */ |
| protected void parseArguments(final String... args) { |
| try { |
| parseCommand(args); |
| parseMemberName(args); |
| |
| final OptionSet options = getParser().parse(args); |
| |
| setDebug(options.has("debug")); |
| setForce(options.has("force")); |
| setHelp(options.has("help")); |
| setRedirectOutput(options.has("redirect-output")); |
| |
| if (!isHelping()) { |
| if (options.has("bind-address")) { |
| setBindAddress(ObjectUtils.toString(options.valueOf("bind-address"))); |
| } |
| |
| if (options.has("dir")) { |
| setWorkingDirectory(ObjectUtils.toString(options.valueOf("dir"))); |
| } |
| |
| if (options.has("hostname-for-clients")) { |
| setHostnameForClients(ObjectUtils.toString(options.valueOf("hostname-for-clients"))); |
| } |
| |
| if (options.has("pid")) { |
| setPid((Integer) options.valueOf("pid")); |
| } |
| |
| if (options.has("port")) { |
| setPort((Integer) options.valueOf("port")); |
| } |
| |
| if (options.has("version")) { |
| setCommand(Command.VERSION); |
| } |
| } |
| } |
| catch (OptionException e) { |
| throw new IllegalArgumentException(LocalizedStrings.Launcher_Builder_PARSE_COMMAND_LINE_ARGUMENT_ERROR_MESSAGE |
| .toLocalizedString("Locator", e.getMessage()), e); |
| } |
| catch (Exception e) { |
| throw new RuntimeException(e.getMessage(), e); |
| } |
| } |
| |
| /** |
| * Iterates the list of arguments in search of the target Locator launcher command. |
| * |
| * @param args an array of arguments from which to search for the Locator launcher command. |
| * @see com.gemstone.gemfire.distributed.LocatorLauncher.Command#valueOfName(String) |
| * @see #parseArguments(String...) |
| */ |
| protected void parseCommand(final String... args) { |
| // search the list of arguments for the command; technically, the command should be the first argument in the |
| // list, but does it really matter? stop after we find one valid command. |
| for (String arg : args) { |
| final Command command = Command.valueOfName(arg); |
| if (command != null) { |
| setCommand(command); |
| break; |
| } |
| } |
| } |
| |
| /** |
| * Iterates the list of arguments in search of the Locator's GemFire member name. If the argument does not |
| * start with '-' or is not the name of a Locator launcher command, then the value is presumed to be the member name |
| * for the Locator in GemFire. |
| * |
| * @param args the array of arguments from which to search for the Locator's member name in GemFire. |
| * @see com.gemstone.gemfire.distributed.LocatorLauncher.Command#isCommand(String) |
| * @see #parseArguments(String...) |
| */ |
| protected void parseMemberName(final String[] args) { |
| for (String arg : args) { |
| if (!(arg.startsWith(OPTION_PREFIX) || Command.isCommand(arg))) { |
| setMemberName(arg); |
| break; |
| } |
| } |
| } |
| |
| /** |
| * Gets the Locator launcher command used during the invocation of the LocatorLauncher. |
| * |
| * @return the Locator launcher command used to invoke (run) the LocatorLauncher class. |
| * @see #setCommand(com.gemstone.gemfire.distributed.LocatorLauncher.Command) |
| * @see LocatorLauncher.Command |
| */ |
| public Command getCommand() { |
| return ObjectUtils.defaultIfNull(this.command, DEFAULT_COMMAND); |
| } |
| |
| /** |
| * Sets the Locator launcher command used during the invocation of the LocatorLauncher |
| * |
| * @param command the targeted Locator launcher command used during the invocation (run) of LocatorLauncher. |
| * @return this Builder instance. |
| * @see #getCommand() |
| * @see LocatorLauncher.Command |
| */ |
| public Builder setCommand(final Command command) { |
| this.command = command; |
| return this; |
| } |
| |
| /** |
| * Determines whether the new instance of the LocatorLauncher will be set to debug mode. |
| * |
| * @return a boolean value indicating whether debug mode is enabled or disabled. |
| * @see #setDebug(Boolean) |
| */ |
| public Boolean getDebug() { |
| return this.debug; |
| } |
| |
| /** |
| * Sets whether the new instance of the LocatorLauncher will be set to debug mode. |
| * |
| * @param debug a boolean value indicating whether debug mode is to be enabled or disabled. |
| * @return this Builder instance. |
| * @see #getHelp() |
| */ |
| public Builder setDebug(final Boolean debug) { |
| this.debug = debug; |
| return this; |
| } |
| |
| /** |
| * Gets the GemFire Distributed System (cluster) Properties configuration. |
| * |
| * @return a Properties object containing configuration settings for the GemFire Distributed System (cluster). |
| * @see java.util.Properties |
| */ |
| public Properties getDistributedSystemProperties() { |
| return this.distributedSystemProperties; |
| } |
| |
| /** |
| * Gets the boolean value used by the Locator to determine if it should overwrite the PID file if it already exists. |
| * |
| * @return the boolean value specifying whether or not to overwrite the PID file if it already exists. |
| * @see com.gemstone.gemfire.internal.process.LocalProcessLauncher |
| * @see #setForce(Boolean) |
| */ |
| public Boolean getForce() { |
| return ObjectUtils.defaultIfNull(this.force, DEFAULT_FORCE); |
| } |
| |
| /** |
| * Sets the boolean value used by the Locator to determine if it should overwrite the PID file if it already exists. |
| * |
| * @param force a boolean value indicating whether to overwrite the PID file when it already exists. |
| * @return this Builder instance. |
| * @see com.gemstone.gemfire.internal.process.LocalProcessLauncher |
| * @see #getForce() |
| */ |
| public Builder setForce(final Boolean force) { |
| this.force = force; |
| return this; |
| } |
| |
| |
| /** |
| * Determines whether the new instance of LocatorLauncher will be used to output help information for either |
| * a specific command, or for using LocatorLauncher in general. |
| * |
| * @return a boolean value indicating whether help will be output during the invocation of LocatorLauncher. |
| * @see #setHelp(Boolean) |
| */ |
| public Boolean getHelp() { |
| return this.help; |
| } |
| |
| /** |
| * Determines whether help has been enabled. |
| * |
| * @return a boolean indicating if help was enabled. |
| */ |
| private boolean isHelping() { |
| return Boolean.TRUE.equals(getHelp()); |
| } |
| |
| /** |
| * Sets whether the new instance of LocatorLauncher will be used to output help information for either a specific |
| * command, or for using LocatorLauncher in general. |
| * |
| * @param help a boolean indicating whether help information is to be displayed during invocation of LocatorLauncher. |
| * @return this Builder instance. |
| * @see #getHelp() |
| */ |
| public Builder setHelp(final Boolean help) { |
| this.help = help; |
| return this; |
| } |
| |
| final boolean isBindAddressSpecified() { |
| return (getBindAddress() != null); |
| |
| } |
| /** |
| * Gets the IP address to which the Locator has bound itself listening for client requests. |
| * |
| * @return an InetAddress with the IP address or hostname on which the Locator is bound and listening. |
| * @see #setBindAddress(String) |
| * @see java.net.InetAddress |
| */ |
| public InetAddress getBindAddress() { |
| return this.bindAddress; |
| } |
| |
| /** |
| * Sets the IP address as an java.net.InetAddress to which the Locator has bound itself listening for client |
| * requests. |
| * |
| * @param bindAddress the InetAddress with the IP address or hostname on which the Locator is bound and listening. |
| * @return this Builder instance. |
| * @throws IllegalArgumentException wrapping the UnknownHostException if the IP address or hostname for the |
| * bind address is unknown. |
| * @see #getBindAddress() |
| * @see java.net.InetAddress |
| */ |
| public Builder setBindAddress(final String bindAddress) { |
| if (StringUtils.isBlank(bindAddress)) { |
| this.bindAddress = null; |
| return this; |
| } |
| else { |
| try { |
| this.bindAddress = InetAddress.getByName(bindAddress); |
| return this; |
| } |
| catch (UnknownHostException e) { |
| throw new IllegalArgumentException(LocalizedStrings.Launcher_Builder_UNKNOWN_HOST_ERROR_MESSAGE |
| .toLocalizedString("Locator"), e); |
| } |
| } |
| } |
| |
| /** |
| * Gets the hostname used by clients to lookup the Locator. |
| * |
| * @return a String indicating the hostname Locator binding used in client lookups. |
| * @see #setHostnameForClients(String) |
| */ |
| public String getHostnameForClients() { |
| return this.hostnameForClients; |
| } |
| |
| /** |
| * Sets the hostname used by clients to lookup the Locator. |
| * |
| * @param hostnameForClients a String indicating the hostname Locator binding used in client lookups. |
| * @return this Builder instance. |
| * @throws IllegalArgumentException if the hostname was not specified (is blank or empty), such as when the |
| * --hostname-for-clients command-line option may have been specified without any argument. |
| * @see #getHostnameForClients() |
| */ |
| public Builder setHostnameForClients(final String hostnameForClients) { |
| if (StringUtils.isEmpty(StringUtils.trim(hostnameForClients))) { |
| throw new IllegalArgumentException( |
| LocalizedStrings.LocatorLauncher_Builder_INVALID_HOSTNAME_FOR_CLIENTS_ERROR_MESSAGE.toLocalizedString()); |
| } |
| this.hostnameForClients = hostnameForClients; |
| return this; |
| } |
| |
| /** |
| * Gets the member name of this Locator in GemFire. |
| * |
| * @return a String indicating the member name of this Locator in GemFire. |
| * @see #setMemberName(String) |
| */ |
| public String getMemberName() { |
| return this.memberName; |
| } |
| |
| /** |
| * Sets the member name of the Locator in GemFire. |
| * |
| * @param memberName a String indicating the member name of this Locator in GemFire. |
| * @return this Builder instance. |
| * @throws IllegalArgumentException if the member name is invalid. |
| * @see #getMemberName() |
| */ |
| public Builder setMemberName(final String memberName) { |
| if (StringUtils.isEmpty(StringUtils.trim(memberName))) { |
| throw new IllegalArgumentException(LocalizedStrings.Launcher_Builder_MEMBER_NAME_ERROR_MESSAGE |
| .toLocalizedString("Locator")); |
| } |
| this.memberName = memberName; |
| return this; |
| } |
| |
| /** |
| * Gets the process ID (PID) of the running Locator indicated by the user as an argument to the LocatorLauncher. |
| * This PID is used by the Locator launcher to determine the Locator's status, or invoke shutdown on the Locator. |
| * |
| * @return a user specified Integer value indicating the process ID of the running Locator. |
| * @see #setPid(Integer) |
| */ |
| public Integer getPid() { |
| return this.pid; |
| } |
| |
| /** |
| * Sets the process ID (PID) of the running Locator indicated by the user as an argument to the LocatorLauncher. |
| * This PID will be used by the Locator launcher to determine the Locator's status, or invoke shutdown on |
| * the Locator. |
| * |
| * @param pid a user specified Integer value indicating the process ID of the running Locator. |
| * @return this Builder instance. |
| * @throws IllegalArgumentException if the process ID (PID) is not valid (greater than zero if not null). |
| * @see #getPid() |
| */ |
| public Builder setPid(final Integer pid) { |
| if (pid != null && pid < 0) { |
| throw new IllegalArgumentException(LocalizedStrings.Launcher_Builder_PID_ERROR_MESSAGE.toLocalizedString()); |
| } |
| this.pid = pid; |
| return this; |
| } |
| |
| boolean isPortSpecified() { |
| return (this.port != null); |
| } |
| |
| /** |
| * Gets the port number used by the Locator to listen for client requests. If the port was not specified, then the |
| * default Locator port (10334) is returned. |
| * |
| * @return the specified Locator port or the default port if unspecified. |
| * @see #setPort(Integer) |
| */ |
| public Integer getPort() { |
| return ObjectUtils.defaultIfNull(port, getDefaultLocatorPort()); |
| } |
| |
| /** |
| * Sets the port number used by the Locator to listen for client requests. The port number must be between 1 and |
| * 65535 inclusive. |
| * |
| * @param port an Integer value indicating the port used by the Locator to listen for client requests. |
| * @return this Builder instance. |
| * @throws IllegalArgumentException if the port number is not valid. |
| * @see #getPort() |
| */ |
| public Builder setPort(final Integer port) { |
| // NOTE if the user were to specify a port number of 0, then java.net.ServerSocket will pick an ephemeral port |
| // to bind the socket, which we do not want. |
| if (port != null && (port < 0 || port > 65535)) { |
| throw new IllegalArgumentException(LocalizedStrings.Launcher_Builder_INVALID_PORT_ERROR_MESSAGE |
| .toLocalizedString("Locator")); |
| } |
| this.port = port; |
| return this; |
| } |
| |
| /** |
| * Determines whether the new instance of LocatorLauncher will redirect |
| * output to system logs when starting a Locator. |
| * |
| * @return a boolean value indicating if output will be redirected to system |
| * logs when starting a Locator |
| * |
| * @see #setRedirectOutput(Boolean) |
| */ |
| public Boolean getRedirectOutput() { |
| return this.redirectOutput; |
| } |
| |
| /** |
| * Determines whether redirecting of output has been enabled. |
| * |
| * @return a boolean indicating if redirecting of output was enabled. |
| */ |
| private boolean isRedirectingOutput() { |
| return Boolean.TRUE.equals(getRedirectOutput()); |
| } |
| |
| /** |
| * Sets whether the new instance of LocatorLauncher will redirect output to system logs when starting a Locator. |
| * |
| * @param redirectOutput a boolean value indicating if output will be redirected to system logs when starting |
| * a Locator. |
| * @return this Builder instance. |
| * @see #getRedirectOutput() |
| */ |
| public Builder setRedirectOutput(final Boolean redirectOutput) { |
| this.redirectOutput = redirectOutput; |
| return this; |
| } |
| |
| boolean isWorkingDirectorySpecified() { |
| return !StringUtils.isBlank(this.workingDirectory); |
| } |
| |
| /** |
| * Gets the working directory pathname in which the Locator will be ran. If the directory is unspecified, |
| * then working directory defaults to the current directory. |
| * |
| * @return a String indicating the working directory pathname. |
| * @see #setWorkingDirectory(String) |
| */ |
| public String getWorkingDirectory() { |
| return IOUtils.tryGetCanonicalPathElseGetAbsolutePath( |
| new File(StringUtils.defaultIfBlank(this.workingDirectory, DEFAULT_WORKING_DIRECTORY))); |
| } |
| |
| /** |
| * Sets the working directory in which the Locator will be ran. This also the directory in which all Locator |
| * files (such as log and license files) will be written. If the directory is unspecified, then the working |
| * directory defaults to the current directory. |
| * |
| * @param workingDirectory a String indicating the pathname of the directory in which the Locator will be ran. |
| * @return this Builder instance. |
| * @throws IllegalArgumentException wrapping a FileNotFoundException if the working directory pathname cannot be |
| * found. |
| * @see #getWorkingDirectory() |
| * @see java.io.FileNotFoundException |
| */ |
| public Builder setWorkingDirectory(final String workingDirectory) { |
| if (!new File(StringUtils.defaultIfBlank(workingDirectory, DEFAULT_WORKING_DIRECTORY)).isDirectory()) { |
| throw new IllegalArgumentException( |
| LocalizedStrings.Launcher_Builder_WORKING_DIRECTORY_NOT_FOUND_ERROR_MESSAGE.toLocalizedString("Locator"), |
| new FileNotFoundException(workingDirectory)); |
| } |
| this.workingDirectory = workingDirectory; |
| return this; |
| } |
| |
| /** |
| * Sets a GemFire Distributed System Property. |
| * |
| * @param propertyName a String indicating the name of the GemFire Distributed System property. |
| * @param propertyValue a String value for the GemFire Distributed System property. |
| * @return this Builder instance. |
| */ |
| public Builder set(final String propertyName, final String propertyValue) { |
| this.distributedSystemProperties.setProperty(propertyName, propertyValue); |
| return this; |
| } |
| |
| /** |
| * Validates the configuration settings and properties of this Builder, ensuring that all invariants have been met. |
| * Currently, the only invariant constraining the Builder is that the user must specify the member name for the |
| * Locator in the GemFire distributed system as a command-line argument, or by setting the memberName property |
| * programmatically using the corresponding setter method. If the member name is not given, then the user must |
| * have specified the pathname to the gemfire.properties file before validate is called. It is then assumed, |
| * but not further validated, that the user has specified the Locator's member name in the properties file. |
| * |
| * @throws IllegalStateException if the Builder is not properly configured. |
| */ |
| protected void validate() { |
| if (!isHelping()) { |
| validateOnStart(); |
| validateOnStatus(); |
| validateOnStop(); |
| // no validation for 'version' required |
| } |
| } |
| |
| /** |
| * Validates the arguments passed to the Builder when the 'start' command has been issued. |
| * |
| * @see com.gemstone.gemfire.distributed.LocatorLauncher.Command#START |
| */ |
| protected void validateOnStart() { |
| if (Command.START.equals(getCommand())) { |
| if (StringUtils.isBlank(getMemberName()) |
| && !isSet(System.getProperties(), DistributionConfig.GEMFIRE_PREFIX + DistributionConfig.NAME_NAME) |
| && !isSet(getDistributedSystemProperties(), DistributionConfig.NAME_NAME) |
| && !isSet(loadGemFireProperties(DistributedSystem.getPropertyFileURL()), DistributionConfig.NAME_NAME)) |
| { |
| throw new IllegalStateException(LocalizedStrings.Launcher_Builder_MEMBER_NAME_VALIDATION_ERROR_MESSAGE |
| .toLocalizedString("Locator")); |
| } |
| |
| if (!SystemUtils.CURRENT_DIRECTORY.equals(getWorkingDirectory())) { |
| throw new IllegalStateException(LocalizedStrings.Launcher_Builder_WORKING_DIRECTORY_OPTION_NOT_VALID_ERROR_MESSAGE |
| .toLocalizedString("Locator")); |
| } |
| } |
| } |
| |
| /** |
| * Validates the arguments passed to the Builder when the 'status' command has been issued. |
| * |
| * @see com.gemstone.gemfire.distributed.LocatorLauncher.Command#STATUS |
| */ |
| protected void validateOnStatus() { |
| if (Command.STATUS.equals(getCommand())) { |
| } |
| } |
| |
| /** |
| * Validates the arguments passed to the Builder when the 'stop' command has been issued. |
| * |
| * @see com.gemstone.gemfire.distributed.LocatorLauncher.Command#STOP |
| */ |
| protected void validateOnStop() { |
| if (Command.STOP.equals(getCommand())) { |
| } |
| } |
| |
| /** |
| * Validates the Builder configuration settings and then constructs an instance of the LocatorLauncher class |
| * to invoke operations on a GemFire Locator. |
| * |
| * @return a newly constructed instance of LocatorLauncher configured with this Builder. |
| * @see #validate() |
| * @see com.gemstone.gemfire.distributed.LocatorLauncher |
| */ |
| public LocatorLauncher build() { |
| validate(); |
| return new LocatorLauncher(this); |
| } |
| } |
| |
| /** |
| * An enumerated type representing valid commands to the Locator launcher. |
| */ |
| public static enum Command { |
| START("start", "bind-address", "hostname-for-clients", "port", "force", "debug", "help"), |
| STATUS("status", "bind-address", "port", "member", "pid", "dir", "debug", "help"), |
| STOP("stop", "member", "pid", "dir", "debug", "help"), |
| VERSION("version"), |
| UNSPECIFIED("unspecified"); |
| |
| private final List<String> options; |
| |
| private final String name; |
| |
| Command(final String name, final String... options) { |
| assert !StringUtils.isBlank(name) : "The name of the locator launcher command must be specified!"; |
| this.name = name; |
| this.options = (options != null ? Collections.unmodifiableList(Arrays.asList(options)) |
| : Collections.<String>emptyList()); |
| } |
| |
| /** |
| * Determines whether the specified name refers to a valid Locator launcher command, as defined by this |
| * enumerated type. |
| * |
| * @param name a String value indicating the potential name of a Locator launcher command. |
| * @return a boolean indicating whether the specified name for a Locator launcher command is valid. |
| */ |
| public static boolean isCommand(final String name) { |
| return (valueOfName(name) != null); |
| } |
| |
| /** |
| * Determines whether the given Locator launcher command has been properly specified. The command is deemed |
| * unspecified if the reference is null or the Command is UNSPECIFIED. |
| * |
| * @param command the Locator launcher command. |
| * @return a boolean value indicating whether the Locator launcher command is unspecified. |
| * @see Command#UNSPECIFIED |
| */ |
| public static boolean isUnspecified(final Command command) { |
| return (command == null || command.isUnspecified()); |
| } |
| |
| /** |
| * Looks up a Locator launcher command by name. The equality comparison on name is case-insensitive. |
| * |
| * @param name a String value indicating the name of the Locator launcher command. |
| * @return an enumerated type representing the command name or null if the no such command with the specified name |
| * exists. |
| */ |
| public static Command valueOfName(final String name) { |
| for (Command command : values()) { |
| if (command.getName().equalsIgnoreCase(name)) { |
| return command; |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Gets the name of the Locator launcher command. |
| * |
| * @return a String value indicating the name of the Locator launcher command. |
| */ |
| public String getName() { |
| return this.name; |
| } |
| |
| /** |
| * Gets a set of valid options that can be used with the Locator launcher command when used from the command-line. |
| * |
| * @return a Set of Strings indicating the names of the options available to the Locator launcher command. |
| */ |
| public List<String> getOptions() { |
| return this.options; |
| } |
| |
| /** |
| * Determines whether this Locator launcher command has the specified command-line option. |
| * |
| * @param option a String indicating the name of the command-line option to this command. |
| * @return a boolean value indicating whether this command has the specified named command-line option. |
| */ |
| public boolean hasOption(final String option) { |
| return getOptions().contains(StringUtils.toLowerCase(option)); |
| } |
| |
| /** |
| * Convenience method for determining whether this is the UNSPECIFIED Locator launcher command. |
| * |
| * @return a boolean indicating if this command is UNSPECIFIED. |
| * @see #UNSPECIFIED |
| */ |
| public boolean isUnspecified() { |
| return UNSPECIFIED.equals(this); |
| } |
| |
| /** |
| * Gets the String representation of this Locator launcher command. |
| * |
| * @return a String value representing this Locator launcher command. |
| */ |
| @Override |
| public String toString() { |
| return getName(); |
| } |
| } |
| |
| /** |
| * The LocatorState is an immutable type representing the state of the specified Locator at any given moment in time. |
| * The state of the Locator is assessed at the exact moment an instance of this class is constructed. |
| * |
| * @see com.gemstone.gemfire.distributed.AbstractLauncher.ServiceState |
| */ |
| public static final class LocatorState extends ServiceState<String> { |
| |
| /** |
| * Unmarshals a LocatorState instance from the JSON String. |
| * |
| * @return a LocatorState value unmarshalled from the JSON String. |
| */ |
| public static LocatorState fromJson(final String json) { |
| try { |
| final GfJsonObject gfJsonObject = new GfJsonObject(json); |
| |
| final Status status = Status.valueOfDescription(gfJsonObject.getString(JSON_STATUS)); |
| |
| final List<String> jvmArguments = Arrays.asList(GfJsonArray.toStringArray( |
| gfJsonObject.getJSONArray(JSON_JVMARGUMENTS))); |
| |
| return new LocatorState(status, |
| gfJsonObject.getString(JSON_STATUSMESSAGE), |
| gfJsonObject.getLong(JSON_TIMESTAMP), |
| gfJsonObject.getString(JSON_LOCATION), |
| gfJsonObject.getInt(JSON_PID), |
| gfJsonObject.getLong(JSON_UPTIME), |
| gfJsonObject.getString(JSON_WORKINGDIRECTORY), |
| jvmArguments, |
| gfJsonObject.getString(JSON_CLASSPATH), |
| gfJsonObject.getString(JSON_GEMFIREVERSION), |
| gfJsonObject.getString(JSON_JAVAVERSION), |
| gfJsonObject.getString(JSON_LOGFILE), |
| gfJsonObject.getString(JSON_HOST), |
| gfJsonObject.getString(JSON_PORT), |
| gfJsonObject.getString(JSON_MEMBERNAME)); |
| } |
| catch (GfJsonException e) { |
| throw new IllegalArgumentException("Unable to create LocatorStatus from JSON: ".concat(json)); |
| } |
| } |
| |
| public LocatorState(final LocatorLauncher launcher, final Status status) { |
| // if status is NOT_RESPONDING then this is executing inside the JVM asking for he status; pid etc will be set according to the caller's JVM instead |
| this(status, |
| launcher.statusMessage, |
| System.currentTimeMillis(), |
| launcher.getId(), |
| identifyPid(), |
| ManagementFactory.getRuntimeMXBean().getUptime(), |
| launcher.getWorkingDirectory(), |
| ManagementFactory.getRuntimeMXBean().getInputArguments(), |
| System.getProperty("java.class.path"), |
| GemFireVersion.getGemFireVersion(), |
| System.getProperty("java.version"), |
| getLogFileCanonicalPath(launcher), |
| launcher.getBindAddressAsString(), |
| launcher.getPortAsString(), |
| launcher.getMemberName()); |
| } |
| |
| public LocatorState(final LocatorLauncher launcher, final Status status, final String errorMessage) { |
| this(status, // status |
| errorMessage, // statusMessage |
| System.currentTimeMillis(), // timestamp |
| null, // locatorLocation |
| null, // pid |
| 0L, // uptime |
| launcher.getWorkingDirectory(), // workingDirectory |
| Collections.<String>emptyList(), // jvmArguments |
| null, // classpath |
| GemFireVersion.getGemFireVersion(), // gemfireVersion |
| null, // javaVersion |
| null, // logFile |
| null, // host |
| null, // port |
| null);// memberName |
| } |
| |
| private static String getBindAddressAsString(LocatorLauncher launcher) { |
| if (InternalLocator.hasLocator()) { |
| final InternalLocator locator = InternalLocator.getLocator(); |
| final InetAddress bindAddress = locator.getBindAddress(); |
| if (bindAddress != null) { |
| if (StringUtils.isBlank(bindAddress.getHostAddress())) { |
| return bindAddress.getHostAddress(); |
| } |
| } |
| } |
| return launcher.getBindAddressAsString(); |
| } |
| |
| private static String getLogFileCanonicalPath(LocatorLauncher launcher) { |
| if (InternalLocator.hasLocator()) { |
| final InternalLocator locator = InternalLocator.getLocator(); |
| final File logFile = locator.getLogFile(); |
| |
| if (logFile != null && logFile.isFile()) { |
| final String logFileCanonicalPath = IOUtils.tryGetCanonicalPathElseGetAbsolutePath(logFile); |
| if (!StringUtils.isBlank(logFileCanonicalPath)) { // this is probably not need but a safe check none-the-less. |
| return logFileCanonicalPath; |
| } |
| } |
| } |
| return launcher.getLogFileCanonicalPath(); |
| } |
| |
| private static String getPortAsString(LocatorLauncher launcher) { |
| if (InternalLocator.hasLocator()) { |
| final InternalLocator locator = InternalLocator.getLocator(); |
| final String portAsString = String.valueOf(locator.getPort()); |
| if (!StringUtils.isBlank(portAsString)) { |
| return portAsString; |
| } |
| } |
| return launcher.getPortAsString(); |
| } |
| |
| protected LocatorState(final Status status, |
| final String statusMessage, |
| final long timestamp, |
| final String locatorLocation, |
| final Integer pid, |
| final Long uptime, |
| final String workingDirectory, |
| final List<String> jvmArguments, |
| final String classpath, |
| final String gemfireVersion, |
| final String javaVersion, |
| final String logFile, |
| final String host, |
| final String port, |
| final String memberName) |
| { |
| super(status, statusMessage, timestamp, locatorLocation, pid, uptime, workingDirectory, jvmArguments, classpath, |
| gemfireVersion, javaVersion, logFile, host, port, memberName); |
| } |
| |
| private LocatorState(final LocatorLauncher launcher, final Status status, final LocatorStatusResponse response) { |
| this(status, |
| launcher.statusMessage, |
| System.currentTimeMillis(), |
| launcher.getId(), |
| response.getPid(), |
| response.getUptime(), |
| response.getWorkingDirectory(), |
| response.getJvmArgs(), |
| response.getClasspath(), |
| response.getGemFireVersion(), |
| response.getJavaVersion(), |
| response.getLogFile(), |
| response.getHost(), |
| String.valueOf(response.getPort()), |
| response.getName()); |
| } |
| |
| @Override |
| protected String getServiceName() { |
| return LOCATOR_SERVICE_NAME; |
| } |
| } |
| |
| } |