http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemConfigImpl.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemConfigImpl.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemConfigImpl.java new file mode 100755 index 0000000..be83024 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemConfigImpl.java @@ -0,0 +1,1135 @@ +/* + * 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.admin.api.impl; + +import org.apache.geode.distributed.internal.DistributionConfig; +import org.apache.geode.distributed.internal.DistributionConfigImpl; +import org.apache.geode.internal.admin.api.AdminXmlException; +import org.apache.geode.internal.admin.api.CacheServerConfig; +import org.apache.geode.internal.admin.api.CacheVmConfig; +import org.apache.geode.internal.admin.api.DistributedSystemConfig; +import org.apache.geode.internal.admin.api.DistributionLocator; +import org.apache.geode.internal.admin.api.DistributionLocatorConfig; +import org.apache.geode.internal.i18n.LocalizedStrings; +import org.apache.geode.internal.logging.InternalLogWriter; +import org.apache.geode.internal.logging.LogConfig; +import org.apache.geode.internal.logging.LogService; +import org.apache.geode.internal.logging.LogWriterImpl; +import org.apache.logging.log4j.Logger; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.*; + +import static org.apache.geode.distributed.ConfigurationProperties.*; + +/** + * An implementation of the configuration object for an + * <code>AdminDistributedSystem</code>. After a config has been used + * to create an <code>AdminDistributedSystem</code> most of the + * configuration attributes cannot be changed. However, some + * operations (such as getting information about GemFire managers and + * distribution locators) are "passed through" to the + * <code>AdminDistributedSystem</code> associated with this + * configuration object. + * + * @since GemFire 3.5 + */ +public class DistributedSystemConfigImpl + implements DistributedSystemConfig { + + private static final Logger logger = LogService.getLogger(); + + private String entityConfigXMLFile = DEFAULT_ENTITY_CONFIG_XML_FILE; + private String systemId = DEFAULT_SYSTEM_ID; + private String mcastAddress = DEFAULT_MCAST_ADDRESS; + private int mcastPort = DEFAULT_MCAST_PORT; + private int ackWaitThreshold = DEFAULT_ACK_WAIT_THRESHOLD; + private int ackSevereAlertThreshold = DEFAULT_ACK_SEVERE_ALERT_THRESHOLD; + private String locators = DEFAULT_LOCATORS; + private String bindAddress = DEFAULT_BIND_ADDRESS; + private String serverBindAddress = DEFAULT_BIND_ADDRESS; + private String remoteCommand = DEFAULT_REMOTE_COMMAND; + private boolean disableTcp = DEFAULT_DISABLE_TCP; + private boolean enableNetworkPartitionDetection = DEFAULT_ENABLE_NETWORK_PARTITION_DETECTION; + private boolean disableAutoReconnect = DEFAULT_DISABLE_AUTO_RECONNECT; + private int memberTimeout = DEFAULT_MEMBER_TIMEOUT; + private String membershipPortRange = getMembershipPortRangeString(DEFAULT_MEMBERSHIP_PORT_RANGE); + private int tcpPort = DEFAULT_TCP_PORT; + + private String logFile = DEFAULT_LOG_FILE; + private String logLevel = DEFAULT_LOG_LEVEL; + private int logDiskSpaceLimit = DEFAULT_LOG_DISK_SPACE_LIMIT; + private int logFileSizeLimit = DEFAULT_LOG_FILE_SIZE_LIMIT; + private int refreshInterval = DEFAULT_REFRESH_INTERVAL; + private Properties gfSecurityProperties = new Properties(); + + /** + * Listeners to notify when this DistributedSystemConfig changes + */ + private Set listeners = new HashSet(); + + /** + * Configs for CacheServers that this system config is aware of + */ + private Set cacheServerConfigs = new HashSet(); + + /** + * Configs for the managed distribution locators in the distributed + * system + */ + private Set locatorConfigs = new HashSet(); + + /** + * The display name of this distributed system + */ + private String systemName = DEFAULT_NAME; + + /** + * The admin distributed system object that is configured by this + * config object. + * + * @since GemFire 4.0 */ + private AdminDistributedSystemImpl system; + + /** + * The GemFire log writer used by the distributed system + */ + private InternalLogWriter logWriter; + + /////////////////////// Static Methods /////////////////////// + + /** + * Filters out all properties that are unique to the admin + * <code>DistributedSystemConfig</code> that are not present in the + * internal <code>DistributionConfig</code>. + * + * @since GemFire 4.0 + */ + private static Properties + filterOutAdminProperties(Properties props) { + + Properties props2 = new Properties(); + for (Enumeration names = props.propertyNames(); + names.hasMoreElements(); ) { + String name = (String) names.nextElement(); + if (!(ENTITY_CONFIG_XML_FILE_NAME.equals(name) || + REFRESH_INTERVAL_NAME.equals(name) || + REMOTE_COMMAND_NAME.equals(name) + ) + ) { + String value = props.getProperty(name); + if ((name != null) && (value != null)) { + props2.setProperty(name, value); + } + } + } + + return props2; + } + + //////////////////////// Constructors //////////////////////// + + /** + * Creates a new <code>DistributedSystemConfigImpl</code> based on + * the configuration stored in a <code>DistributedSystem</code>'s + * <code>DistributionConfig</code>. + */ + public DistributedSystemConfigImpl(DistributionConfig distConfig, + String remoteCommand) { + if (distConfig == null) { + throw new IllegalArgumentException(LocalizedStrings.DistributedSystemConfigImpl_DISTRIBUTIONCONFIG_MUST_NOT_BE_NULL.toLocalizedString()); + } + + this.mcastAddress = InetAddressUtil.toString(distConfig.getMcastAddress()); + this.mcastPort = distConfig.getMcastPort(); + this.locators = distConfig.getLocators(); + this.membershipPortRange = + getMembershipPortRangeString(distConfig.getMembershipPortRange()); + + this.systemName = distConfig.getName(); + + this.sslEnabled = distConfig.getClusterSSLEnabled(); + this.sslCiphers = distConfig.getClusterSSLCiphers(); + this.sslProtocols = distConfig.getClusterSSLProtocols(); + this.sslAuthenticationRequired = distConfig.getClusterSSLRequireAuthentication(); + + this.logFile = distConfig.getLogFile().getPath(); + this.logLevel = + LogWriterImpl.levelToString(distConfig.getLogLevel()); + this.logDiskSpaceLimit = distConfig.getLogDiskSpaceLimit(); + this.logFileSizeLimit = distConfig.getLogFileSizeLimit(); + + basicSetBindAddress(distConfig.getBindAddress()); + this.tcpPort = distConfig.getTcpPort(); + + this.disableTcp = distConfig.getDisableTcp(); + + this.remoteCommand = remoteCommand; + this.serverBindAddress = distConfig.getServerBindAddress(); + this.enableNetworkPartitionDetection = distConfig.getEnableNetworkPartitionDetection(); + this.memberTimeout = distConfig.getMemberTimeout(); + this.refreshInterval = DistributedSystemConfig.DEFAULT_REFRESH_INTERVAL; + this.gfSecurityProperties = (Properties) distConfig.getSSLProperties().clone(); + } + + /** + * Zero-argument constructor to be used only by subclasses. + * + * @since GemFire 4.0 + */ + protected DistributedSystemConfigImpl() { + + } + + /** + * Creates a new <code>DistributedSystemConifgImpl</code> whose + * configuration is specified by the given <code>Properties</code> + * object. + */ + protected DistributedSystemConfigImpl(Properties props) { + this(props, false); + } + + /** + * Creates a new <code>DistributedSystemConifgImpl</code> whose configuration + * is specified by the given <code>Properties</code> object. + * + * @param props + * The configuration properties specified by the caller + * @param ignoreGemFirePropsFile + * whether to skip loading distributed system properties from + * gemfire.properties file + * + * @since GemFire 6.5 + */ + protected DistributedSystemConfigImpl(Properties props, + boolean ignoreGemFirePropsFile) { + this(new DistributionConfigImpl( + filterOutAdminProperties(props), ignoreGemFirePropsFile), + DEFAULT_REMOTE_COMMAND); + String remoteCommand = props.getProperty(REMOTE_COMMAND_NAME); + if (remoteCommand != null) { + this.remoteCommand = remoteCommand; + } + + String entityConfigXMLFile = + props.getProperty(ENTITY_CONFIG_XML_FILE_NAME); + if (entityConfigXMLFile != null) { + this.entityConfigXMLFile = entityConfigXMLFile; + } + + String refreshInterval = + props.getProperty(REFRESH_INTERVAL_NAME); + if (refreshInterval != null) { + try { + this.refreshInterval = Integer.parseInt(refreshInterval); + } catch (NumberFormatException nfEx) { + throw new IllegalArgumentException( + LocalizedStrings.DistributedSystemConfigImpl_0_IS_NOT_A_VALID_INTEGER_1.toLocalizedString(new Object[] { refreshInterval, REFRESH_INTERVAL_NAME })); + } + } + } + + ////////////////////// Instance Methods ////////////////////// + + /** + * Returns the <code>LogWriterI18n</code> to be used when administering + * the distributed system. Returns null if nothing has been provided via + * <code>setInternalLogWriter</code>. + * + * @since GemFire 4.0 + */ + public InternalLogWriter getInternalLogWriter() { + // LOG: used only for sharing between IDS, AdminDSImpl and AgentImpl -- to prevent multiple banners, etc. + synchronized (this) { + return this.logWriter; + } + } + + /** + * Sets the <code>LogWriterI18n</code> to be used when administering the + * distributed system. + */ + public void setInternalLogWriter(InternalLogWriter logWriter) { + // LOG: used only for sharing between IDS, AdminDSImpl and AgentImpl -- to prevent multiple banners, etc. + synchronized (this) { + this.logWriter = logWriter; + } + } + + public LogConfig createLogConfig() { + return new LogConfig() { + @Override + public int getLogLevel() { + return LogWriterImpl.levelNameToCode(DistributedSystemConfigImpl.this.getLogLevel()); + } + + @Override + public File getLogFile() { + return new File(DistributedSystemConfigImpl.this.getLogFile()); + } + + @Override + public int getLogFileSizeLimit() { + return DistributedSystemConfigImpl.this.getLogFileSizeLimit(); + } + + @Override + public int getLogDiskSpaceLimit() { + return DistributedSystemConfigImpl.this.getLogDiskSpaceLimit(); + } + + @Override + public String getName() { + return DistributedSystemConfigImpl.this.getSystemName(); + } + + @Override + public String toLoggerString() { + return DistributedSystemConfigImpl.this.toString(); + } + }; + } + + /** + * Marks this config object as "read only". Attempts to modify a + * config object will result in a {@link IllegalStateException} + * being thrown. + * + * @since GemFire 4.0 + */ + void setDistributedSystem(AdminDistributedSystemImpl system) { + this.system = system; + } + + /** + * Checks to see if this config object is "read only". If it is, + * then an {@link IllegalStateException} is thrown. + * + * @since GemFire 4.0 + */ + protected void checkReadOnly() { + if (this.system != null) { + throw new IllegalStateException( + LocalizedStrings.DistributedSystemConfigImpl_A_DISTRIBUTEDSYSTEMCONFIG_OBJECT_CANNOT_BE_MODIFIED_AFTER_IT_HAS_BEEN_USED_TO_CREATE_AN_ADMINDISTRIBUTEDSYSTEM + .toLocalizedString()); + } + } + + public String getEntityConfigXMLFile() { + return this.entityConfigXMLFile; + } + + public void setEntityConfigXMLFile(String xmlFile) { + checkReadOnly(); + this.entityConfigXMLFile = xmlFile; + configChanged(); + } + + /** + * Parses the XML configuration file that describes managed + * entities. + * + * @throws AdminXmlException If a problem is encountered while parsing the XML file. + */ + private void parseEntityConfigXMLFile() { + String fileName = this.entityConfigXMLFile; + File xmlFile = new File(fileName); + if (!xmlFile.exists()) { + if (DEFAULT_ENTITY_CONFIG_XML_FILE.equals(fileName)) { + // Default doesn't exist, no big deal + return; + } else { + throw new AdminXmlException(LocalizedStrings.DistributedSystemConfigImpl_ENTITY_CONFIGURATION_XML_FILE_0_DOES_NOT_EXIST.toLocalizedString(fileName)); + } + } + + try { + InputStream is = new FileInputStream(xmlFile); + try { + ManagedEntityConfigXmlParser.parse(is, this); + } finally { + is.close(); + } + } catch (IOException ex) { + throw new AdminXmlException(LocalizedStrings.DistributedSystemConfigImpl_WHILE_PARSING_0.toLocalizedString(fileName), ex); + } + } + + public String getSystemId() { + return this.systemId; + } + + public void setSystemId(String systemId) { + checkReadOnly(); + this.systemId = systemId; + configChanged(); + } + + /** + * Returns the multicast address for the system + */ + public String getMcastAddress() { + return this.mcastAddress; + } + + public void setMcastAddress(String mcastAddress) { + checkReadOnly(); + this.mcastAddress = mcastAddress; + configChanged(); + } + + /** + * Returns the multicast port for the system + */ + public int getMcastPort() { + return this.mcastPort; + } + + public void setMcastPort(int mcastPort) { + checkReadOnly(); + this.mcastPort = mcastPort; + configChanged(); + } + + public int getAckWaitThreshold() { + return this.ackWaitThreshold; + } + + public void setAckWaitThreshold(int seconds) { + checkReadOnly(); + this.ackWaitThreshold = seconds; + configChanged(); + } + + public int getAckSevereAlertThreshold() { + return this.ackSevereAlertThreshold; + } + + public void setAckSevereAlertThreshold(int seconds) { + checkReadOnly(); + this.ackSevereAlertThreshold = seconds; + configChanged(); + } + + /** + * Returns the comma-delimited list of locators for the system + */ + public String getLocators() { + return this.locators; + } + + public void setLocators(String locators) { + checkReadOnly(); + if (locators == null) { + this.locators = ""; + } else { + this.locators = locators; + } + configChanged(); + } + + /** + * Returns the value for membership-port-range + * + * @return the value for the Distributed System property membership-port-range + */ + public String getMembershipPortRange() { + return this.membershipPortRange; + } + + /** + * Sets the Distributed System property membership-port-range + * + * @param membershipPortRangeStr the value for membership-port-range given as two numbers separated + * by a minus sign. + */ + public void setMembershipPortRange(String membershipPortRangeStr) { + /* + * FIXME: Setting attributes in DistributedSystemConfig has no effect on + * DistributionConfig which is actually used for connection with DS. This is + * true for all such attributes. Should be addressed in the Admin Revamp if + * we want these 'set' calls to affect anything. Then we can use the + * validation code in DistributionConfigImpl code. + */ + checkReadOnly(); + if (membershipPortRangeStr == null) { + this.membershipPortRange = getMembershipPortRangeString(DEFAULT_MEMBERSHIP_PORT_RANGE); + } else { + try { + if (validateMembershipRange(membershipPortRangeStr)) { + this.membershipPortRange = membershipPortRangeStr; + } else { + throw new IllegalArgumentException( + LocalizedStrings.DistributedSystemConfigImpl_INVALID_VALUE_FOR_MEMBERSHIP_PORT_RANGE + .toLocalizedString(new Object[] { membershipPortRangeStr, + MEMBERSHIP_PORT_RANGE_NAME })); + } + } catch (Exception e) { + if (logger.isDebugEnabled()) { + logger.debug(e.getMessage(), e); + } + } + } + } + + public void setTcpPort(int port) { + checkReadOnly(); + this.tcpPort = port; + configChanged(); + } + + public int getTcpPort() { + return this.tcpPort; + } + + /** + * Validates the given string - which is expected in the format as two numbers + * separated by a minus sign - in to an integer array of length 2 with first + * element as lower end & second element as upper end of the range. + * + * @param membershipPortRange membership-port-range given as two numbers separated by a minus + * sign. + * @return true if the membership-port-range string is valid, false otherwise + */ + private boolean validateMembershipRange(String membershipPortRange) { + int[] range = null; + if (membershipPortRange != null && membershipPortRange.trim().length() > 0) { + String[] splitted = membershipPortRange.split("-"); + range = new int[2]; + range[0] = Integer.parseInt(splitted[0].trim()); + range[1] = Integer.parseInt(splitted[1].trim()); + //NumberFormatException if any could be thrown + + if (range[0] < 0 || range[0] >= range[1] || + range[1] < 0 || range[1] > 65535) { + range = null; + } + } + return range != null; + } + + /** + * @return the String representation of membershipPortRange with lower & upper + * limits of the port range separated by '-' e.g. 1-65535 + */ + private static String getMembershipPortRangeString(int[] membershipPortRange) { + String membershipPortRangeString = ""; + if (membershipPortRange != null && + membershipPortRange.length == 2) { + membershipPortRangeString = membershipPortRange[0] + "-" + + membershipPortRange[1]; + } + + return membershipPortRangeString; + } + + public String getBindAddress() { + return this.bindAddress; + } + + public void setBindAddress(String bindAddress) { + checkReadOnly(); + basicSetBindAddress(bindAddress); + configChanged(); + } + + public String getServerBindAddress() { + return this.serverBindAddress; + } + + public void setServerBindAddress(String bindAddress) { + checkReadOnly(); + basicSetServerBindAddress(bindAddress); + configChanged(); + } + + public boolean getDisableTcp() { + return this.disableTcp; + } + + public void setDisableTcp(boolean flag) { + checkReadOnly(); + disableTcp = flag; + configChanged(); + } + + public void setEnableNetworkPartitionDetection(boolean newValue) { + checkReadOnly(); + this.enableNetworkPartitionDetection = newValue; + configChanged(); + } + + public boolean getEnableNetworkPartitionDetection() { + return this.enableNetworkPartitionDetection; + } + + public void setDisableAutoReconnect(boolean newValue) { + checkReadOnly(); + this.disableAutoReconnect = newValue; + configChanged(); + } + + public boolean getDisableAutoReconnect() { + return this.disableAutoReconnect; + } + + public int getMemberTimeout() { + return this.memberTimeout; + } + + public void setMemberTimeout(int value) { + checkReadOnly(); + this.memberTimeout = value; + configChanged(); + } + + private void basicSetBindAddress(String bindAddress) { + if (!validateBindAddress(bindAddress)) { + throw new IllegalArgumentException(LocalizedStrings.DistributedSystemConfigImpl_INVALID_BIND_ADDRESS_0.toLocalizedString(bindAddress)); + } + this.bindAddress = bindAddress; + } + + private void basicSetServerBindAddress(String bindAddress) { + if (!validateBindAddress(bindAddress)) { + throw new IllegalArgumentException(LocalizedStrings.DistributedSystemConfigImpl_INVALID_BIND_ADDRESS_0.toLocalizedString(bindAddress)); + } + this.serverBindAddress = bindAddress; + } + + /** + * Returns the remote command setting to use for remote administration + */ + public String getRemoteCommand() { + return this.remoteCommand; + } + + /** + * Sets the remote command for this config object. This attribute + * may be modified after this config object has been used to create + * an admin distributed system. + */ + public void setRemoteCommand(String remoteCommand) { + if (!ALLOW_ALL_REMOTE_COMMANDS) { + checkRemoteCommand(remoteCommand); + } + this.remoteCommand = remoteCommand; + configChanged(); + } + + private static final boolean ALLOW_ALL_REMOTE_COMMANDS = Boolean.getBoolean(DistributionConfig.GEMFIRE_PREFIX + "admin.ALLOW_ALL_REMOTE_COMMANDS"); + private static final String[] LEGAL_REMOTE_COMMANDS = { "rsh", "ssh" }; + private static final String ILLEGAL_REMOTE_COMMAND_RSH_OR_SSH = "Allowed remote commands include \"rsh {HOST} {CMD}\" or \"ssh {HOST} {CMD}\" with valid rsh or ssh switches. Invalid: "; + + private final void checkRemoteCommand(final String remoteCommand) { + if (remoteCommand == null || remoteCommand.isEmpty()) { + return; + } + final String command = remoteCommand.toLowerCase().trim(); + if (!command.contains("{host}") || !command.contains("{cmd}")) { + throw new IllegalArgumentException(ILLEGAL_REMOTE_COMMAND_RSH_OR_SSH + remoteCommand); + } + + final StringTokenizer tokenizer = new StringTokenizer(command, " "); + final ArrayList<String> array = new ArrayList<String>(); + for (int i = 0; tokenizer.hasMoreTokens(); i++) { + String string = tokenizer.nextToken(); + if (i == 0) { + // first element must be rsh or ssh + boolean found = false; + for (int j = 0; j < LEGAL_REMOTE_COMMANDS.length; j++) { + if (string.contains(LEGAL_REMOTE_COMMANDS[j])) { + // verify command is at end of string + if (!(string.endsWith(LEGAL_REMOTE_COMMANDS[j]) || string.endsWith(LEGAL_REMOTE_COMMANDS[j] + ".exe"))) { + throw new IllegalArgumentException(ILLEGAL_REMOTE_COMMAND_RSH_OR_SSH + remoteCommand); + } + found = true; + } + } + if (!found) { + throw new IllegalArgumentException(ILLEGAL_REMOTE_COMMAND_RSH_OR_SSH + remoteCommand); + } + } else { + final boolean isSwitch = string.startsWith("-"); + final boolean isHostOrCmd = string.equals("{host}") || string.equals("{cmd}"); + + // additional elements must be switches or values-for-switches or {host} or user@{host} or {cmd} + if (!isSwitch && !isHostOrCmd) { + final String previous = (array == null || array.isEmpty()) ? null : array.get(array.size() - 1); + final boolean isValueForSwitch = previous != null && previous.startsWith("-"); + final boolean isHostWithUser = string.contains("@") && string.endsWith("{host}"); + + if (!(isValueForSwitch || isHostWithUser)) { + throw new IllegalArgumentException(ILLEGAL_REMOTE_COMMAND_RSH_OR_SSH + remoteCommand); + } + } + } + array.add(string); + } + } + + public String getSystemName() { + return this.systemName; + } + + public void setSystemName(final String systemName) { + checkReadOnly(); + this.systemName = systemName; + configChanged(); + } + + /** + * Returns an array of configurations for statically known + * CacheServers + * + * @since GemFire 4.0 + */ + public CacheServerConfig[] getCacheServerConfigs() { + return (CacheServerConfig[]) this.cacheServerConfigs.toArray( + new CacheServerConfig[this.cacheServerConfigs.size()]); + } + + public CacheVmConfig[] getCacheVmConfigs() { + return (CacheVmConfig[]) this.cacheServerConfigs.toArray(new CacheVmConfig[this.cacheServerConfigs.size()]); + } + + /** + * Creates the configuration for a CacheServer + * + * @since GemFire 4.0 + */ + public CacheServerConfig createCacheServerConfig() { + CacheServerConfig config = new CacheServerConfigImpl(); + addCacheServerConfig(config); + return config; + } + + public CacheVmConfig createCacheVmConfig() { + return (CacheVmConfig) createCacheServerConfig(); + } + + /** + * Adds the configuration for a CacheServer + * + * @since GemFire 4.0 + */ + private void addCacheServerConfig(CacheServerConfig managerConfig) { + checkReadOnly(); + + if (managerConfig == null) + return; + for (Iterator iter = this.cacheServerConfigs.iterator(); iter.hasNext(); ) { + CacheServerConfigImpl impl = (CacheServerConfigImpl) iter.next(); + if (impl.equals(managerConfig)) { + return; + } + } + this.cacheServerConfigs.add(managerConfig); + configChanged(); + } + + /** + * Removes the configuration for a CacheServer + * + * @since GemFire 4.0 + */ + public void removeCacheServerConfig(CacheServerConfig managerConfig) { + removeCacheVmConfig((CacheVmConfig) managerConfig); + } + + public void removeCacheVmConfig(CacheVmConfig managerConfig) { + checkReadOnly(); + this.cacheServerConfigs.remove(managerConfig); + configChanged(); + } + + /** + * Returns the configurations of all managed distribution locators + */ + public DistributionLocatorConfig[] getDistributionLocatorConfigs() { + if (this.system != null) { + DistributionLocator[] locators = + this.system.getDistributionLocators(); + DistributionLocatorConfig[] configs = + new DistributionLocatorConfig[locators.length]; + for (int i = 0; i < locators.length; i++) { + configs[i] = locators[i].getConfig(); + } + return configs; + + } else { + Object[] array = + new DistributionLocatorConfig[this.locatorConfigs.size()]; + return (DistributionLocatorConfig[]) this.locatorConfigs.toArray(array); + } + } + + /** + * Creates the configuration for a DistributionLocator + */ + public DistributionLocatorConfig createDistributionLocatorConfig() { + checkReadOnly(); + DistributionLocatorConfig config = new DistributionLocatorConfigImpl(); + addDistributionLocatorConfig(config); + return config; + } + + /** + * Adds the configuration for a DistributionLocator + */ + private void addDistributionLocatorConfig(DistributionLocatorConfig config) { + checkReadOnly(); + this.locatorConfigs.add(config); + configChanged(); + } + + /** + * Removes the configuration for a DistributionLocator + */ + public void removeDistributionLocatorConfig(DistributionLocatorConfig config) { + checkReadOnly(); + this.locatorConfigs.remove(config); + configChanged(); + } + + /** + * Validates the bind address. The address may be a host name or IP address, + * but it must not be empty and must be usable for creating an InetAddress. + * Cannot have a leading '/' (which InetAddress.toString() produces). + * + * @param bindAddress host name or IP address to validate + */ + public static boolean validateBindAddress(String bindAddress) { + if (bindAddress == null || bindAddress.length() == 0) + return true; + if (InetAddressUtil.validateHost(bindAddress) == null) + return false; + return true; + } + + public synchronized void configChanged() { + ConfigListener[] clients = null; + synchronized (this.listeners) { + clients = (ConfigListener[]) + listeners.toArray(new ConfigListener[this.listeners.size()]); + } + for (int i = 0; i < clients.length; i++) { + try { + clients[i].configChanged(this); + } catch (Exception e) { + logger.warn(e.getMessage(), e); + } + } + } + + /** + * Registers listener for notification of changes in this config. + */ + public void addListener(ConfigListener listener) { + synchronized (this.listeners) { + this.listeners.add(listener); + } + } + + /** + * Removes previously registered listener of this config. + */ + public void removeListener(ConfigListener listener) { + synchronized (this.listeners) { + this.listeners.remove(listener); + } + } + + // ------------------------------------------------------------------------- + // SSL support... + // ------------------------------------------------------------------------- + private boolean sslEnabled = + DistributionConfig.DEFAULT_SSL_ENABLED; + private String sslProtocols = + DistributionConfig.DEFAULT_SSL_PROTOCOLS; + private String sslCiphers = + DistributionConfig.DEFAULT_SSL_CIPHERS; + private boolean sslAuthenticationRequired = + DistributionConfig.DEFAULT_SSL_REQUIRE_AUTHENTICATION; + private Properties sslProperties = new Properties(); + + public boolean isSSLEnabled() { + return this.sslEnabled; + } + + public void setSSLEnabled(boolean enabled) { + checkReadOnly(); + this.sslEnabled = enabled; + configChanged(); + } + + public String getSSLProtocols() { + return this.sslProtocols; + } + + public void setSSLProtocols(String protocols) { + checkReadOnly(); + this.sslProtocols = protocols; + configChanged(); + } + + public String getSSLCiphers() { + return this.sslCiphers; + } + + public void setSSLCiphers(String ciphers) { + checkReadOnly(); + this.sslCiphers = ciphers; + configChanged(); + } + + public boolean isSSLAuthenticationRequired() { + return this.sslAuthenticationRequired; + } + + public void setSSLAuthenticationRequired(boolean authRequired) { + checkReadOnly(); + this.sslAuthenticationRequired = authRequired; + configChanged(); + } + + public Properties getSSLProperties() { + return this.sslProperties; + } + + public void setSSLProperties(Properties sslProperties) { + checkReadOnly(); + this.sslProperties = sslProperties; + if (this.sslProperties == null) { + this.sslProperties = new Properties(); + } + configChanged(); + } + + public void addSSLProperty(String key, String value) { + checkReadOnly(); + this.sslProperties.put(key, value); + configChanged(); + } + + public void removeSSLProperty(String key) { + checkReadOnly(); + this.sslProperties.remove(key); + configChanged(); + } + + /** + * @return the gfSecurityProperties + * @since GemFire 6.6.3 + */ + public Properties getGfSecurityProperties() { + return gfSecurityProperties; + } + + public String getLogFile() { + return this.logFile; + } + + public void setLogFile(String logFile) { + checkReadOnly(); + this.logFile = logFile; + configChanged(); + } + + public String getLogLevel() { + return this.logLevel; + } + + public void setLogLevel(String logLevel) { + checkReadOnly(); + this.logLevel = logLevel; + configChanged(); + } + + public int getLogDiskSpaceLimit() { + return this.logDiskSpaceLimit; + } + + public void setLogDiskSpaceLimit(int limit) { + checkReadOnly(); + this.logDiskSpaceLimit = limit; + configChanged(); + } + + public int getLogFileSizeLimit() { + return this.logFileSizeLimit; + } + + public void setLogFileSizeLimit(int limit) { + checkReadOnly(); + this.logFileSizeLimit = limit; + configChanged(); + } + + /** + * Returns the refreshInterval in seconds + */ + public int getRefreshInterval() { + return this.refreshInterval; + } + + /** + * Sets the refreshInterval in seconds + */ + public void setRefreshInterval(int timeInSecs) { + checkReadOnly(); + this.refreshInterval = timeInSecs; + configChanged(); + } + + /** + * Makes sure that the mcast port and locators are correct and + * consistent. + * + * @throws IllegalArgumentException If configuration is not valid + */ + public void validate() { + if (this.getMcastPort() < MIN_MCAST_PORT || + this.getMcastPort() > MAX_MCAST_PORT) { + throw new IllegalArgumentException(LocalizedStrings.DistributedSystemConfigImpl_MCASTPORT_MUST_BE_AN_INTEGER_INCLUSIVELY_BETWEEN_0_AND_1 + .toLocalizedString(new Object[] { Integer.valueOf(MIN_MCAST_PORT), Integer.valueOf(MAX_MCAST_PORT) })); + } + + // disabled in 5.1 - multicast and locators can be used together + //if (!DEFAULT_LOCATORS.equals(this.getLocators()) && + // this.mcastPort > 0) { + // throw new IllegalArgumentException( + // "mcastPort must be zero when locators are specified"); + //} + + LogWriterImpl.levelNameToCode(this.logLevel); + + if (this.logFileSizeLimit < MIN_LOG_FILE_SIZE_LIMIT || + this.logFileSizeLimit > MAX_LOG_FILE_SIZE_LIMIT) { + throw new IllegalArgumentException(LocalizedStrings.DistributedSystemConfigImpl_LOGFILESIZELIMIT_MUST_BE_AN_INTEGER_BETWEEN_0_AND_1 + .toLocalizedString(new Object[] { Integer.valueOf(MIN_LOG_FILE_SIZE_LIMIT), Integer.valueOf(MAX_LOG_FILE_SIZE_LIMIT) })); + } + + if (this.logDiskSpaceLimit < MIN_LOG_DISK_SPACE_LIMIT || + this.logDiskSpaceLimit > MAX_LOG_DISK_SPACE_LIMIT) { + throw new IllegalArgumentException(LocalizedStrings.DistributedSystemConfigImpl_LOGDISKSPACELIMIT_MUST_BE_AN_INTEGER_BETWEEN_0_AND_1 + .toLocalizedString(new Object[] { Integer.valueOf(MIN_LOG_DISK_SPACE_LIMIT), Integer.valueOf(MAX_LOG_DISK_SPACE_LIMIT) })); + } + + parseEntityConfigXMLFile(); + } + + /** + * Makes a deep copy of this config object. + */ + @Override + public Object clone() throws CloneNotSupportedException { + DistributedSystemConfigImpl other = + (DistributedSystemConfigImpl) super.clone(); + other.system = null; + other.cacheServerConfigs = new HashSet(); + other.locatorConfigs = new HashSet(); + + DistributionLocatorConfig[] myLocators = + this.getDistributionLocatorConfigs(); + for (int i = 0; i < myLocators.length; i++) { + DistributionLocatorConfig locator = myLocators[i]; + other.addDistributionLocatorConfig((DistributionLocatorConfig) locator.clone()); + } + + CacheServerConfig[] myCacheServers = this.getCacheServerConfigs(); + for (int i = 0; i < myCacheServers.length; i++) { + CacheServerConfig locator = myCacheServers[i]; + other.addCacheServerConfig((CacheServerConfig) locator.clone()); + } + + return other; + } + + @Override + public String toString() { + StringBuffer buf = new StringBuffer(1000); + String lf = System.getProperty("line.separator"); + if (lf == null) + lf = ","; + + buf.append("DistributedSystemConfig("); + buf.append(lf); + buf.append(" system-name="); + buf.append(String.valueOf(this.systemName)); + buf.append(lf); + buf.append(" " + MCAST_ADDRESS + "="); + buf.append(String.valueOf(this.mcastAddress)); + buf.append(lf); + buf.append(" " + MCAST_PORT + "="); + buf.append(String.valueOf(this.mcastPort)); + buf.append(lf); + buf.append(" " + LOCATORS + "="); + buf.append(String.valueOf(this.locators)); + buf.append(lf); + buf.append(" " + MEMBERSHIP_PORT_RANGE_NAME + "="); + buf.append(getMembershipPortRange()); + buf.append(lf); + buf.append(" " + BIND_ADDRESS + "="); + buf.append(String.valueOf(this.bindAddress)); + buf.append(lf); + buf.append(" " + TCP_PORT + "=" + this.tcpPort); + buf.append(lf); + buf.append(" " + DISABLE_TCP + "="); + buf.append(String.valueOf(this.disableTcp)); + buf.append(lf); + buf.append(" " + DISABLE_AUTO_RECONNECT + "="); + buf.append(String.valueOf(this.disableAutoReconnect)); + buf.append(lf); + buf.append(" " + REMOTE_COMMAND_NAME + "="); + buf.append(String.valueOf(this.remoteCommand)); + buf.append(lf); + buf.append(" " + CLUSTER_SSL_ENABLED + "="); + buf.append(String.valueOf(this.sslEnabled)); + buf.append(lf); + buf.append(" " + CLUSTER_SSL_CIPHERS + "="); + buf.append(String.valueOf(this.sslCiphers)); + buf.append(lf); + buf.append(" " + CLUSTER_SSL_PROTOCOLS + "="); + buf.append(String.valueOf(this.sslProtocols)); + buf.append(lf); + buf.append(" " + CLUSTER_SSL_REQUIRE_AUTHENTICATION + "="); + buf.append(String.valueOf(this.sslAuthenticationRequired)); + buf.append(lf); + buf.append(" " + LOG_FILE_NAME + "="); + buf.append(String.valueOf(this.logFile)); + buf.append(lf); + buf.append(" " + LOG_LEVEL_NAME + "="); + buf.append(String.valueOf(this.logLevel)); + buf.append(lf); + buf.append(" " + LOG_DISK_SPACE_LIMIT_NAME + "="); + buf.append(String.valueOf(this.logDiskSpaceLimit)); + buf.append(lf); + buf.append(" " + LOG_FILE_SIZE_LIMIT_NAME + "="); + buf.append(String.valueOf(this.logFileSizeLimit)); + buf.append(lf); + buf.append(" " + REFRESH_INTERVAL_NAME + "="); + buf.append(String.valueOf(this.refreshInterval)); + buf.append(")"); + return buf.toString(); + } +} +
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthConfigImpl.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthConfigImpl.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthConfigImpl.java new file mode 100644 index 0000000..9d3f5e6 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthConfigImpl.java @@ -0,0 +1,58 @@ +/* + * 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.admin.api.impl; + +import org.apache.geode.internal.admin.api.DistributedSystemHealthConfig; + +/** + * The implementation of <code>DistributedSystemHealthConfig</code>. + * Note that because it never leaves the management VM, it is not + * <code>Serializable</code> and is not part of the {@link + * GemFireHealthConfigImpl} class hierarchy. + * + * + * @since GemFire 3.5 + */ +public class DistributedSystemHealthConfigImpl + implements DistributedSystemHealthConfig { + + /** The maximum number of application members that can + * unexceptedly leave a healthy the distributed system. */ + private long maxDepartedApplications = + DEFAULT_MAX_DEPARTED_APPLICATIONS; + + ////////////////////// Constructors ////////////////////// + + /** + * Creates a new <code>DistributedSystemHealthConfigImpl</code> with + * the default configuration. + */ + protected DistributedSystemHealthConfigImpl() { + + } + + ///////////////////// Instance Methods ///////////////////// + + public long getMaxDepartedApplications() { + return this.maxDepartedApplications; + } + + public void setMaxDepartedApplications(long maxDepartedApplications) + { + this.maxDepartedApplications = maxDepartedApplications; + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthEvaluator.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthEvaluator.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthEvaluator.java new file mode 100644 index 0000000..ac47ddc --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthEvaluator.java @@ -0,0 +1,172 @@ +/* + * 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.admin.api.impl; + +import org.apache.geode.internal.admin.api.DistributedSystemHealthConfig; +import org.apache.geode.distributed.internal.DM; +import org.apache.geode.distributed.internal.DistributionConfig; +import org.apache.geode.distributed.internal.DistributionManager; +import org.apache.geode.distributed.internal.MembershipListener; +import org.apache.geode.distributed.internal.membership.InternalDistributedMember; +import org.apache.geode.internal.i18n.LocalizedStrings; + +import java.util.List; +import java.util.Set; + +/** + * Contains the logic for evaluating the health of an entire GemFire + * distributed system according to the thresholds provided in a {@link + * DistributedSystemHealthConfig}. + * + * <P> + * + * Note that unlike other evaluators, the + * <code>DistributedSystemHealthEvaluator</code> resides in the + * "administrator" VM and not in the member VMs. This is because + * there only needs to be one + * <code>DistributedSystemHealthEvaluator</code> per distributed + * system. + * + * + * @since GemFire 3.5 + * */ +class DistributedSystemHealthEvaluator + extends AbstractHealthEvaluator implements MembershipListener { + + /** The config from which we get the evaluation criteria */ + private DistributedSystemHealthConfig config; + + /** The distribution manager with which this MembershipListener is + * registered */ + private DM dm; + + /** The description of the distributed system being evaluated */ + private String description; + + /** The number of application members that have unexpectedly left + * since the previous evaluation */ + private int crashedApplications; + + /////////////////////// Constructors /////////////////////// + + /** + * Creates a new <code>DistributedSystemHealthEvaluator</code> + */ + DistributedSystemHealthEvaluator(DistributedSystemHealthConfig config, + DM dm) { + super(null, dm); + + this.config = config; + this.dm = dm; + this.dm.addMembershipListener(this); + + StringBuffer sb = new StringBuffer(); + sb.append("Distributed System "); + + String desc = null; + if (dm instanceof DistributionManager) { + desc = + ((DistributionManager) dm).getDistributionConfigDescription(); + } + + if (desc != null) { + sb.append(desc); + + } else { + DistributionConfig dsc = dm.getSystem().getConfig(); + String locators = dsc.getLocators(); + if (locators == null || locators.equals("")) { + sb.append("using multicast "); + sb.append(dsc.getMcastAddress()); + sb.append(":"); + sb.append(dsc.getMcastPort()); + + } else { + sb.append("using locators "); + sb.append(locators); + } + } + + this.description = sb.toString(); + } + + //////////////////// Instance Methods //////////////////// + + @Override + protected String getDescription() { + return this.description; + } + + /** + * Checks to make sure that the number of application members of + * the distributed system that have left unexpected since the last + * evaluation is less than the {@linkplain + * DistributedSystemHealthConfig#getMaxDepartedApplications + * threshold}. If not, the status is "poor" health. + */ + void checkDepartedApplications(List status) { + synchronized (this) { + long threshold = this.config.getMaxDepartedApplications(); + if (this.crashedApplications > threshold) { + String s = LocalizedStrings.DistributedSystemHealth_THE_NUMBER_OF_APPLICATIONS_THAT_HAVE_LEFT_THE_DISTRIBUTED_SYSTEM_0_EXCEEDS_THE_THRESHOLD_1.toLocalizedString(new Object[] { Long.valueOf(this.crashedApplications), Long.valueOf(threshold)}); + status.add(poorHealth(s)); + } + this.crashedApplications = 0; + } + } + + @Override + protected void check(List status) { + checkDepartedApplications(status); + } + + @Override + void close() { + this.dm.removeMembershipListener(this); + } + + public void memberJoined(InternalDistributedMember id) { + + } + + /** + * Keeps track of which members depart unexpectedly + */ + public void memberDeparted(InternalDistributedMember id, boolean crashed) { + if (!crashed) + return; + synchronized (this) { + int kind = id.getVmKind(); + switch (kind) { + case DistributionManager.LOCATOR_DM_TYPE: + case DistributionManager.NORMAL_DM_TYPE: + this.crashedApplications++; + break; + default: + break; + } + } // synchronized + } + + public void quorumLost(Set<InternalDistributedMember> failures, List<InternalDistributedMember> remaining) { + } + + public void memberSuspect(InternalDistributedMember id, + InternalDistributedMember whoSuspected, String reason) { + } + +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthMonitor.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthMonitor.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthMonitor.java new file mode 100644 index 0000000..3ce8bcc --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthMonitor.java @@ -0,0 +1,436 @@ +/* + * 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.admin.api.impl; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; + +import org.apache.logging.log4j.Logger; + +import org.apache.geode.SystemFailure; +import org.apache.geode.internal.admin.api.AdminException; +import org.apache.geode.internal.admin.api.GemFireHealth; +import org.apache.geode.internal.admin.api.GemFireHealthConfig; +import org.apache.geode.internal.admin.api.GemFireMemberStatus; +import org.apache.geode.internal.admin.api.RegionSubRegionSnapshot; +import org.apache.geode.cache.Region; +import org.apache.geode.cache.RegionAttributes; +import org.apache.geode.distributed.internal.membership.InternalDistributedMember; +import org.apache.geode.internal.Assert; +import org.apache.geode.internal.Config; +import org.apache.geode.internal.net.SocketCreator; +import org.apache.geode.internal.admin.AdminBridgeServer; +import org.apache.geode.internal.admin.CacheInfo; +import org.apache.geode.internal.admin.DLockInfo; +import org.apache.geode.internal.admin.GemFireVM; +import org.apache.geode.internal.admin.GfManagerAgent; +import org.apache.geode.internal.admin.HealthListener; +import org.apache.geode.internal.admin.Stat; +import org.apache.geode.internal.admin.StatAlertDefinition; +import org.apache.geode.internal.admin.StatListener; +import org.apache.geode.internal.admin.StatResource; +import org.apache.geode.internal.i18n.LocalizedStrings; +import org.apache.geode.internal.logging.LogService; +import org.apache.geode.internal.logging.LoggingThreadGroup; +import org.apache.geode.internal.logging.log4j.LocalizedMessage; + +/** + * A thread that monitors the health of the distributed system. It is + * kind of like a {@link + * org.apache.geode.distributed.internal.HealthMonitorImpl}. In + * order to get it to place nice with the rest of the health + * monitoring APIs, this class pretends that it is a + * <code>GemFireVM</code>. Kind of hokey, but it beats a bunch of + * special-case code. + * + * + * @since GemFire 3.5 + * */ +class DistributedSystemHealthMonitor implements Runnable, GemFireVM { + + private static final Logger logger = LogService.getLogger(); + + /** Evaluates the health of the distributed system */ + private DistributedSystemHealthEvaluator eval; + + /** Notified when the health of the distributed system changes */ + private GemFireHealthImpl healthImpl; + + /** The number of seconds between health checks */ + private int interval; + + /** The thread in which the monitoring occurs */ + private Thread thread; + + /** Has this monitor been asked to stop? */ + private volatile boolean stopRequested = false; + + /** The health of the distributed system the last time we checked. */ + private GemFireHealth.Health prevHealth = GemFireHealth.GOOD_HEALTH; + + /** The most recent <code>OKAY_HEALTH</code> diagnoses of the + * GemFire system */ + private List okayDiagnoses; + + /** The most recent <code>POOR_HEALTH</code> diagnoses of the + * GemFire system */ + private List poorDiagnoses; + + ////////////////////// Constructors ////////////////////// + + /** + * Creates a new <code>DistributedSystemHealthMonitor</code> that + * evaluates the health of the distributed system against the given + * thresholds once every <code>interval</code> seconds. + * + * @param eval + * Used to evaluate the health of the distributed system + * @param healthImpl + * Receives callbacks when the health of the distributed + * system changes + * @param interval + * How often the health is checked + */ + DistributedSystemHealthMonitor(DistributedSystemHealthEvaluator eval, + GemFireHealthImpl healthImpl, + int interval) { + this.eval = eval; + this.healthImpl = healthImpl; + this.interval = interval; + this.okayDiagnoses = new ArrayList(); + this.poorDiagnoses = new ArrayList(); + + ThreadGroup group = + LoggingThreadGroup.createThreadGroup(LocalizedStrings.DistributedSystemHealthMonitor_HEALTH_MONITORS.toLocalizedString(), logger); + String name = LocalizedStrings.DistributedSystemHealthMonitor_HEALTH_MONITOR_FOR_0.toLocalizedString(eval.getDescription()); + this.thread = new Thread(group, this, name); + this.thread.setDaemon(true); + } + + /** + * Does the work of monitoring the health of the distributed + * system. + */ + public void run() { + if (logger.isDebugEnabled()) { + logger.debug("Monitoring health of {} every {} seconds", this.eval.getDescription(), interval); + } + + while (!this.stopRequested) { + SystemFailure.checkFailure(); + try { + Thread.sleep(interval * 1000); + List status = new ArrayList(); + eval.evaluate(status); + + GemFireHealth.Health overallHealth = GemFireHealth.GOOD_HEALTH; + this.okayDiagnoses.clear(); + this.poorDiagnoses.clear(); + + for (Iterator iter = status.iterator(); iter.hasNext(); ) { + AbstractHealthEvaluator.HealthStatus health = + (AbstractHealthEvaluator.HealthStatus) iter.next(); + if (overallHealth == GemFireHealth.GOOD_HEALTH) { + if ((health.getHealthCode() != GemFireHealth.GOOD_HEALTH)) { + overallHealth = health.getHealthCode(); + } + + } else if (overallHealth == GemFireHealth.OKAY_HEALTH) { + if (health.getHealthCode() == GemFireHealth.POOR_HEALTH) { + overallHealth = GemFireHealth.POOR_HEALTH; + } + } + + GemFireHealth.Health healthCode = health.getHealthCode(); + if (healthCode == GemFireHealth.OKAY_HEALTH) { + this.okayDiagnoses.add(health.getDiagnosis()); + + } else if (healthCode == GemFireHealth.POOR_HEALTH) { + this.poorDiagnoses.add(health.getDiagnosis()); + break; + } + } + + if (overallHealth != prevHealth) { + healthImpl.healthChanged(this, overallHealth); + this.prevHealth = overallHealth; + } + + } catch (InterruptedException ex) { + // We're all done + // No need to reset the interrupted flag, since we're going to exit. + break; + } + } + + eval.close(); + if (logger.isDebugEnabled()) { + logger.debug("Stopped checking for distributed system health"); + } + } + + /** + * Starts this <code>DistributedSystemHealthMonitor</code> + */ + void start(){ + this.thread.start(); + } + + /** + * Stops this <code>DistributedSystemHealthMonitor</code> + */ + void stop() { + if (this.thread.isAlive()) { + this.stopRequested = true; + this.thread.interrupt(); + this.healthImpl.nodeLeft(null, this); + + try { + this.thread.join(); + } + catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + logger.warn(LocalizedMessage.create(LocalizedStrings.DistributedSystemHealthMonitor_INTERRUPTED_WHILE_STOPPING_HEALTH_MONITOR_THREAD), ex); + } + } + } + + ////////////////////// GemFireVM Methods ////////////////////// + + public java.net.InetAddress getHost() { + try { + return SocketCreator.getLocalHost(); + + } catch (Exception ex) { + throw new org.apache.geode.InternalGemFireException(LocalizedStrings.DistributedSystemHealthMonitor_COULD_NOT_GET_LOCALHOST.toLocalizedString()); + } + } + + public String getName() { +// return getId().toString(); + throw new UnsupportedOperationException("Not a real GemFireVM"); + } + + public java.io.File getWorkingDirectory() { + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public java.io.File getGemFireDir() { + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public java.util.Date getBirthDate() { + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public Properties getLicenseInfo(){ + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public GemFireMemberStatus getSnapshot() { + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public RegionSubRegionSnapshot getRegionSnapshot() { + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public StatResource[] getStats(String statisticsTypeName){ + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public StatResource[] getAllStats(){ + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public DLockInfo[] getDistributedLockInfo(){ + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public void addStatListener(StatListener observer, + StatResource observedResource, + Stat observedStat){ + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public void removeStatListener(StatListener observer){ + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public void addHealthListener(HealthListener observer, + GemFireHealthConfig cfg){ + + } + + public void removeHealthListener(){ + + } + + public void resetHealthStatus(){ + this.prevHealth = GemFireHealth.GOOD_HEALTH; + } + + public String[] getHealthDiagnosis(GemFireHealth.Health healthCode){ + if (healthCode == GemFireHealth.GOOD_HEALTH) { + return new String[0]; + + } else if (healthCode == GemFireHealth.OKAY_HEALTH) { + String[] array = new String[this.okayDiagnoses.size()]; + this.okayDiagnoses.toArray(array); + return array; + + } else { + Assert.assertTrue(healthCode == GemFireHealth.POOR_HEALTH); + String[] array = new String[this.poorDiagnoses.size()]; + this.poorDiagnoses.toArray(array); + return array; + } + } + + public Config getConfig(){ + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public void setConfig(Config cfg){ + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public GfManagerAgent getManagerAgent(){ + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public String[] getSystemLogs(){ + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public void setInspectionClasspath(String classpath){ + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public String getInspectionClasspath(){ + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public Region[] getRootRegions(){ + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public Region getRegion(CacheInfo c, String path) { + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public Region createVMRootRegion(CacheInfo c, String name, + RegionAttributes attrs) { + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public Region createSubregion(CacheInfo c, String parentPath, + String name, RegionAttributes attrs) { + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public void setCacheInspectionMode(int mode) { + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public int getCacheInspectionMode(){ + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public void takeRegionSnapshot(String regionName, int snapshotId){ + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public InternalDistributedMember getId() { + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public CacheInfo getCacheInfo() { + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public String getVersionInfo() { + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public CacheInfo setCacheLockTimeout(CacheInfo c, int v) { + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public CacheInfo setCacheLockLease(CacheInfo c, int v) { + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public CacheInfo setCacheSearchTimeout(CacheInfo c, int v) { + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public AdminBridgeServer addCacheServer(CacheInfo cache) + throws AdminException { + + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public AdminBridgeServer getBridgeInfo(CacheInfo cache, + int id) + throws AdminException { + + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public AdminBridgeServer startBridgeServer(CacheInfo cache, + AdminBridgeServer bridge) + throws AdminException { + + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + public AdminBridgeServer stopBridgeServer(CacheInfo cache, + AdminBridgeServer bridge) + throws AdminException { + + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + /** + * This operation is not supported for this object. Will throw + * UnsupportedOperationException if invoked. + */ + public void setAlertsManager(StatAlertDefinition[] alertDefs, + long refreshInterval, boolean setRemotely) { + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + /** + * This operation is not supported for this object. Will throw + * UnsupportedOperationException if invoked. + */ + public void setRefreshInterval(long refreshInterval) { + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } + + /** + * This operation is not supported for this object. Will throw + * UnsupportedOperationException if invoked. + */ + public void updateAlertDefinitions(StatAlertDefinition[] alertDefs, + int actionCode) { + throw new UnsupportedOperationException(LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString()); + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributionLocatorConfigImpl.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributionLocatorConfigImpl.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributionLocatorConfigImpl.java new file mode 100644 index 0000000..5b40d64 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributionLocatorConfigImpl.java @@ -0,0 +1,192 @@ +/* + * 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.admin.api.impl; + +import org.apache.geode.internal.admin.api.DistributionLocator; +import org.apache.geode.internal.admin.api.DistributionLocatorConfig; +import org.apache.geode.distributed.internal.tcpserver.*; +import org.apache.geode.internal.i18n.LocalizedStrings; + +import java.net.InetAddress; +import java.util.Properties; + +import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT; + +/** + * Provides an implementation of + * <code>DistributionLocatorConfig</code>. + * + * @since GemFire 4.0 + */ +public class DistributionLocatorConfigImpl + extends ManagedEntityConfigImpl + implements DistributionLocatorConfig { + + /** The minimum networking port (0) */ + public static final int MIN_PORT = 0; + + /** The maximum networking port (65535) */ + public static final int MAX_PORT = 65535; + + ////////////////////// Instance Fields ////////////////////// + + /** The port on which this locator listens */ + private int port; + + /** The address to bind to on a multi-homed host */ + private String bindAddress; + + /** The properties used to configure the DistributionLocator's + DistributedSystem */ + private Properties dsProperties; + + /** The DistributionLocator that was created with this config */ + private DistributionLocator locator; + + ////////////////////// Static Methods ////////////////////// + + /** + * Contacts a distribution locator on the given host and port and + * creates a <code>DistributionLocatorConfig</code> for it. + * + * @see TcpClient#getLocatorInfo + * + * @return <code>null</code> if the locator cannot be contacted + */ + static DistributionLocatorConfig + createConfigFor(String host, int port, InetAddress bindAddress) { + TcpClient client = new TcpClient(); + String[] info = null; + if (bindAddress != null) { + info = client.getInfo(bindAddress, port); + } + else { + info = client.getInfo(InetAddressUtil.toInetAddress(host), port); + } + if (info == null) { + return null; + } + + DistributionLocatorConfigImpl config = + new DistributionLocatorConfigImpl(); + config.setHost(host); + config.setPort(port); + if (bindAddress != null) { + config.setBindAddress(bindAddress.getHostAddress()); + } + config.setWorkingDirectory(info[0]); + config.setProductDirectory(info[1]); + + return config; + } + + /////////////////////// Constructors /////////////////////// + + /** + * Creates a new <code>DistributionLocatorConfigImpl</code> with the + * default settings. + */ + public DistributionLocatorConfigImpl() { + this.port = 0; + this.bindAddress = null; + this.locator = null; + this.dsProperties = new java.util.Properties(); + this.dsProperties.setProperty(MCAST_PORT, "0"); + } + + ///////////////////// Instance Methods ///////////////////// + + /** + * Sets the locator that was configured with this + * <Code>DistributionLocatorConfigImpl</code>. + */ + void setLocator(DistributionLocator locator) { + this.locator = locator; + } + + @Override + protected boolean isReadOnly() { + return this.locator != null && this.locator.isRunning(); + } + + public int getPort() { + return this.port; + } + + public void setPort(int port) { + checkReadOnly(); + this.port = port; + configChanged(); + } + + public String getBindAddress() { + return this.bindAddress; + } + + public void setBindAddress(String bindAddress) { + checkReadOnly(); + this.bindAddress = bindAddress; + configChanged(); + } + + public void setDistributedSystemProperties(Properties props) { + this.dsProperties = props; + } + + public Properties getDistributedSystemProperties() { + return this.dsProperties; + } + + @Override + public void validate() { + super.validate(); + + if (port < MIN_PORT || port > MAX_PORT) { + throw new IllegalArgumentException(LocalizedStrings.DistributionLocatorConfigImpl_PORT_0_MUST_BE_AN_INTEGER_BETWEEN_1_AND_2.toLocalizedString(new Object[] {Integer.valueOf(port), Integer.valueOf(MIN_PORT), Integer.valueOf(MAX_PORT)})); + } + + if (this.bindAddress != null && + InetAddressUtil.validateHost(this.bindAddress) == null) { + throw new IllegalArgumentException(LocalizedStrings.DistributionLocatorConfigImpl_INVALID_HOST_0.toLocalizedString(this.bindAddress)); + } + } + + /** + * Currently, listeners are not supported on the locator config. + */ + @Override + protected void configChanged() { + + } + + @Override + public Object clone() throws CloneNotSupportedException { + DistributionLocatorConfigImpl clone = + (DistributionLocatorConfigImpl) super.clone(); + clone.locator = null; + return clone; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("DistributionLocatorConfig: host=").append(getHost()); + sb.append(", bindAddress=").append(getBindAddress()); + sb.append(", port=").append(getPort()); + return sb.toString(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributionLocatorImpl.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributionLocatorImpl.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributionLocatorImpl.java new file mode 100755 index 0000000..0e5db21 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributionLocatorImpl.java @@ -0,0 +1,336 @@ +/* + * 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.admin.api.impl; + +import org.apache.geode.internal.admin.api.AdminDistributedSystem; +import org.apache.geode.internal.admin.api.DistributionLocator; +import org.apache.geode.internal.admin.api.DistributionLocatorConfig; +import org.apache.geode.internal.admin.api.ManagedEntityConfig; +import org.apache.geode.distributed.internal.DM; +import org.apache.geode.distributed.internal.DistributionConfig; +import org.apache.geode.distributed.internal.membership.InternalDistributedMember; +import org.apache.geode.internal.admin.remote.DistributionLocatorId; +import org.apache.geode.internal.i18n.LocalizedStrings; +import org.apache.geode.internal.logging.LogService; +import org.apache.geode.internal.logging.log4j.LocalizedMessage; +import org.apache.logging.log4j.Logger; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.*; + +/** + * Default administrative implementation of a DistributionLocator. + * + * @since GemFire 3.5 + */ +public class DistributionLocatorImpl + implements DistributionLocator, InternalManagedEntity { + + private static final Logger logger = LogService.getLogger(); + + /** + * How many new <code>DistributionLocator</code>s have been created? + */ + private static int newLocators = 0; + + //////////////////// Instance Fields //////////////////// + + /** + * The configuration object for this locator + */ + private final DistributionLocatorConfigImpl config; + + /** + * The id of this distribution locator + */ + private final String id; + + /** + * Used to control the actual DistributionLocator service + */ + private ManagedEntityController controller; + + /** + * The system that this locator is a part of + */ + private AdminDistributedSystemImpl system; + + // ------------------------------------------------------------------------- + // constructor(s)... + // ------------------------------------------------------------------------- + + /** + * Constructs new instance of <code>DistributionLocatorImpl</code> + * that is a member of the given distributed system. + */ + public DistributionLocatorImpl(DistributionLocatorConfig config, + AdminDistributedSystemImpl system) { + this.config = (DistributionLocatorConfigImpl) config; + this.config.validate(); + this.config.setManagedEntity(this); + this.id = getNewId(); + this.controller = system.getEntityController(); + this.system = system; + } + + // ------------------------------------------------------------------------- + // Attribute accessors/mutators... + // ------------------------------------------------------------------------- + + public String getId() { + return this.id; + } + + public String getNewId() { + synchronized (DistributionLocatorImpl.class) { + return "Locator" + (++newLocators); + } + } + + /** + * Returns the configuration object for this locator. + * + * @since GemFire 4.0 + */ + public DistributionLocatorConfig getConfig() { + return this.config; + } + + public AdminDistributedSystem getDistributedSystem() { + return this.system; + } + + /** + * Unfortunately, it doesn't make much sense to maintain the state + * of a locator. The admin API does not receive notification when + * the locator actually starts and stops. If we try to guess, we'll + * just end up with race conditions galore. So, we can't fix bug + * 32455 for locators. + */ + public int setState(int state) { + throw new UnsupportedOperationException(LocalizedStrings.DistributionLocatorImpl_CAN_NOT_SET_THE_STATE_OF_A_LOCATOR.toLocalizedString()); + } + + // ------------------------------------------------------------------------- + // Operations... + // ------------------------------------------------------------------------- + + /** + * Polls to determine whether or not this managed entity has + * started. + */ + public boolean waitToStart(long timeout) + throws InterruptedException { + + if (Thread.interrupted()) + throw new InterruptedException(); + + long start = System.currentTimeMillis(); + while (System.currentTimeMillis() - start < timeout) { + if (this.isRunning()) { + return true; + + } else { + Thread.sleep(100); + } + } + + logger.info(LocalizedMessage.create( + LocalizedStrings.DistributionLocatorImpl_DONE_WAITING_FOR_LOCATOR)); + return this.isRunning(); + } + + /** + * Polls to determine whether or not this managed entity has + * stopped. + */ + public boolean waitToStop(long timeout) + throws InterruptedException { + + if (Thread.interrupted()) + throw new InterruptedException(); + + long start = System.currentTimeMillis(); + while (System.currentTimeMillis() - start < timeout) { + if (!this.isRunning()) { + return true; + + } else { + Thread.sleep(100); + } + } + + return !this.isRunning(); + } + + public boolean isRunning() { + DM dm = ((AdminDistributedSystemImpl) getDistributedSystem()).getDistributionManager(); + if (dm == null) { + try { + return this.controller.isRunning(this); + } catch (IllegalStateException e) { + return false; + } + } + + String host = getConfig().getHost(); + int port = getConfig().getPort(); + String bindAddress = getConfig().getBindAddress(); + + boolean found = false; + Map<InternalDistributedMember, Collection<String>> hostedLocators = dm.getAllHostedLocators(); + for (Iterator<InternalDistributedMember> memberIter = hostedLocators.keySet().iterator(); memberIter.hasNext(); ) { + for (Iterator<String> locatorIter = hostedLocators.get(memberIter.next()).iterator(); locatorIter.hasNext(); ) { + DistributionLocatorId locator = new DistributionLocatorId(locatorIter.next()); + found = found || locator.getHost().getHostAddress().equals(host); + found = found || locator.getHost().getHostName().equals(host); + if (!found && !host.contains(".")) { + try { + InetAddress inetAddr = InetAddress.getByName(host); + found = locator.getHost().getHostName().equals(inetAddr.getHostName()); + if (!found) { + found = locator.getHost().getHostAddress().equals(inetAddr.getHostAddress()); + } + } catch (UnknownHostException e) { + // try config host as if it is an IP address instead of host name + } + } + if (locator.getBindAddress() != null && !locator.getBindAddress().isEmpty() + && bindAddress != null && !bindAddress.isEmpty()) { + found = found && locator.getBindAddress().equals(bindAddress); + } + found = found && locator.getPort() == port; + if (found) { + return true; + } + } + } + return found; + } + + public void start() { + this.config.validate(); + this.controller.start(this); + this.config.setLocator(this); + this.system.updateLocatorsString(); + } + + public void stop() { + this.controller.stop(this); + this.config.setLocator(null); + } + + public String getLog() { + return this.controller.getLog(this); + } + + /** + * Returns a string representation of the object. + * + * @return a string representation of the object + */ + @Override + public String toString() { + return "DistributionLocator " + getId(); + } + + //////////////////////// Command execution //////////////////////// + + public ManagedEntityConfig getEntityConfig() { + return this.getConfig(); + } + + public String getEntityType() { + return "Locator"; + } + + public String getStartCommand() { + StringBuffer sb = new StringBuffer(); + sb.append(this.controller.getProductExecutable(this, "gemfire")); + sb.append(" start-locator -q -dir="); + sb.append(this.getConfig().getWorkingDirectory()); + sb.append(" -port="); + sb.append(this.getConfig().getPort()); + Properties props = config.getDistributedSystemProperties(); + Enumeration en = props.propertyNames(); + while (en.hasMoreElements()) { + String pn = (String) en.nextElement(); + sb.append(" -D" + DistributionConfig.GEMFIRE_PREFIX + "" + pn + "=" + props.getProperty(pn)); + } + + String bindAddress = this.getConfig().getBindAddress(); + if (bindAddress != null && bindAddress.length() > 0) { + sb.append(" -address="); + sb.append(this.getConfig().getBindAddress()); + } + sb.append(" "); + + String sslArgs = + this.controller.buildSSLArguments(this.system.getConfig()); + if (sslArgs != null) { + sb.append(sslArgs); + } + + return sb.toString().trim(); + } + + public String getStopCommand() { + StringBuffer sb = new StringBuffer(); + sb.append(this.controller.getProductExecutable(this, "gemfire")); + sb.append(" stop-locator -q -dir="); + sb.append(this.getConfig().getWorkingDirectory()); + sb.append(" -port="); + sb.append(this.getConfig().getPort()); + + String bindAddress = this.getConfig().getBindAddress(); + if (bindAddress != null && bindAddress.length() > 0) { + sb.append(" -address="); + sb.append(this.getConfig().getBindAddress()); + } + sb.append(" "); + + String sslArgs = + this.controller.buildSSLArguments(this.system.getConfig()); + if (sslArgs != null) { + sb.append(sslArgs); + } + + return sb.toString().trim(); + } + + public String getIsRunningCommand() { + StringBuffer sb = new StringBuffer(); + sb.append(this.controller.getProductExecutable(this, "gemfire")); + sb.append(" status-locator -dir="); + sb.append(this.getConfig().getWorkingDirectory()); + + return sb.toString().trim(); + } + + public String getLogCommand() { + StringBuffer sb = new StringBuffer(); + sb.append(this.controller.getProductExecutable(this, "gemfire")); + sb.append(" tail-locator-log -dir="); + sb.append(this.getConfig().getWorkingDirectory()); + + return sb.toString().trim(); + } + +} +
