http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java b/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java index 158e7bf..ae64691 100755 --- a/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java +++ b/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java @@ -12,12 +12,45 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ - package org.apache.geode.distributed; +import static org.apache.commons.lang.StringUtils.EMPTY; +import static org.apache.commons.lang.StringUtils.defaultIfBlank; +import static org.apache.commons.lang.StringUtils.isBlank; +import static org.apache.commons.lang.StringUtils.isNotBlank; +import static org.apache.commons.lang.StringUtils.lowerCase; import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE; import static org.apache.geode.distributed.ConfigurationProperties.NAME; import static org.apache.geode.distributed.ConfigurationProperties.SERVER_BIND_ADDRESS; +import static org.apache.geode.internal.lang.ObjectUtils.defaultIfNull; +import static org.apache.geode.internal.lang.StringUtils.wrap; +import static org.apache.geode.internal.lang.SystemUtils.CURRENT_DIRECTORY; +import static org.apache.geode.internal.util.IOUtils.tryGetCanonicalPathElseGetAbsolutePath; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.management.ManagementFactory; +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.ServiceLoader; +import java.util.TreeMap; +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 joptsimple.OptionException; +import joptsimple.OptionParser; +import joptsimple.OptionSet; import org.apache.geode.SystemFailure; import org.apache.geode.cache.Cache; @@ -36,10 +69,7 @@ import org.apache.geode.internal.cache.PartitionedRegion; import org.apache.geode.internal.cache.tier.sockets.CacheServerHelper; import org.apache.geode.internal.i18n.LocalizedStrings; import org.apache.geode.internal.lang.ObjectUtils; -import org.apache.geode.internal.lang.StringUtils; -import org.apache.geode.internal.lang.SystemUtils; import org.apache.geode.internal.net.SocketCreator; -import org.apache.geode.internal.process.ClusterConfigurationNotAvailableException; import org.apache.geode.internal.process.ConnectionFailedException; import org.apache.geode.internal.process.ControlNotificationHandler; import org.apache.geode.internal.process.ControllableProcess; @@ -53,7 +83,6 @@ import org.apache.geode.internal.process.ProcessLauncherContext; import org.apache.geode.internal.process.ProcessType; import org.apache.geode.internal.process.StartupStatusListener; import org.apache.geode.internal.process.UnableToControlProcessException; -import org.apache.geode.internal.util.IOUtils; import org.apache.geode.lang.AttachAPINotFoundException; import org.apache.geode.management.internal.cli.i18n.CliStrings; import org.apache.geode.management.internal.cli.json.GfJsonArray; @@ -63,30 +92,6 @@ import org.apache.geode.pdx.PdxSerializer; import org.apache.geode.security.AuthenticationRequiredException; import org.apache.geode.security.GemFireSecurityException; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.lang.management.ManagementFactory; -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.ServiceLoader; -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 joptsimple.OptionException; -import joptsimple.OptionParser; -import joptsimple.OptionSet; - /** * The ServerLauncher class is a launcher class with main method to start a GemFire Server (implying * a GemFire Cache Server process). @@ -114,6 +119,8 @@ public class ServerLauncher extends AbstractLauncher<String> { helpMap.put("assign-buckets", LocalizedStrings.ServerLauncher_SERVER_ASSIGN_BUCKETS_HELP.toLocalizedString()); helpMap.put("debug", LocalizedStrings.ServerLauncher_SERVER_DEBUG_HELP.toLocalizedString()); + helpMap.put("delete-pid-file-on-stop", + "Specifies that this Server's PID file should be deleted on stop. The default is to not delete this Server's PID file until JVM exit if --delete-pid-file-on-stop is not specified."); helpMap.put("dir", LocalizedStrings.ServerLauncher_SERVER_DIR_HELP.toLocalizedString()); helpMap.put("disable-default-server", LocalizedStrings.ServerLauncher_SERVER_DISABLE_DEFAULT_SERVER_HELP.toLocalizedString()); @@ -163,6 +170,7 @@ public class ServerLauncher extends AbstractLauncher<String> { private final AtomicBoolean starting = new AtomicBoolean(false); private final boolean assignBuckets; + private final boolean deletePidFileOnStop; private final boolean disableDefaultServer; private final boolean force; private final boolean help; @@ -215,8 +223,8 @@ public class ServerLauncher extends AbstractLauncher<String> { public static void main(final String... args) { try { new Builder(args).build().run(); - } catch (AttachAPINotFoundException e) { - System.err.println(e.getMessage()); + } catch (AttachAPINotFoundException handled) { + System.err.println(handled.getMessage()); } } @@ -243,7 +251,7 @@ public class ServerLauncher extends AbstractLauncher<String> { * @return the ServerState for this process or null. */ public static ServerState getServerState() { - return (getInstance() != null ? getInstance().status() : null); + return getInstance() != null ? getInstance().status() : null; } /** @@ -262,6 +270,7 @@ public class ServerLauncher extends AbstractLauncher<String> { this.command = builder.getCommand(); this.assignBuckets = Boolean.TRUE.equals(builder.getAssignBuckets()); setDebug(Boolean.TRUE.equals(builder.getDebug())); + this.deletePidFileOnStop = Boolean.TRUE.equals(builder.getDeletePidFileOnStop()); this.disableDefaultServer = Boolean.TRUE.equals(builder.getDisableDefaultServer()); CacheServerLauncher.setDisableDefaultServer(this.disableDefaultServer); this.distributedSystemProperties = builder.getDistributedSystemProperties(); @@ -351,7 +360,7 @@ public class ServerLauncher extends AbstractLauncher<String> { final StringBuilder buffer = new StringBuilder(ServerState.getServerBindAddressAsString(this)); final String serverPort = ServerState.getServerPortAsString(this); - if (StringUtils.isNotBlank(serverPort)) { + if (isNotBlank(serverPort)) { buffer.append("[").append(serverPort).append("]"); } @@ -436,9 +445,9 @@ public class ServerLauncher extends AbstractLauncher<String> { * * @return a String value indicating the name of this Server's log file. */ + @Override public String getLogFileName() { - return StringUtils.defaultIfBlank(getMemberName(), DEFAULT_SERVER_LOG_NAME) - .concat(DEFAULT_SERVER_LOG_EXT); + return defaultIfBlank(getMemberName(), DEFAULT_SERVER_LOG_NAME).concat(DEFAULT_SERVER_LOG_EXT); } /** @@ -450,7 +459,7 @@ public class ServerLauncher extends AbstractLauncher<String> { */ @Override public String getMemberName() { - return StringUtils.defaultIfBlank(this.memberName, super.getMemberName()); + return defaultIfBlank(this.memberName, super.getMemberName()); } /** @@ -511,11 +520,9 @@ public class ServerLauncher extends AbstractLauncher<String> { final InetAddress localhost = SocketCreator.getLocalHost(); return localhost.getCanonicalHostName(); - } catch (UnknownHostException ignore) { - // TODO determine a better value for the host on which the Server is running to return here... + } catch (UnknownHostException handled) { // NOTE returning localhost/127.0.0.1 implies the serverBindAddress was null and no IP address - // for localhost - // could be found + // for localhost could be found return "localhost/127.0.0.1"; } } @@ -542,7 +549,7 @@ public class ServerLauncher extends AbstractLauncher<String> { * @see #getServerPort() */ public String getServerPortAsString() { - return ObjectUtils.defaultIfNull(getServerPort(), getDefaultServerPort()).toString(); + return defaultIfNull(getServerPort(), getDefaultServerPort()).toString(); } /** @@ -550,6 +557,7 @@ public class ServerLauncher extends AbstractLauncher<String> { * * @return a String indicating the name for a GemFire Server. */ + @Override public String getServiceName() { return SERVER_SERVICE_NAME; } @@ -575,7 +583,7 @@ public class ServerLauncher extends AbstractLauncher<String> { * configuration meta-data. */ public boolean isSpringXmlLocationSpecified() { - return StringUtils.isNotBlank(this.springXmlLocation); + return isNotBlank(this.springXmlLocation); } /** @@ -639,14 +647,13 @@ public class ServerLauncher extends AbstractLauncher<String> { if (Command.isUnspecified(command)) { usage(); } else { - info(StringUtils.wrap(helpMap.get(command.getName()), 80, "")); + info(wrap(helpMap.get(command.getName()), 80, "")); info("\n\nusage: \n\n"); - info(StringUtils.wrap("> java ... " + getClass().getName() + ' ' + usageMap.get(command), 80, - "\t\t")); + info(wrap("> java ... " + getClass().getName() + ' ' + usageMap.get(command), 80, "\t\t")); info("\n\noptions: \n\n"); for (final String option : command.getOptions()) { - info(StringUtils.wrap("--" + option + ": " + helpMap.get(option) + '\n', 80, "\t")); + info(wrap("--" + option + ": " + helpMap.get(option) + '\n', 80, "\t")); } info("\n\n"); @@ -660,7 +667,7 @@ public class ServerLauncher extends AbstractLauncher<String> { * @see #help(org.apache.geode.distributed.ServerLauncher.Command) */ public void usage() { - info(StringUtils.wrap(helpMap.get("launcher"), 80, "\t")); + info(wrap(helpMap.get("launcher"), 80, "\t")); info("\n\nSTART\n\n"); help(Command.START); info("STATUS\n\n"); @@ -719,7 +726,7 @@ public class ServerLauncher extends AbstractLauncher<String> { * @see #start() */ private boolean isStartable() { - return (!isRunning() && this.starting.compareAndSet(false, true)); + return !isRunning() && this.starting.compareAndSet(false, true); } /** @@ -810,18 +817,12 @@ public class ServerLauncher extends AbstractLauncher<String> { LocalizedStrings.Launcher_Command_START_PID_UNAVAILABLE_ERROR_MESSAGE.toLocalizedString( getServiceName(), getId(), getWorkingDirectory(), e.getMessage()), e); - } catch (ClusterConfigurationNotAvailableException e) { - failOnStart(e); - throw e; - } catch (RuntimeException e) { + } catch (RuntimeException | Error e) { failOnStart(e); throw e; } catch (Exception e) { failOnStart(e); throw new RuntimeException(e); - } catch (Error e) { - failOnStart(e); - throw e; } finally { this.starting.set(false); } @@ -857,7 +858,7 @@ public class ServerLauncher extends AbstractLauncher<String> { this.cache = null; } if (this.process != null) { - this.process.stop(); + this.process.stop(this.deletePidFileOnStop); this.process = null; } @@ -886,7 +887,7 @@ public class ServerLauncher extends AbstractLauncher<String> { */ boolean isWaiting(final Cache cache) { // return (isRunning() && !getCache().isClosed()); - return (isRunning() && (cache.getDistributedSystem().isConnected() || cache.isReconnecting())); + return isRunning() && (cache.getDistributedSystem().isConnected() || cache.isReconnecting()); } /** @@ -901,9 +902,10 @@ public class ServerLauncher extends AbstractLauncher<String> { while (isWaiting(getCache())) { try { synchronized (this) { - wait(500l); + wait(500L); } - } catch (InterruptedException ignore) { + } catch (InterruptedException handled) { + // loop back around } } } catch (RuntimeException e) { @@ -926,7 +928,7 @@ public class ServerLauncher extends AbstractLauncher<String> { * @see #isDisableDefaultServer() */ protected boolean isDefaultServerEnabled(final Cache cache) { - return (cache.getCacheServers().isEmpty() && !isDisableDefaultServer()); + return cache.getCacheServers().isEmpty() && !isDisableDefaultServer(); } /** @@ -940,7 +942,7 @@ public class ServerLauncher extends AbstractLauncher<String> { void startCacheServer(final Cache cache) throws IOException { if (isDefaultServerEnabled(cache)) { final String serverBindAddress = - (getServerBindAddress() == null ? null : getServerBindAddress().getHostAddress()); + getServerBindAddress() == null ? null : getServerBindAddress().getHostAddress(); final Integer serverPort = getServerPort(); CacheServerLauncher.setServerBindAddress(serverBindAddress); CacheServerLauncher.setServerPort(serverPort); @@ -1024,7 +1026,7 @@ public class ServerLauncher extends AbstractLauncher<String> { * @return a boolean indicating if the Server is starting or is already running. */ protected boolean isStartingOrRunning() { - return (this.starting.get() || isRunning()); + return this.starting.get() || isRunning(); } /** @@ -1037,7 +1039,7 @@ public class ServerLauncher extends AbstractLauncher<String> { if (isStartingOrRunning()) { debug( "Getting status from the ServerLauncher instance that actually launched the GemFire Cache Server.%n"); - return new ServerState(this, (isRunning() ? Status.ONLINE : Status.STARTING)); + return new ServerState(this, isRunning() ? Status.ONLINE : Status.STARTING); } else if (isPidInProcess() && launcher != null) { return launcher.statusInProcess(); } else if (getPid() != null) { @@ -1061,7 +1063,7 @@ public class ServerLauncher extends AbstractLauncher<String> { if (isStartingOrRunning()) { debug( "Getting status from the ServerLauncher instance that actually launched the GemFire Cache Server.%n"); - return new ServerState(this, (isRunning() ? Status.ONLINE : Status.STARTING)); + return new ServerState(this, isRunning() ? Status.ONLINE : Status.STARTING); } else { return new ServerState(this, Status.NOT_RESPONDING); } @@ -1074,50 +1076,13 @@ public class ServerLauncher extends AbstractLauncher<String> { controller.checkPidSupport(); final String statusJson = controller.status(); return ServerState.fromJson(statusJson); - } - // catch (NoClassDefFoundError error) { - // if (isAttachAPINotFound(error)) { - // throw new - // AttachAPINotFoundException(LocalizedStrings.Launcher_ATTACH_API_NOT_FOUND_ERROR_MESSAGE - // .toLocalizedString(), error); - // } - // - // throw error; - // } - catch (ConnectionFailedException e) { + } catch (ConnectionFailedException handled) { // failed to attach to server JVM - return createNoResponseState(e, "Failed to connect to server with process id " + getPid()); - } catch (IOException e) { - // failed to open or read file or dir - return createNoResponseState(e, - "Failed to communicate with server with process id " + getPid()); - } - // catch (MalformedObjectNameException e) { // impossible - // // JMX object name is bad - // return createNoResponseState(e, "Failed to communicate with server 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 server with process id " + getPid()); - } - // catch (PidUnavailableException e) { - // // couldn't determine pid from within server JVM - // return createNoResponseState(e, "Failed to communicate with server with process id " + - // getPid()); - // } - catch (UnableToControlProcessException e) { - // TODO comment me - return createNoResponseState(e, - "Failed to communicate with server with process id " + getPid()); - } catch (InterruptedException e) { - // TODO comment me - return createNoResponseState(e, - "Failed to communicate with server with process id " + getPid()); - } catch (TimeoutException e) { - // TODO comment me - return createNoResponseState(e, + return createNoResponseState(handled, + "Failed to connect to server with process id " + getPid()); + } catch (IOException | MBeanInvocationFailedException | UnableToControlProcessException + | InterruptedException | TimeoutException handled) { + return createNoResponseState(handled, "Failed to communicate with server with process id " + getPid()); } } @@ -1125,9 +1090,9 @@ public class ServerLauncher extends AbstractLauncher<String> { private ServerState statusWithWorkingDirectory() { int parsedPid = 0; try { - final ProcessController controller = new ProcessControllerFactory().createProcessController( - this.controllerParameters, new File(getWorkingDirectory()), - ProcessType.SERVER.getPidFileName(), READ_PID_FILE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); + final ProcessController controller = + new ProcessControllerFactory().createProcessController(this.controllerParameters, + new File(getWorkingDirectory()), ProcessType.SERVER.getPidFileName()); parsedPid = controller.getProcessId(); // note: in-process request will go infinite loop unless we do the following @@ -1140,35 +1105,26 @@ public class ServerLauncher extends AbstractLauncher<String> { final String statusJson = controller.status(); return ServerState.fromJson(statusJson); - } catch (ConnectionFailedException e) { + } catch (ConnectionFailedException handled) { // failed to attach to server JVM - return createNoResponseState(e, "Failed to connect to server with process id " + parsedPid); - } catch (FileNotFoundException e) { + return createNoResponseState(handled, + "Failed to connect to server with process id " + parsedPid); + } catch (FileNotFoundException handled) { // could not find pid file - return createNoResponseState(e, "Failed to find process file " + return createNoResponseState(handled, "Failed to find process file " + ProcessType.SERVER.getPidFileName() + " in " + getWorkingDirectory()); - } catch (IOException e) { - // failed to open or read file or dir - return createNoResponseState(e, + } catch (IOException | MBeanInvocationFailedException | UnableToControlProcessException + | TimeoutException handled) { + return createNoResponseState(handled, "Failed to communicate with server with process id " + parsedPid); - } catch (InterruptedException e) { + } catch (InterruptedException handled) { Thread.currentThread().interrupt(); - return createNoResponseState(e, + return createNoResponseState(handled, "Interrupted while trying to communicate with server 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 server with process id " + parsedPid); - } catch (PidUnavailableException e) { + } catch (PidUnavailableException handled) { // couldn't determine pid from within server JVM - return createNoResponseState(e, "Failed to find usable process id within file " + return createNoResponseState(handled, "Failed to find usable process id within file " + ProcessType.SERVER.getPidFileName() + " in " + getWorkingDirectory()); - } catch (UnableToControlProcessException e) { - return createNoResponseState(e, - "Failed to communicate with server with process id " + parsedPid); - } catch (TimeoutException e) { - return createNoResponseState(e, - "Failed to communicate with server with process id " + parsedPid); } } @@ -1205,7 +1161,6 @@ public class ServerLauncher extends AbstractLauncher<String> { return stopWithWorkingDirectory(); } - // TODO give user detailed error message? return new ServerState(this, Status.NOT_RESPONDING); } @@ -1217,7 +1172,7 @@ public class ServerLauncher extends AbstractLauncher<String> { this.cache.close(); this.cache = null; if (this.process != null) { - this.process.stop(); + this.process.stop(this.deletePidFileOnStop); this.process = null; } INSTANCE.compareAndSet(this, null); // note: other thread may return Status.NOT_RESPONDING now @@ -1235,42 +1190,13 @@ public class ServerLauncher extends AbstractLauncher<String> { controller.checkPidSupport(); controller.stop(); return new ServerState(this, Status.STOPPED); - } - // catch (NoClassDefFoundError error) { - // if (isAttachAPINotFound(error)) { - // throw new - // AttachAPINotFoundException(LocalizedStrings.Launcher_ATTACH_API_NOT_FOUND_ERROR_MESSAGE - // .toLocalizedString(), error); - // } - // - // throw error; - // } - catch (ConnectionFailedException e) { + } catch (ConnectionFailedException handled) { // failed to attach to server JVM - return createNoResponseState(e, "Failed to connect to server with process id " + getPid()); - } catch (IOException e) { - // failed to open or read file or dir - return createNoResponseState(e, - "Failed to communicate with server with process id " + getPid()); - } - // catch (MalformedObjectNameException e) { // impossible - // // JMX object name is bad - // return createNoResponseState(e, "Failed to communicate with server 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 server with process id " + getPid()); - } - // catch (PidUnavailableException e) { - // // couldn't determine pid from within server JVM - // return createNoResponseState(e, "Failed to communicate with server with process id " + - // getPid()); - // } - catch (UnableToControlProcessException e) { - // TODO comment me - return createNoResponseState(e, + return createNoResponseState(handled, + "Failed to connect to server with process id " + getPid()); + } catch (IOException | MBeanInvocationFailedException + | UnableToControlProcessException handled) { + return createNoResponseState(handled, "Failed to communicate with server with process id " + getPid()); } } @@ -1278,9 +1204,9 @@ public class ServerLauncher extends AbstractLauncher<String> { private ServerState stopWithWorkingDirectory() { int parsedPid = 0; try { - final ProcessController controller = new ProcessControllerFactory().createProcessController( - this.controllerParameters, new File(getWorkingDirectory()), - ProcessType.SERVER.getPidFileName(), READ_PID_FILE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); + final ProcessController controller = + new ProcessControllerFactory().createProcessController(this.controllerParameters, + new File(getWorkingDirectory()), ProcessType.SERVER.getPidFileName()); parsedPid = controller.getProcessId(); // NOTE in-process request will go infinite loop unless we do the following @@ -1293,35 +1219,30 @@ public class ServerLauncher extends AbstractLauncher<String> { controller.stop(); return new ServerState(this, Status.STOPPED); - } catch (ConnectionFailedException e) { + } catch (ConnectionFailedException handled) { // failed to attach to server JVM - return createNoResponseState(e, "Failed to connect to server with process id " + parsedPid); - } catch (FileNotFoundException e) { + return createNoResponseState(handled, + "Failed to connect to server with process id " + parsedPid); + } catch (FileNotFoundException handled) { // could not find pid file - return createNoResponseState(e, "Failed to find process file " + return createNoResponseState(handled, "Failed to find process file " + ProcessType.SERVER.getPidFileName() + " in " + getWorkingDirectory()); - } catch (IOException e) { - // failed to open or read file or dir - return createNoResponseState(e, + } catch (IOException | MBeanInvocationFailedException + | UnableToControlProcessException handled) { + return createNoResponseState(handled, "Failed to communicate with server with process id " + parsedPid); - } catch (InterruptedException e) { + } catch (InterruptedException handled) { Thread.currentThread().interrupt(); - return createNoResponseState(e, + return createNoResponseState(handled, "Interrupted while trying to communicate with server 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 server with process id " + parsedPid); - } catch (PidUnavailableException e) { + } catch (PidUnavailableException handled) { // couldn't determine pid from within server JVM - return createNoResponseState(e, "Failed to find usable process id within file " - + ProcessType.SERVER.getPidFileName() + " in " + getWorkingDirectory()); - } catch (TimeoutException e) { - return createNoResponseState(e, "Timed out trying to find usable process id within file " + return createNoResponseState(handled, "Failed to find usable process id within file " + ProcessType.SERVER.getPidFileName() + " in " + getWorkingDirectory()); - } catch (UnableToControlProcessException e) { - return createNoResponseState(e, - "Failed to communicate with server with process id " + parsedPid); + } catch (TimeoutException handled) { + return createNoResponseState(handled, + "Timed out trying to find usable process id within file " + + ProcessType.SERVER.getPidFileName() + " in " + getWorkingDirectory()); } } @@ -1330,17 +1251,16 @@ public class ServerLauncher extends AbstractLauncher<String> { this.running.set(true); } - private ServerState createNoResponseState(final Exception cause, final String errorMessage) { debug(cause); return new ServerState(this, Status.NOT_RESPONDING, errorMessage); } - private Properties getOverriddenDefaults() { + private Properties getOverriddenDefaults() throws IOException { final Properties overriddenDefaults = new Properties(); overriddenDefaults.put(ProcessLauncherContext.OVERRIDDEN_DEFAULTS_PREFIX.concat(LOG_FILE), - getLogFileName()); + getLogFile().getCanonicalPath()); for (String key : System.getProperties().stringPropertyNames()) { if (key.startsWith(ProcessLauncherContext.OVERRIDDEN_DEFAULTS_PREFIX)) { @@ -1358,7 +1278,7 @@ public class ServerLauncher extends AbstractLauncher<String> { } @Override - public File getWorkingDirectory() { + public File getDirectory() { return new File(ServerLauncher.this.getWorkingDirectory()); } @@ -1376,7 +1296,7 @@ public class ServerLauncher extends AbstractLauncher<String> { public ObjectName getNamePattern() { try { return ObjectName.getInstance("GemFire:type=Member,*"); - } catch (MalformedObjectNameException | NullPointerException ignore) { + } catch (MalformedObjectNameException | NullPointerException handled) { return null; } } @@ -1421,6 +1341,7 @@ public class ServerLauncher extends AbstractLauncher<String> { private Boolean assignBuckets; private Boolean debug; + private Boolean deletePidFileOnStop; private Boolean disableDefaultServer; private Boolean force; private Boolean help; @@ -1540,6 +1461,7 @@ public class ServerLauncher extends AbstractLauncher<String> { setAssignBuckets(options.has("assign-buckets")); setDebug(options.has("debug")); + setDeletePidFileOnStop(options.has("delete-pid-file-on-stop")); setDisableDefaultServer(options.has("disable-default-server")); setForce(options.has("force")); setHelp(options.has("help")); @@ -1617,7 +1539,7 @@ public class ServerLauncher extends AbstractLauncher<String> { } } - // TODO why are these option not inside the 'if (!isHelping())' conditional block!? + // why are these option not inside the 'if (!isHelping())' conditional block? if (options.hasArgument(CliStrings.START_SERVER__CRITICAL__HEAP__PERCENTAGE)) { setCriticalHeapPercentage(Float.parseFloat(ObjectUtils @@ -1726,7 +1648,7 @@ public class ServerLauncher extends AbstractLauncher<String> { * @see org.apache.geode.distributed.ServerLauncher.Command */ public Command getCommand() { - return ObjectUtils.defaultIfNull(this.command, DEFAULT_COMMAND); + return defaultIfNull(this.command, DEFAULT_COMMAND); } /** @@ -1801,7 +1723,33 @@ public class ServerLauncher extends AbstractLauncher<String> { } /** - * Determines whether a default cache server will be added when the GemFire Server comes online. + * Determines whether the Geode Server should delete the pid file when its service stops or when + * the JVM exits. + * + * @return a boolean value indicating if the pid file should be deleted when this service stops + * or when the JVM exits. + * @see #setDeletePidFileOnStop(Boolean) + */ + public Boolean getDeletePidFileOnStop() { + return this.deletePidFileOnStop; + } + + /** + * Sets whether the Geode Server should delete the pid file when its service stops or when the + * JVM exits. + * + * @param deletePidFileOnStop a boolean value indicating if the pid file should be deleted when + * this service stops or when the JVM exits. + * @return this Builder instance. + * @see #getDeletePidFileOnStop() + */ + public Builder setDeletePidFileOnStop(final Boolean deletePidFileOnStop) { + this.deletePidFileOnStop = deletePidFileOnStop; + return this; + } + + /** + * Determines whether a default cache server will be added when the Geode Server comes online. * * @return a boolean value indicating whether to add a default cache server. * @see #setDisableDefaultServer(Boolean) @@ -1840,11 +1788,10 @@ public class ServerLauncher extends AbstractLauncher<String> { * * @return the boolean value specifying whether or not to overwrite the PID file if it already * exists. - * @see org.apache.geode.internal.process.LocalProcessLauncher * @see #setForce(Boolean) */ public Boolean getForce() { - return ObjectUtils.defaultIfNull(this.force, DEFAULT_FORCE); + return defaultIfNull(this.force, DEFAULT_FORCE); } /** @@ -1854,7 +1801,6 @@ public class ServerLauncher extends AbstractLauncher<String> { * @param force a boolean value indicating whether to overwrite the PID file when it already * exists. * @return this Builder instance. - * @see org.apache.geode.internal.process.LocalProcessLauncher * @see #getForce() */ public Builder setForce(final Boolean force) { @@ -1941,7 +1887,7 @@ public class ServerLauncher extends AbstractLauncher<String> { * @see #getMemberName() */ public Builder setMemberName(final String memberName) { - if (StringUtils.isBlank(memberName)) { + if (isBlank(memberName)) { throw new IllegalArgumentException( LocalizedStrings.Launcher_Builder_MEMBER_NAME_ERROR_MESSAGE .toLocalizedString("Server")); @@ -1983,11 +1929,11 @@ public class ServerLauncher extends AbstractLauncher<String> { } /** - * Determines whether the new instance of LocatorLauncher will redirect output to system logs - * when starting a Locator. + * Determines whether the new instance of ServerLauncher will redirect output to system logs + * when starting a Server. * * @return a boolean value indicating if output will be redirected to system logs when starting - * a Locator + * a Server * * @see #setRedirectOutput(Boolean) */ @@ -2005,11 +1951,11 @@ public class ServerLauncher extends AbstractLauncher<String> { } /** - * Sets whether the new instance of LocatorLauncher will redirect output to system logs when - * starting a Locator. + * Sets whether the new instance of ServerLauncher will redirect output to system logs when + * starting a Server. * * @param redirectOutput a boolean value indicating if output will be redirected to system logs - * when starting a Locator. + * when starting a Server. * @return this Builder instance. * @see #getRedirectOutput() */ @@ -2047,7 +1993,7 @@ public class ServerLauncher extends AbstractLauncher<String> { * @see #getServerBindAddress() */ public Builder setServerBindAddress(final String serverBindAddress) { - if (StringUtils.isBlank(serverBindAddress)) { + if (isBlank(serverBindAddress)) { this.serverBindAddress = null; return this; } @@ -2081,7 +2027,7 @@ public class ServerLauncher extends AbstractLauncher<String> { * @see #setServerPort(Integer) */ public Integer getServerPort() { - return ObjectUtils.defaultIfNull(this.serverPort, getDefaultServerPort()); + return defaultIfNull(this.serverPort, getDefaultServerPort()); } boolean isServerPortSetByUser() { @@ -2144,8 +2090,8 @@ public class ServerLauncher extends AbstractLauncher<String> { * @see #setWorkingDirectory(String) */ public String getWorkingDirectory() { - return IOUtils.tryGetCanonicalPathElseGetAbsolutePath( - new File(StringUtils.defaultIfBlank(this.workingDirectory, DEFAULT_WORKING_DIRECTORY))); + return tryGetCanonicalPathElseGetAbsolutePath( + new File(defaultIfBlank(this.workingDirectory, DEFAULT_WORKING_DIRECTORY))); } /** @@ -2162,8 +2108,7 @@ public class ServerLauncher extends AbstractLauncher<String> { * @see java.io.FileNotFoundException */ public Builder setWorkingDirectory(final String workingDirectory) { - if (!(new File(StringUtils.defaultIfBlank(workingDirectory, DEFAULT_WORKING_DIRECTORY)) - .isDirectory())) { + if (!new File(defaultIfBlank(workingDirectory, DEFAULT_WORKING_DIRECTORY)).isDirectory()) { throw new IllegalArgumentException( LocalizedStrings.Launcher_Builder_WORKING_DIRECTORY_NOT_FOUND_ERROR_MESSAGE .toLocalizedString("Server"), @@ -2242,6 +2187,10 @@ public class ServerLauncher extends AbstractLauncher<String> { } public Builder setHostNameForClients(String hostNameForClients) { + if (isBlank(hostNameForClients)) { + throw new IllegalArgumentException( + "The hostname used by clients to connect to the Server must have an argument if the --hostname-for-clients command-line option is specified!"); + } this.hostNameForClients = hostNameForClients; return this; } @@ -2412,7 +2361,7 @@ public class ServerLauncher extends AbstractLauncher<String> { */ void validateOnStart() { if (Command.START == getCommand()) { - if (StringUtils.isBlank(getMemberName()) + if (isBlank(getMemberName()) && !isSet(System.getProperties(), DistributionConfig.GEMFIRE_PREFIX + NAME) && !isSet(getDistributedSystemProperties(), NAME) && !isSet(loadGemFireProperties(DistributedSystem.getPropertyFileURL()), NAME)) { @@ -2421,7 +2370,7 @@ public class ServerLauncher extends AbstractLauncher<String> { .toLocalizedString("Server")); } - if (!SystemUtils.CURRENT_DIRECTORY.equals(getWorkingDirectory())) { + if (!CURRENT_DIRECTORY.equals(getWorkingDirectory())) { throw new IllegalStateException( LocalizedStrings.Launcher_Builder_WORKING_DIRECTORY_OPTION_NOT_VALID_ERROR_MESSAGE .toLocalizedString("Server")); @@ -2481,10 +2430,10 @@ public class ServerLauncher extends AbstractLauncher<String> { private final String name; Command(final String name, final String... options) { - assert StringUtils.isNotBlank(name) : "The name of the command must be specified!"; + assert isNotBlank(name) : "The name of the command must be specified!"; this.name = name; - this.options = (options != null ? Collections.unmodifiableList(Arrays.asList(options)) - : Collections.<String>emptyList()); + this.options = options != null ? Collections.unmodifiableList(Arrays.asList(options)) + : Collections.<String>emptyList(); } /** @@ -2496,7 +2445,7 @@ public class ServerLauncher extends AbstractLauncher<String> { * valid. */ public static boolean isCommand(final String name) { - return (valueOfName(name) != null); + return valueOfName(name) != null; } /** @@ -2508,7 +2457,7 @@ public class ServerLauncher extends AbstractLauncher<String> { * @see Command#UNSPECIFIED */ public static boolean isUnspecified(final Command command) { - return (command == null || command.isUnspecified()); + return command == null || command.isUnspecified(); } /** @@ -2539,7 +2488,7 @@ public class ServerLauncher extends AbstractLauncher<String> { } /** - * Gets a set of valid options that can be used with the Locator launcher command when used from + * Gets a set of valid options that can be used with the Server launcher command when used from * the command-line. * * @return a Set of Strings indicating the names of the options available to the Server launcher @@ -2550,14 +2499,14 @@ public class ServerLauncher extends AbstractLauncher<String> { } /** - * Determines whether this Locator launcher command has the specified command-line option. + * Determines whether this Server 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.lowerCase(option)); + return getOptions().contains(lowerCase(option)); } /** @@ -2567,7 +2516,7 @@ public class ServerLauncher extends AbstractLauncher<String> { * @see #UNSPECIFIED */ public boolean isUnspecified() { - return (this == UNSPECIFIED); + return this == UNSPECIFIED; } /** @@ -2582,8 +2531,8 @@ public class ServerLauncher extends AbstractLauncher<String> { } /** - * The ServerState 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 + * The ServerState is an immutable type representing the state of the specified Server at any + * given moment in time. The state of the Server is assessed at the exact moment an instance of * this class is constructed. * * @see org.apache.geode.distributed.AbstractLauncher.ServiceState @@ -2612,7 +2561,6 @@ public class ServerLauncher extends AbstractLauncher<String> { gfJsonObject.getString(JSON_HOST), gfJsonObject.getString(JSON_PORT), gfJsonObject.getString(JSON_MEMBERNAME)); } catch (GfJsonException e) { - // TODO: or should we return OFFLINE? throw new IllegalArgumentException("Unable to create ServerStatus from JSON: " + json, e); } } @@ -2673,9 +2621,8 @@ public class ServerLauncher extends AbstractLauncher<String> { if (system != null) { final File logFile = system.getConfig().getLogFile(); if (logFile != null && logFile.isFile()) { - final String logFileCanonicalPath = - IOUtils.tryGetCanonicalPathElseGetAbsolutePath(logFile); - if (StringUtils.isNotBlank(logFileCanonicalPath)) { + final String logFileCanonicalPath = tryGetCanonicalPathElseGetAbsolutePath(logFile); + if (isNotBlank(logFileCanonicalPath)) { return logFileCanonicalPath; } } @@ -2693,7 +2640,7 @@ public class ServerLauncher extends AbstractLauncher<String> { if (csList != null && !csList.isEmpty()) { final CacheServer cs = csList.get(0); final String serverBindAddressAsString = cs.getBindAddress(); - if (StringUtils.isNotBlank(serverBindAddressAsString)) { + if (isNotBlank(serverBindAddressAsString)) { return serverBindAddressAsString; } } @@ -2711,14 +2658,13 @@ public class ServerLauncher extends AbstractLauncher<String> { if (csList != null && !csList.isEmpty()) { final CacheServer cs = csList.get(0); final String portAsString = String.valueOf(cs.getPort()); - if (StringUtils.isNotBlank(portAsString)) { + if (isNotBlank(portAsString)) { return portAsString; } } } - return (launcher.isDisableDefaultServer() ? StringUtils.EMPTY - : launcher.getServerPortAsString()); + return launcher.isDisableDefaultServer() ? EMPTY : launcher.getServerPortAsString(); } @Override
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java index ffe3be4..4725518 100644 --- a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java +++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java @@ -69,7 +69,6 @@ import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.logging.LogWriterFactory; import org.apache.geode.internal.logging.LoggingThreadGroup; import org.apache.geode.internal.logging.log4j.LocalizedMessage; -import org.apache.geode.internal.logging.log4j.LogMarker; import org.apache.geode.internal.logging.log4j.LogWriterAppenders; import org.apache.geode.internal.net.SocketCreator; import org.apache.geode.internal.net.SocketCreatorFactory; @@ -525,6 +524,10 @@ public class InternalLocator extends Locator implements ConnectListener { return this.config; } + public InternalCache getCache() { + return myCache; + } + /** * Start peer location in this locator. If you plan on starting a distributed system later, this * method should be called first so that the distributed system can use this locator. http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java b/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java index 1c4104e..2bbe009 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java @@ -17,8 +17,25 @@ package org.apache.geode.internal.cache; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; +import java.util.Set; +import java.util.stream.Stream; + import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; +import org.apache.logging.log4j.Logger; + import org.apache.geode.UnmodifiableException; import org.apache.geode.cache.Cache; import org.apache.geode.distributed.internal.ClusterConfigurationService; @@ -29,28 +46,12 @@ import org.apache.geode.internal.ConfigSource; import org.apache.geode.internal.DeployedJar; import org.apache.geode.internal.JarDeployer; import org.apache.geode.internal.admin.remote.DistributionLocatorId; +import org.apache.geode.internal.config.ClusterConfigurationNotAvailableException; import org.apache.geode.internal.i18n.LocalizedStrings; import org.apache.geode.internal.logging.LogService; -import org.apache.geode.internal.process.ClusterConfigurationNotAvailableException; import org.apache.geode.management.internal.configuration.domain.Configuration; import org.apache.geode.management.internal.configuration.messages.ConfigurationRequest; import org.apache.geode.management.internal.configuration.messages.ConfigurationResponse; -import org.apache.logging.log4j.Logger; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Properties; -import java.util.Set; -import java.util.stream.Stream; public class ClusterConfigurationLoader { http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java b/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java index f176d22..67c8add 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java @@ -76,12 +76,9 @@ import javax.transaction.TransactionManager; import com.sun.jna.Native; import com.sun.jna.Platform; - import org.apache.commons.lang.StringUtils; import org.apache.logging.log4j.Logger; -import org.apache.geode.internal.cache.event.EventTracker; -import org.apache.geode.internal.cache.event.EventTrackerExpiryTask; -import org.apache.geode.internal.security.SecurityServiceFactory; + import org.apache.geode.CancelCriterion; import org.apache.geode.CancelException; import org.apache.geode.ForcedDisconnectException; @@ -177,6 +174,7 @@ import org.apache.geode.internal.SystemTimer; import org.apache.geode.internal.cache.control.InternalResourceManager; import org.apache.geode.internal.cache.control.InternalResourceManager.ResourceType; import org.apache.geode.internal.cache.control.ResourceAdvisor; +import org.apache.geode.internal.cache.event.EventTrackerExpiryTask; import org.apache.geode.internal.cache.execute.util.FindRestEnabledServersFunction; import org.apache.geode.internal.cache.extension.Extensible; import org.apache.geode.internal.cache.extension.ExtensionPoint; @@ -204,6 +202,7 @@ import org.apache.geode.internal.cache.xmlcache.CacheXmlParser; import org.apache.geode.internal.cache.xmlcache.CacheXmlPropertyResolver; import org.apache.geode.internal.cache.xmlcache.PropertyResolver; import org.apache.geode.internal.concurrent.ConcurrentHashSet; +import org.apache.geode.internal.config.ClusterConfigurationNotAvailableException; import org.apache.geode.internal.i18n.LocalizedStrings; import org.apache.geode.internal.jndi.JNDIInvoker; import org.apache.geode.internal.jta.TransactionManagerImpl; @@ -213,8 +212,8 @@ import org.apache.geode.internal.logging.LoggingThreadGroup; import org.apache.geode.internal.logging.log4j.LocalizedMessage; import org.apache.geode.internal.net.SocketCreator; import org.apache.geode.internal.offheap.MemoryAllocator; -import org.apache.geode.internal.process.ClusterConfigurationNotAvailableException; import org.apache.geode.internal.security.SecurityService; +import org.apache.geode.internal.security.SecurityServiceFactory; import org.apache.geode.internal.sequencelog.SequenceLoggerImpl; import org.apache.geode.internal.tcp.ConnectionTable; import org.apache.geode.internal.util.concurrent.FutureResult; http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/config/ClusterConfigurationNotAvailableException.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/config/ClusterConfigurationNotAvailableException.java b/geode-core/src/main/java/org/apache/geode/internal/config/ClusterConfigurationNotAvailableException.java new file mode 100644 index 0000000..b22f13f --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/config/ClusterConfigurationNotAvailableException.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.config; + +/** + * Exception thrown during server startup when it requests the locators for shared configuration and + * does not receive it. + */ +public class ClusterConfigurationNotAvailableException + extends org.apache.geode.internal.process.ClusterConfigurationNotAvailableException { + + private static final long serialVersionUID = 771319836094239284L; + + public ClusterConfigurationNotAvailableException(final String message) { + super(message); + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/io/TeePrintStream.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/io/TeePrintStream.java b/geode-core/src/main/java/org/apache/geode/internal/io/TeePrintStream.java index 3f36244..4b35ce5 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/io/TeePrintStream.java +++ b/geode-core/src/main/java/org/apache/geode/internal/io/TeePrintStream.java @@ -34,7 +34,7 @@ public class TeePrintStream extends PrintStream { @Override public String toString() { - final StringBuilder sb = new StringBuilder(getClass().getSimpleName()); + StringBuilder sb = new StringBuilder(getClass().getSimpleName()); sb.append("@").append(System.identityHashCode(this)).append("{"); sb.append("teeOutputStream=").append(this.teeOut); return sb.append("}").toString(); http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/AttachProcessUtils.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/AttachProcessUtils.java b/geode-core/src/main/java/org/apache/geode/internal/process/AttachProcessUtils.java index 2103785..3b5da76 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/process/AttachProcessUtils.java +++ b/geode-core/src/main/java/org/apache/geode/internal/process/AttachProcessUtils.java @@ -14,10 +14,13 @@ */ package org.apache.geode.internal.process; -import org.apache.geode.internal.process.ProcessUtils.InternalProcessUtils; +import static org.apache.commons.lang.Validate.isTrue; + import com.sun.tools.attach.VirtualMachine; import com.sun.tools.attach.VirtualMachineDescriptor; +import org.apache.geode.internal.process.ProcessUtils.InternalProcessUtils; + /** * Implementation of the {@link ProcessUtils} SPI that uses the JDK Attach API. * @@ -25,10 +28,10 @@ import com.sun.tools.attach.VirtualMachineDescriptor; */ class AttachProcessUtils implements InternalProcessUtils { - AttachProcessUtils() {} - @Override public boolean isProcessAlive(final int pid) { + isTrue(pid > 0, "Invalid pid '" + pid + "' specified"); + for (VirtualMachineDescriptor vm : VirtualMachine.list()) { if (vm.id().equals(String.valueOf(pid))) { return true; // found the vm http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/BlockingProcessStreamReader.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/BlockingProcessStreamReader.java b/geode-core/src/main/java/org/apache/geode/internal/process/BlockingProcessStreamReader.java index 9d2b497..62bded4 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/process/BlockingProcessStreamReader.java +++ b/geode-core/src/main/java/org/apache/geode/internal/process/BlockingProcessStreamReader.java @@ -14,9 +14,11 @@ */ package org.apache.geode.internal.process; +import static org.apache.commons.lang.SystemUtils.LINE_SEPARATOR; + import java.io.BufferedReader; -import java.io.IOException; import java.io.InputStreamReader; +import java.io.UncheckedIOException; import org.apache.logging.log4j.Logger; @@ -39,32 +41,11 @@ public class BlockingProcessStreamReader extends ProcessStreamReader { @Override public void run() { - final boolean isDebugEnabled = logger.isDebugEnabled(); - if (isDebugEnabled) { - logger.debug("Running {}", this); - } - BufferedReader reader = null; try { - reader = new BufferedReader(new InputStreamReader(inputStream)); - String line; - while ((line = reader.readLine()) != null) { - this.inputListener.notifyInputLine(line); - } - } catch (IOException e) { - if (isDebugEnabled) { - logger.debug("Failure reading from buffered input stream: {}", e.getMessage(), e); - } - } finally { - try { - reader.close(); - } catch (IOException e) { - if (isDebugEnabled) { - logger.debug("Failure closing buffered input stream reader: {}", e.getMessage(), e); - } - } - if (isDebugEnabled) { - logger.debug("Terminating {}", this); - } + new BufferedReader(new InputStreamReader(inputStream)).lines() + .map(line -> line + LINE_SEPARATOR).forEach(this.inputListener::notifyInputLine); + } catch (UncheckedIOException e) { + logger.debug(e); } } } http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ClusterConfigurationNotAvailableException.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ClusterConfigurationNotAvailableException.java b/geode-core/src/main/java/org/apache/geode/internal/process/ClusterConfigurationNotAvailableException.java index 7699cc4..981c460 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/process/ClusterConfigurationNotAvailableException.java +++ b/geode-core/src/main/java/org/apache/geode/internal/process/ClusterConfigurationNotAvailableException.java @@ -17,10 +17,14 @@ package org.apache.geode.internal.process; /** * Exception thrown during server startup when it requests the locators for shared configuration and * does not receive it. - * + * * @since GemFire 8.0 + * @deprecated Please use + * {@link org.apache.geode.internal.config.ClusterConfigurationNotAvailableException} + * instead. */ -public class ClusterConfigurationNotAvailableException extends RuntimeException { +@Deprecated +public class ClusterConfigurationNotAvailableException extends Exception { private static final long serialVersionUID = -3448160213553925462L; public ClusterConfigurationNotAvailableException(String message) { http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ConnectionFailedException.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ConnectionFailedException.java b/geode-core/src/main/java/org/apache/geode/internal/process/ConnectionFailedException.java index 0c04130..52d7cc7 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/process/ConnectionFailedException.java +++ b/geode-core/src/main/java/org/apache/geode/internal/process/ConnectionFailedException.java @@ -23,23 +23,23 @@ public class ConnectionFailedException extends Exception { private static final long serialVersionUID = 5622636452836752700L; /** - * Creates a new <code>ConnectionFailedException</code>. + * Creates a new {@code ConnectionFailedException}. */ public ConnectionFailedException(final String message) { super(message); } /** - * Creates a new <code>ConnectionFailedException</code> that was caused by a given exception + * Creates a new {@code ConnectionFailedException} that was caused by a given exception */ - public ConnectionFailedException(final String message, final Throwable thr) { - super(message, thr); + public ConnectionFailedException(final String message, final Throwable cause) { + super(message, cause); } /** - * Creates a new <code>ConnectionFailedException</code> that was caused by a given exception + * Creates a new {@code ConnectionFailedException} that was caused by a given exception */ - public ConnectionFailedException(final Throwable thr) { - super(thr.getMessage(), thr); + public ConnectionFailedException(final Throwable cause) { + super(cause.getMessage(), cause); } } http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ControlFileWatchdog.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ControlFileWatchdog.java b/geode-core/src/main/java/org/apache/geode/internal/process/ControlFileWatchdog.java index 0af8758..efebe70 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/process/ControlFileWatchdog.java +++ b/geode-core/src/main/java/org/apache/geode/internal/process/ControlFileWatchdog.java @@ -14,6 +14,9 @@ */ package org.apache.geode.internal.process; +import static org.apache.commons.lang.Validate.notEmpty; +import static org.apache.commons.lang.Validate.notNull; + import java.io.File; import java.io.IOException; @@ -30,74 +33,83 @@ class ControlFileWatchdog implements Runnable { private static final Logger logger = LogService.getLogger(); private static final long STOP_TIMEOUT_MILLIS = 60 * 1000; - private static final long SLEEP_MILLIS = 1000; + private static final long LOOP_INTERVAL_MILLIS = 1000; - private final File workingDir; + private final File directory; private final File file; private final ControlRequestHandler requestHandler; private final boolean stopAfterRequest; + private Thread thread; private boolean alive; - ControlFileWatchdog(final File workingDir, final String fileName, + ControlFileWatchdog(final File directory, final String fileName, final ControlRequestHandler requestHandler, final boolean stopAfterRequest) { - this.workingDir = workingDir; - this.file = new File(this.workingDir, fileName); + notNull(directory, "Invalid directory '" + directory + "' specified"); + notEmpty(fileName, "Invalid fileName '" + fileName + "' specified"); + notNull(requestHandler, "Invalid requestHandler '" + requestHandler + "' specified"); + + this.directory = directory; + this.file = new File(directory, fileName); this.requestHandler = requestHandler; this.stopAfterRequest = stopAfterRequest; } @Override public void run() { - try { // always set this.alive before stopping + try { // always set alive before stopping while (isAlive()) { - try { // handle handle exceptions - Thread.sleep(SLEEP_MILLIS); - if (this.file.exists()) { - try { // always check stopAfterRequest after main work - work(); - } finally { - if (this.stopAfterRequest) { - stopMe(); - } - } - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - // allow to loop around and check isAlive() - } catch (IOException e) { - logger.error( - "Unable to control process with {}. Please add tools.jar from JDK to classpath for improved process control.", - this.file); - // allow to loop around and check isAlive() - } + doWork(); } } finally { synchronized (this) { - this.alive = false; + alive = false; + } + } + } + + private void doWork() { + try { // handle handle exceptions + if (file.exists()) { + try { // always check stopAfterRequest after handleRequest + handleRequest(); + } finally { + if (stopAfterRequest) { + stopMe(); + } + } } + Thread.sleep(LOOP_INTERVAL_MILLIS); + } catch (InterruptedException ignored) { + Thread.currentThread().interrupt(); + // allow to loop around and check isAlive() + } catch (IOException ignored) { + logger.error( + "Unable to control process with {}. Please add tools.jar from JDK to classpath for improved process control.", + file); + // allow to loop around and check isAlive() } } - private void work() throws IOException { + private void handleRequest() throws IOException { try { // always delete file after invoking handler - this.requestHandler.handleRequest(); + requestHandler.handleRequest(); } finally { try { - this.file.delete(); + file.delete(); } catch (SecurityException e) { - logger.warn("Unable to delete {}", this.file, e); + logger.warn("Unable to delete {}", file, e); } } } void start() { synchronized (this) { - if (this.thread == null) { - this.thread = new Thread(this, createThreadName()); - this.thread.setDaemon(true); - this.alive = true; - this.thread.start(); + if (thread == null) { + thread = new Thread(this, createThreadName()); + thread.setDaemon(true); + alive = true; + thread.start(); } } } @@ -105,13 +117,13 @@ class ControlFileWatchdog implements Runnable { void stop() throws InterruptedException { Thread stopping = null; synchronized (this) { - if (this.thread != null) { - this.alive = false; - if (this.thread != Thread.currentThread()) { - this.thread.interrupt(); - stopping = this.thread; + if (thread != null) { + alive = false; + if (thread != Thread.currentThread()) { + thread.interrupt(); + stopping = thread; } - this.thread = null; + thread = null; } } if (stopping != null) { @@ -121,39 +133,39 @@ class ControlFileWatchdog implements Runnable { boolean isAlive() { synchronized (this) { - return this.alive; + return alive; } } private void stopMe() { synchronized (this) { - if (this.thread != null) { - this.alive = false; - this.thread = null; + if (thread != null) { + alive = false; + thread = null; } } } @Override public String toString() { - final StringBuilder sb = new StringBuilder(getClass().getSimpleName()); - sb.append("@").append(System.identityHashCode(this)).append("{"); - sb.append("workingDir=").append(this.workingDir); - sb.append(", file=").append(this.file); - sb.append(", alive=").append(this.alive); - sb.append(", stopAfterRequest=").append(this.stopAfterRequest); - return sb.append("}").toString(); + StringBuilder sb = new StringBuilder(getClass().getSimpleName()); + sb.append('@').append(System.identityHashCode(this)).append('{'); + sb.append("directory=").append(directory); + sb.append(", file=").append(file); + sb.append(", alive=").append(alive); // not synchronized + sb.append(", stopAfterRequest=").append(stopAfterRequest); + return sb.append('}').toString(); } private String createThreadName() { - return getClass().getSimpleName() + "@" + Integer.toHexString(hashCode()) + " monitoring " - + this.file.getName(); + return getClass().getSimpleName() + '@' + Integer.toHexString(hashCode()) + " monitoring " + + file.getName(); } /** * Defines the callback to be invoked when the control file exists. */ interface ControlRequestHandler { - public void handleRequest() throws IOException; + void handleRequest() throws IOException; } } http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ControlNotificationHandler.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ControlNotificationHandler.java b/geode-core/src/main/java/org/apache/geode/internal/process/ControlNotificationHandler.java index 246c1e8..a49d3a6 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/process/ControlNotificationHandler.java +++ b/geode-core/src/main/java/org/apache/geode/internal/process/ControlNotificationHandler.java @@ -24,7 +24,8 @@ import org.apache.geode.distributed.AbstractLauncher.ServiceState; * @since GemFire 8.0 */ public interface ControlNotificationHandler { - public void handleStop(); - public ServiceState<?> handleStatus(); + void handleStop(); + + ServiceState<?> handleStatus(); } http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ControllableProcess.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ControllableProcess.java b/geode-core/src/main/java/org/apache/geode/internal/process/ControllableProcess.java index 7641ed3..2fdd116 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/process/ControllableProcess.java +++ b/geode-core/src/main/java/org/apache/geode/internal/process/ControllableProcess.java @@ -14,6 +14,8 @@ */ package org.apache.geode.internal.process; +import static org.apache.commons.lang.Validate.notNull; + import java.io.File; import java.io.FileWriter; import java.io.IOException; @@ -25,65 +27,54 @@ import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.process.ControlFileWatchdog.ControlRequestHandler; /** - * Exists inside a process launched by ServerLauncher or LocatorLauncher. Creates the PID file and - * ControlFileWatchdogs to monitor working directory for creation of stop or status request files. + * Creates the {@link PidFile} and uses {@link ControlFileWatchdog} to monitor the directory for + * creation of stop or status request files. * * @since GemFire 8.0 */ public class ControllableProcess { private static final Logger logger = LogService.getLogger(); - private final File workingDir; - private final File pidFile; + private final File directory; private final LocalProcessLauncher launcher; private final ControlFileWatchdog stopRequestFileWatchdog; private final ControlFileWatchdog statusRequestFileWatchdog; - public ControllableProcess(final ControlNotificationHandler handler, final File workingDir, - final ProcessType processType, boolean force) + public ControllableProcess(final ControlNotificationHandler handler, final File directory, + final ProcessType processType, final boolean force) throws FileAlreadyExistsException, IOException, PidUnavailableException { - this.workingDir = workingDir; - this.pidFile = new File(this.workingDir, processType.getPidFileName()); - - deleteFiles(this.workingDir, processType); - - this.launcher = new LocalProcessLauncher(this.pidFile, force); + this(directory, processType, force, createPidFile(directory, processType), + createStopHandler(handler), createStatusHandler(handler, directory, processType)); + } - final ControlRequestHandler stopHandler = new ControlRequestHandler() { - @Override - public void handleRequest() { - handler.handleStop(); - } - }; - final ControlRequestHandler statusHandler = new ControlRequestHandler() { - @Override - public void handleRequest() throws IOException { - final ServiceState<?> state = handler.handleStatus(); - final File statusFile = new File(workingDir, processType.getStatusFileName()); - if (statusFile.exists()) { - statusFile.delete(); - } - final File statusFileTmp = new File(workingDir, processType.getStatusFileName() + ".tmp"); - if (statusFileTmp.exists()) { - statusFileTmp.delete(); - } - boolean created = statusFileTmp.createNewFile(); - assert created; - final FileWriter writer = new FileWriter(statusFileTmp); - writer.write(state.toJson()); - writer.flush(); - writer.close(); - boolean renamed = statusFileTmp.renameTo(statusFile); - assert renamed; - } - }; + private ControllableProcess(final File directory, final ProcessType processType, + final boolean force, final File pidFile, final ControlRequestHandler stopHandler, + final ControlRequestHandler statusHandler) + throws FileAlreadyExistsException, IOException, PidUnavailableException { + this(directory, processType, createLocalProcessLauncher(pidFile, force), + createStopRequestFileWatchdog(directory, processType, stopHandler), + createStatusRequestFileWatchdog(directory, processType, statusHandler)); + } - this.stopRequestFileWatchdog = new ControlFileWatchdog(workingDir, - processType.getStopRequestFileName(), stopHandler, false); - this.stopRequestFileWatchdog.start(); - this.statusRequestFileWatchdog = new ControlFileWatchdog(workingDir, - processType.getStatusRequestFileName(), statusHandler, false); - this.statusRequestFileWatchdog.start(); + ControllableProcess(final File directory, final ProcessType processType, + final LocalProcessLauncher launcher, final ControlFileWatchdog stopRequestFileWatchdog, + final ControlFileWatchdog statusRequestFileWatchdog) { + notNull(directory, "Invalid directory '" + directory + "' specified"); + notNull(processType, "Invalid processType '" + processType + "' specified"); + notNull(launcher, "Invalid launcher '" + launcher + "' specified"); + notNull(stopRequestFileWatchdog, + "Invalid stopRequestFileWatchdog '" + stopRequestFileWatchdog + "' specified"); + notNull(statusRequestFileWatchdog, + "Invalid statusRequestFileWatchdog '" + statusRequestFileWatchdog + "' specified"); + + this.directory = directory; + this.launcher = launcher; + this.stopRequestFileWatchdog = stopRequestFileWatchdog; + this.statusRequestFileWatchdog = statusRequestFileWatchdog; + + deleteFiles(directory, processType); + stopRequestFileWatchdog.start(); + statusRequestFileWatchdog.start(); } /** @@ -92,7 +83,7 @@ public class ControllableProcess { * @return the process id (PID) */ public int getPid() { - return this.launcher.getPid(); + return launcher.getPid(); } /** @@ -101,38 +92,115 @@ public class ControllableProcess { * @return the PID file */ public File getPidFile() { - return this.launcher.getPidFile(); + return launcher.getPidFile(); + } + + public File getDirectory() { + return directory; } public void stop() { + boolean interrupted = false; try { - this.statusRequestFileWatchdog.stop(); - } catch (InterruptedException e) { - logger.warn("Interrupted while stopping status handler for controllable process.", e); + interrupted = stop(statusRequestFileWatchdog); + interrupted = stop(stopRequestFileWatchdog) || interrupted; + launcher.close(); } finally { - try { - this.stopRequestFileWatchdog.stop(); - } catch (InterruptedException e) { - logger.warn("Interrupted while stopping stop handler for controllable process.", e); + if (interrupted) { + Thread.currentThread().interrupt(); } - this.launcher.close(); } } - protected File getWorkingDir() { - return this.workingDir; + public void stop(final boolean deletePidFileOnStop) { + boolean interrupted = false; + try { + interrupted = stop(statusRequestFileWatchdog); + interrupted = stop(stopRequestFileWatchdog) || interrupted; + launcher.close(deletePidFileOnStop); + } finally { + if (interrupted) { + Thread.currentThread().interrupt(); + } + } + } + + private boolean stop(final ControlFileWatchdog fileWatchdog) { + boolean interrupted = false; + try { + fileWatchdog.stop(); + } catch (InterruptedException e) { + interrupted = true; + logger.warn("Interrupted while stopping status handler for controllable process.", e); + } + return interrupted; } - private static void deleteFiles(final File workingDir, final ProcessType processType) { - deleteFile(workingDir, processType.getStatusRequestFileName()); - deleteFile(workingDir, processType.getStatusFileName()); - deleteFile(workingDir, processType.getStopRequestFileName()); + private void deleteFiles(final File directory, final ProcessType processType) { + deleteFile(directory, processType.getStatusRequestFileName()); + deleteFile(directory, processType.getStatusFileName()); + deleteFile(directory, processType.getStopRequestFileName()); } - private static void deleteFile(final File workingDir, final String fileName) { - final File file = new File(workingDir, fileName); + private void deleteFile(final File directory, final String fileName) { + File file = new File(directory, fileName); if (file.exists()) { file.delete(); } } + + private static File createPidFile(final File directory, final ProcessType processType) { + return new File(directory, processType.getPidFileName()); + } + + private static LocalProcessLauncher createLocalProcessLauncher(final File pidFile, + final boolean force) throws FileAlreadyExistsException, IOException, PidUnavailableException { + return new LocalProcessLauncher(pidFile, force); + } + + private static ControlRequestHandler createStopHandler(final ControlNotificationHandler handler) { + return handler::handleStop; + } + + private static ControlRequestHandler createStatusHandler(final ControlNotificationHandler handler, + final File directory, final ProcessType processType) { + return () -> { + ServiceState<?> state = handler.handleStatus(); + + File statusFile = new File(directory, processType.getStatusFileName()); + if (statusFile.exists()) { + boolean deleted = statusFile.delete(); + assert deleted; + } + + File statusFileTmp = new File(directory, processType.getStatusFileName() + ".tmp"); + if (statusFileTmp.exists()) { + boolean deleted = statusFileTmp.delete(); + assert deleted; + } + + boolean created = statusFileTmp.createNewFile(); + assert created; + + FileWriter writer = new FileWriter(statusFileTmp); + writer.write(state.toJson()); + writer.flush(); + writer.close(); + + boolean renamed = statusFileTmp.renameTo(statusFile); + assert renamed; + }; + } + + private static ControlFileWatchdog createStopRequestFileWatchdog(final File directory, + final ProcessType processType, final ControlRequestHandler stopHandler) { + return new ControlFileWatchdog(directory, processType.getStopRequestFileName(), stopHandler, + false); + } + + private static ControlFileWatchdog createStatusRequestFileWatchdog(final File directory, + final ProcessType processType, final ControlRequestHandler statusHandler) { + return new ControlFileWatchdog(directory, processType.getStatusRequestFileName(), statusHandler, + false); + } } http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/FileAlreadyExistsException.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/FileAlreadyExistsException.java b/geode-core/src/main/java/org/apache/geode/internal/process/FileAlreadyExistsException.java index 4bb6d57..19be21d 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/process/FileAlreadyExistsException.java +++ b/geode-core/src/main/java/org/apache/geode/internal/process/FileAlreadyExistsException.java @@ -24,23 +24,23 @@ public class FileAlreadyExistsException extends Exception { private static final long serialVersionUID = 5471082555536094256L; /** - * Creates a new <code>FileAlreadyExistsException</code>. + * Creates a new {@code FileAlreadyExistsException}. */ public FileAlreadyExistsException(final String message) { super(message); } /** - * Creates a new <code>FileAlreadyExistsException</code> that was caused by a given exception + * Creates a new {@code FileAlreadyExistsException} that was caused by a given exception */ - public FileAlreadyExistsException(final String message, final Throwable thr) { - super(message, thr); + public FileAlreadyExistsException(final String message, final Throwable cause) { + super(message, cause); } /** - * Creates a new <code>FileAlreadyExistsException</code> that was caused by a given exception + * Creates a new {@code FileAlreadyExistsException} that was caused by a given exception */ - public FileAlreadyExistsException(final Throwable thr) { - super(thr.getMessage(), thr); + public FileAlreadyExistsException(final Throwable cause) { + super(cause.getMessage(), cause); } } http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/FileControllerParameters.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/FileControllerParameters.java b/geode-core/src/main/java/org/apache/geode/internal/process/FileControllerParameters.java index 0beb9ff..d181894 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/process/FileControllerParameters.java +++ b/geode-core/src/main/java/org/apache/geode/internal/process/FileControllerParameters.java @@ -25,7 +25,8 @@ import org.apache.geode.internal.process.ProcessController.Arguments; * @since GemFire 8.0 */ interface FileControllerParameters extends Arguments { - public File getPidFile(); - public File getWorkingDirectory(); + File getPidFile(); + + File getDirectory(); }