| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more contributor license |
| * agreements. See the NOTICE file distributed with this work for additional information regarding |
| * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the License. You may obtain a |
| * copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software distributed under the License |
| * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
| * or implied. See the License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| |
| package org.apache.geode.management.internal.cli.commands; |
| |
| import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; |
| import static org.apache.geode.management.internal.cli.shell.MXBeanProvider.getDistributedSystemMXBean; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.FileReader; |
| import java.io.IOException; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.Properties; |
| |
| import javax.management.MalformedObjectNameException; |
| |
| import org.apache.commons.lang3.ArrayUtils; |
| import org.apache.commons.lang3.StringUtils; |
| |
| import org.apache.geode.annotations.Immutable; |
| import org.apache.geode.distributed.internal.DistributionConfig; |
| import org.apache.geode.internal.GemFireVersion; |
| import org.apache.geode.internal.process.ProcessLauncherContext; |
| import org.apache.geode.internal.util.IOUtils; |
| import org.apache.geode.management.DistributedSystemMXBean; |
| import org.apache.geode.management.internal.cli.util.ThreePhraseGenerator; |
| |
| /** |
| * Encapsulates methods used by StartServerCommand and StartLocatorCommand and their associated |
| * tests. |
| * |
| * @see StartLocatorCommand |
| * @see StartServerCommand |
| */ |
| public class StartMemberUtils { |
| public static final String GEODE_HOME = System.getenv("GEODE_HOME"); |
| |
| private static final String JAVA_HOME = System.getProperty("java.home"); |
| static final int CMS_INITIAL_OCCUPANCY_FRACTION = 60; |
| @Immutable |
| private static final ThreePhraseGenerator nameGenerator = new ThreePhraseGenerator(); |
| |
| static final String EXTENSIONS_PATHNAME = IOUtils.appendToPath(GEODE_HOME, "extensions"); |
| static final String CORE_DEPENDENCIES_JAR_PATHNAME = |
| IOUtils.appendToPath(GEODE_HOME, "lib", "geode-dependencies.jar"); |
| static final String GEODE_JAR_PATHNAME = |
| IOUtils.appendToPath(GEODE_HOME, "lib", GemFireVersion.getGemFireJarFileName()); |
| static final long PROCESS_STREAM_READER_ASYNC_STOP_TIMEOUT_MILLIS = 5 * 1000; |
| static final int INVALID_PID = -1; |
| |
| static ThreePhraseGenerator getNameGenerator() { |
| return nameGenerator; |
| } |
| |
| static void setPropertyIfNotNull(Properties properties, String key, Object value) { |
| if (key != null && value != null) { |
| properties.setProperty(key, value.toString()); |
| } |
| } |
| |
| static String resolveWorkingDir(File userSpecifiedDir, File memberNameDir) { |
| File workingDir = |
| (userSpecifiedDir == null || userSpecifiedDir.equals(new File(""))) ? memberNameDir |
| : userSpecifiedDir; |
| String workingDirPath = IOUtils.tryGetCanonicalPathElseGetAbsolutePath(workingDir); |
| if (!workingDir.exists()) { |
| if (!workingDir.mkdirs()) { |
| throw new IllegalStateException(String.format( |
| "Could not create directory %s. Please verify directory path or user permissions.", |
| workingDirPath)); |
| } |
| } |
| return workingDirPath; |
| } |
| |
| static void addGemFirePropertyFile(final List<String> commandLine, |
| final File gemfirePropertiesFile) { |
| if (gemfirePropertiesFile != null) { |
| commandLine.add("-DgemfirePropertyFile=" + gemfirePropertiesFile.getAbsolutePath()); |
| } |
| } |
| |
| static void addGemFireSecurityPropertyFile(final List<String> commandLine, |
| final File gemfireSecurityPropertiesFile) { |
| if (gemfireSecurityPropertiesFile != null) { |
| commandLine |
| .add("-DgemfireSecurityPropertyFile=" + gemfireSecurityPropertiesFile.getAbsolutePath()); |
| } |
| } |
| |
| static void addGemFireSystemProperties(final List<String> commandLine, |
| final Properties gemfireProperties) { |
| for (final Object property : gemfireProperties.keySet()) { |
| final String propertyName = property.toString(); |
| final String propertyValue = gemfireProperties.getProperty(propertyName); |
| if (StringUtils.isNotBlank(propertyValue)) { |
| commandLine.add( |
| "-D" + DistributionConfig.GEMFIRE_PREFIX + "" + propertyName + "=" + propertyValue); |
| } |
| } |
| } |
| |
| static void addJvmArgumentsAndOptions(final List<String> commandLine, |
| final String[] jvmArgsOpts) { |
| if (jvmArgsOpts != null) { |
| commandLine.addAll(Arrays.asList(jvmArgsOpts)); |
| } |
| } |
| |
| static void addInitialHeap(final List<String> commandLine, final String initialHeap) { |
| if (StringUtils.isNotBlank(initialHeap)) { |
| commandLine.add("-Xms" + initialHeap); |
| } |
| } |
| |
| static void addMaxHeap(final List<String> commandLine, final String maxHeap) { |
| if (StringUtils.isNotBlank(maxHeap)) { |
| commandLine.add("-Xmx" + maxHeap); |
| |
| String collectorKey = "-XX:+UseConcMarkSweepGC"; |
| if (!commandLine.contains(collectorKey)) { |
| commandLine.add(collectorKey); |
| } |
| |
| String occupancyFractionKey = "-XX:CMSInitiatingOccupancyFraction="; |
| if (commandLine.stream().noneMatch(s -> s.contains(occupancyFractionKey))) { |
| commandLine.add(occupancyFractionKey + CMS_INITIAL_OCCUPANCY_FRACTION); |
| } |
| } |
| } |
| |
| static void addCurrentLocators(OfflineGfshCommand gfshCommand, final List<String> commandLine, |
| final Properties gemfireProperties) throws MalformedObjectNameException { |
| if (StringUtils.isBlank(gemfireProperties.getProperty(LOCATORS))) { |
| String currentLocators = getCurrentLocators(gfshCommand); |
| if (StringUtils.isNotBlank(currentLocators)) { |
| commandLine.add("-D".concat(ProcessLauncherContext.OVERRIDDEN_DEFAULTS_PREFIX) |
| .concat(LOCATORS).concat("=").concat(currentLocators)); |
| } |
| } |
| } |
| |
| private static String getCurrentLocators(OfflineGfshCommand gfshCommand) |
| throws MalformedObjectNameException { |
| String delimitedLocators = ""; |
| try { |
| if (gfshCommand.isConnectedAndReady()) { |
| final DistributedSystemMXBean dsMBeanProxy = getDistributedSystemMXBean(); |
| if (dsMBeanProxy != null) { |
| final String[] locators = dsMBeanProxy.listLocators(); |
| if (locators != null && locators.length > 0) { |
| final StringBuilder sb = new StringBuilder(); |
| for (int i = 0; i < locators.length; i++) { |
| if (i > 0) { |
| sb.append(","); |
| } |
| sb.append(locators[i]); |
| } |
| delimitedLocators = sb.toString(); |
| } |
| } |
| } |
| } catch (IOException e) { // thrown by getDistributedSystemMXBean |
| // leave delimitedLocators = "" |
| gfshCommand.getGfsh().logWarning("DistributedSystemMXBean is unavailable\n", e); |
| } |
| return delimitedLocators; |
| } |
| |
| public static int readPid(final File pidFile) { |
| assert pidFile != null : "The file from which to read the process ID (pid) cannot be null!"; |
| if (pidFile.isFile()) { |
| BufferedReader fileReader = null; |
| try { |
| fileReader = new BufferedReader(new FileReader(pidFile)); |
| return Integer.parseInt(fileReader.readLine()); |
| } catch (IOException | NumberFormatException ignore) { |
| } finally { |
| IOUtils.close(fileReader); |
| } |
| } |
| return INVALID_PID; |
| } |
| |
| static String getJavaPath() { |
| return new File(new File(JAVA_HOME, "bin"), "java").getPath(); |
| } |
| |
| static String getSystemClasspath() { |
| return System.getProperty("java.class.path"); |
| } |
| |
| static String toClasspath(final boolean includeSystemClasspath, String[] jarFilePathnames, |
| String... userClasspaths) { |
| // gemfire jar must absolutely be the first JAR file on the CLASSPATH!!! |
| StringBuilder classpath = new StringBuilder(getGemFireJarPath()); |
| |
| userClasspaths = (userClasspaths != null ? userClasspaths : ArrayUtils.EMPTY_STRING_ARRAY); |
| |
| // Then, include user-specified classes on CLASSPATH to enable the user to override GemFire JAR |
| // dependencies |
| // with application-specific versions; this logic/block corresponds to classes/jar-files |
| // specified with the |
| // --classpath option to the 'start locator' and 'start server commands'; also this will |
| // override any |
| // System CLASSPATH environment variable setting, which is consistent with the Java platform |
| // behavior... |
| for (String userClasspath : userClasspaths) { |
| if (StringUtils.isNotBlank(userClasspath)) { |
| classpath.append((classpath.length() == 0) ? StringUtils.EMPTY : File.pathSeparator); |
| classpath.append(userClasspath); |
| } |
| } |
| |
| // Now, include any System-specified CLASSPATH environment variable setting... |
| if (includeSystemClasspath) { |
| classpath.append(File.pathSeparator); |
| classpath.append(getSystemClasspath()); |
| } |
| |
| jarFilePathnames = |
| (jarFilePathnames != null ? jarFilePathnames : ArrayUtils.EMPTY_STRING_ARRAY); |
| |
| // And finally, include all GemFire dependencies on the CLASSPATH... |
| for (String jarFilePathname : jarFilePathnames) { |
| if (StringUtils.isNotBlank(jarFilePathname)) { |
| classpath.append((classpath.length() == 0) ? StringUtils.EMPTY : File.pathSeparator); |
| classpath.append(jarFilePathname); |
| } |
| } |
| return classpath.toString(); |
| } |
| |
| static String getGemFireJarPath() { |
| String classpath = getSystemClasspath(); |
| String gemfireJarPath = GEODE_JAR_PATHNAME; |
| for (String classpathElement : classpath.split(File.pathSeparator)) { |
| if (classpathElement.endsWith("geode-core-" + GemFireVersion.getGemFireVersion() + ".jar")) { |
| gemfireJarPath = classpathElement; |
| break; |
| } |
| } |
| return gemfireJarPath; |
| } |
| } |