blob: a30994b5be5f48ea223d55c050ab3421fd1f3140 [file] [log] [blame]
/*
* 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.admin.jmx.internal;
import static org.apache.geode.distributed.ConfigurationProperties.BIND_ADDRESS;
import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_CIPHERS;
import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_ENABLED;
import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_PROTOCOLS;
import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_REQUIRE_AUTHENTICATION;
import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
import static org.apache.geode.distributed.ConfigurationProperties.MCAST_ADDRESS;
import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
import static org.apache.geode.distributed.ConfigurationProperties.TCP_PORT;
import static org.apache.geode.distributed.internal.DistributionConfig.DEFAULT_SSL_CIPHERS;
import static org.apache.geode.distributed.internal.DistributionConfig.DEFAULT_SSL_ENABLED;
import static org.apache.geode.distributed.internal.DistributionConfig.DEFAULT_SSL_PROTOCOLS;
import static org.apache.geode.distributed.internal.DistributionConfig.DEFAULT_SSL_REQUIRE_AUTHENTICATION;
import static org.apache.geode.internal.net.InetAddressUtils.toHostString;
import static org.apache.geode.internal.net.InetAddressUtilsWithLogging.validateHost;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.InetAddress;
import java.net.URL;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Properties;
import java.util.StringTokenizer;
import org.apache.geode.GemFireIOException;
import org.apache.geode.admin.DistributedSystemConfig;
import org.apache.geode.admin.DistributionLocatorConfig;
import org.apache.geode.admin.internal.DistributedSystemConfigImpl;
import org.apache.geode.admin.jmx.Agent;
import org.apache.geode.admin.jmx.AgentConfig;
import org.apache.geode.internal.ClassPathLoader;
import org.apache.geode.internal.util.IOUtils;
/**
* Provides the JMX Agent configuration properties.
* <p>
* Supports importing of persisted properties from an external configuration file.
* <p>
* Select values can also be overridden with command line arguments. See remarks on individual
* properties for further information.
* <p>
* Extends and implements DistributedSystemConfig.
*
* @since GemFire 3.5 (in which it was named AgentConfig)
*/
public class AgentConfigImpl extends DistributedSystemConfigImpl implements AgentConfig {
// -------------------------------------------------------------------------
// Static class variable(s)
// -------------------------------------------------------------------------
/**
* Command-line arg to enable agent debugging
*/
public static final String AGENT_DEBUG = "agent-debug";
/**
* The name of the "propertyFile" property. May specify as cmd-line arg
*/
public static final String PROPERTY_FILE_NAME = "property-file";
/**
* The name of the "gfAgentPropertyFile" property, can be specified as System Property
*/
public static final String AGENT_PROPSFILE_PROPERTY_NAME = "gfAgentPropertyFile";
// -------------------------------------------------------------------------
// DistributionLocator properties...
// -------------------------------------------------------------------------
/**
* The name of the "locator.host-" property
*/
public static final String LOCATOR_HOST_NAME = "locator.host-";
/**
* The name of the "locator.port-" property
*/
public static final String LOCATOR_PORT_NAME = "locator.port-";
/**
* The name of the "locator.product-directory-" property
*/
public static final String LOCATOR_PRODUCT_DIRECTORY_NAME = "locator.product-directory-";
/**
* The name of the "locator.working-directory-" property
*/
public static final String LOCATOR_WORKING_DIRECTORY_NAME = "locator.working-directory-";
/**
* The name of the "locator.remote-command-" property
*/
public static final String LOCATOR_REMOTE_COMMAND = "locator.remote-command-";
/**
* The name of the "locator.bind-address-" property
*/
public static final String LOCATOR_BIND_ADDRESS = "locator.bind-address-";
/**
* the properties used in configuring a locator's distributed system
*/
public static final String LOCATOR_DS_PROPERTIES = "locator.ds-properties";
/**
* The default log file for stand-alone JMX agents
*/
/* package scope */
static final String DEFAULT_LOG_FILE = "agent.log";
/**
* The default startup log file to be used by agent launcher
*/
/* package scope */
static final String DEFAULT_STARTUP_LOG_FILE = "start_agent.log";
private static final String OBFUSCATED_STRING = "********";
////////////////////// Static Methods //////////////////////
/**
* The <code>propertyFile</code> is the name of the property file that will be loaded on startup
* of the Agent.
* <p>
* The file will be searched for, in order, in the following directories:
* <ol>
* <li>the current directory
* <li>the home directory
* <li>the class path
* </ol>
* Only the first file found will be used.
* <p>
* The default value of propertyFile is <code>"agent.properties"</code>. However if the
* "gfAgentPropertyFile" system property is set then its value is the value of propertyFile. If
* this value is a relative file system path then the above search is done. If its an absolute
* file system path then that file must exist; no search for it is done.
*/
static String retrievePropertyFile() {
return System.getProperty(AGENT_PROPSFILE_PROPERTY_NAME, DEFAULT_PROPERTY_FILE);
}
/**
* Creates a new <code>Properties</code> object that contains all of the default values.
*/
private static Properties getDefaultProperties() {
Properties props = new Properties();
props.setProperty(AUTO_CONNECT_NAME, String.valueOf(DEFAULT_AUTO_CONNECT));
props.setProperty(HTTP_ENABLED_NAME, String.valueOf(DEFAULT_HTTP_ENABLED));
props.setProperty(HTTP_BIND_ADDRESS_NAME, String.valueOf(DEFAULT_HTTP_BIND_ADDRESS));
props.setProperty(HTTP_PORT_NAME, String.valueOf(DEFAULT_HTTP_PORT));
props.setProperty(HTTP_AUTHENTICATION_ENABLED_NAME,
String.valueOf(DEFAULT_HTTP_AUTHENTICATION_ENABLED));
props.setProperty(HTTP_AUTHENTICATION_USER_NAME,
String.valueOf(DEFAULT_HTTP_AUTHENTICATION_USER));
props.setProperty(HTTP_AUTHENTICATION_PASSWORD_NAME,
String.valueOf(DEFAULT_HTTP_AUTHENTICATION_PASSWORD));
props.setProperty(RMI_ENABLED_NAME, String.valueOf(DEFAULT_RMI_ENABLED));
props.setProperty(RMI_REGISTRY_ENABLED_NAME, String.valueOf(DEFAULT_RMI_REGISTRY_ENABLED));
props.setProperty(RMI_BIND_ADDRESS_NAME, String.valueOf(DEFAULT_RMI_BIND_ADDRESS));
props.setProperty(RMI_PORT_NAME, String.valueOf(DEFAULT_RMI_PORT));
props.setProperty(RMI_SERVER_PORT_NAME, String.valueOf(DEFAULT_RMI_SERVER_PORT));
props.setProperty(SNMP_ENABLED_NAME, String.valueOf(DEFAULT_SNMP_ENABLED));
props.setProperty(SNMP_DIRECTORY_NAME, String.valueOf(DEFAULT_SNMP_DIRECTORY));
props.setProperty(AGENT_SSL_ENABLED_NAME, String.valueOf(DEFAULT_AGENT_SSL_ENABLED));
props.setProperty(AGENT_SSL_PROTOCOLS_NAME, String.valueOf(DEFAULT_AGENT_SSL_PROTOCOLS));
props.setProperty(AGENT_SSL_CIPHERS_NAME, String.valueOf(DEFAULT_AGENT_SSL_CIPHERS));
props.setProperty(AGENT_SSL_REQUIRE_AUTHENTICATION_NAME,
String.valueOf(DEFAULT_AGENT_SSL_REQUIRE_AUTHENTICATION));
props.setProperty(HTTP_SSL_REQUIRE_AUTHENTICATION_NAME,
String.valueOf(DEFAULT_HTTP_SSL_REQUIRE_AUTHENTICATION));
return props;
}
/**
* Returns default values for all valid agent properties as a Properties object.
*
* @return default values for all valid agent properties
*/
static Properties getDefaultValuesForAllProperties() {
Properties props = new Properties();
props.setProperty(AUTO_CONNECT_NAME, String.valueOf(DEFAULT_AUTO_CONNECT));
props.setProperty(HTTP_ENABLED_NAME, String.valueOf(DEFAULT_HTTP_ENABLED));
props.setProperty(HTTP_BIND_ADDRESS_NAME, String.valueOf(DEFAULT_HTTP_BIND_ADDRESS));
props.setProperty(HTTP_PORT_NAME, String.valueOf(DEFAULT_HTTP_PORT));
props.setProperty(HTTP_AUTHENTICATION_ENABLED_NAME,
String.valueOf(DEFAULT_HTTP_AUTHENTICATION_ENABLED));
props.setProperty(HTTP_AUTHENTICATION_USER_NAME,
String.valueOf(DEFAULT_HTTP_AUTHENTICATION_USER));
props.setProperty(HTTP_AUTHENTICATION_PASSWORD_NAME,
String.valueOf(DEFAULT_HTTP_AUTHENTICATION_PASSWORD));
props.setProperty(RMI_ENABLED_NAME, String.valueOf(DEFAULT_RMI_ENABLED));
props.setProperty(RMI_REGISTRY_ENABLED_NAME, String.valueOf(DEFAULT_RMI_REGISTRY_ENABLED));
props.setProperty(RMI_BIND_ADDRESS_NAME, String.valueOf(DEFAULT_RMI_BIND_ADDRESS));
props.setProperty(RMI_PORT_NAME, String.valueOf(DEFAULT_RMI_PORT));
props.setProperty(RMI_SERVER_PORT_NAME, String.valueOf(DEFAULT_RMI_SERVER_PORT));
props.setProperty(SNMP_ENABLED_NAME, String.valueOf(DEFAULT_SNMP_ENABLED));
props.setProperty(SNMP_DIRECTORY_NAME, String.valueOf(DEFAULT_SNMP_DIRECTORY));
props.setProperty(AGENT_SSL_ENABLED_NAME, String.valueOf(DEFAULT_AGENT_SSL_ENABLED));
props.setProperty(AGENT_SSL_PROTOCOLS_NAME, String.valueOf(DEFAULT_AGENT_SSL_PROTOCOLS));
props.setProperty(AGENT_SSL_CIPHERS_NAME, String.valueOf(DEFAULT_AGENT_SSL_CIPHERS));
props.setProperty(AGENT_SSL_REQUIRE_AUTHENTICATION_NAME,
String.valueOf(DEFAULT_AGENT_SSL_REQUIRE_AUTHENTICATION));
props.setProperty(HTTP_SSL_REQUIRE_AUTHENTICATION_NAME,
String.valueOf(DEFAULT_HTTP_SSL_REQUIRE_AUTHENTICATION));
props.setProperty(SNMP_BIND_ADDRESS_NAME, String.valueOf(DEFAULT_SNMP_BIND_ADDRESS));
props.setProperty(EMAIL_NOTIFICATIONS_ENABLED_NAME,
String.valueOf(DEFAULT_EMAIL_NOTIFICATIONS_ENABLED));
props.setProperty(EMAIL_NOTIFICATIONS_HOST_NAME, String.valueOf(DEFAULT_EMAIL_HOST));
props.setProperty(EMAIL_NOTIFICATIONS_FROM_NAME, String.valueOf(DEFAULT_EMAIL_FROM));
props.setProperty(EMAIL_NOTIFICATIONS_TO_LIST_NAME, String.valueOf(DEFAULT_EMAIL_TO_LIST));
props.setProperty(STATE_SAVE_FILE_NAME, String.valueOf(DEFAULT_STATE_SAVE_FILE));
props.setProperty(CLUSTER_SSL_ENABLED, String.valueOf(DEFAULT_SSL_ENABLED));
props.setProperty(CLUSTER_SSL_PROTOCOLS, String.valueOf(DEFAULT_SSL_PROTOCOLS));
props.setProperty(CLUSTER_SSL_CIPHERS, String.valueOf(DEFAULT_SSL_CIPHERS));
props.setProperty(CLUSTER_SSL_REQUIRE_AUTHENTICATION,
String.valueOf(DEFAULT_SSL_REQUIRE_AUTHENTICATION));
props.setProperty(ENTITY_CONFIG_XML_FILE_NAME, String.valueOf(DEFAULT_ENTITY_CONFIG_XML_FILE));
props.setProperty(MCAST_PORT, String.valueOf(DEFAULT_MCAST_PORT));
props.setProperty(MCAST_ADDRESS, String.valueOf(DEFAULT_MCAST_ADDRESS));
props.setProperty(LOCATORS, String.valueOf(DEFAULT_LOCATORS));
props.setProperty(BIND_ADDRESS, String.valueOf(DEFAULT_BIND_ADDRESS));
props.setProperty(REMOTE_COMMAND_NAME, String.valueOf(DEFAULT_REMOTE_COMMAND));
props.setProperty(LOG_FILE_NAME, String.valueOf(DEFAULT_LOG_FILE));
props.setProperty(LOG_LEVEL_NAME, String.valueOf(DEFAULT_LOG_LEVEL));
props.setProperty(LOG_DISK_SPACE_LIMIT_NAME, String.valueOf(DEFAULT_LOG_DISK_SPACE_LIMIT));
props.setProperty(LOG_FILE_SIZE_LIMIT_NAME, String.valueOf(DEFAULT_LOG_FILE_SIZE_LIMIT));
props.setProperty(REFRESH_INTERVAL_NAME, String.valueOf(DEFAULT_REFRESH_INTERVAL));
return props;
}
// -------------------------------------------------------------------------
// Member variable(s)
// -------------------------------------------------------------------------
/**
* Does agent automatically connect to the distributed system?
*/
private boolean autoConnect;
/**
* True if Agent adaptors should use SSL
*/
private boolean agentSSLEnabled;
/**
* The SSL Protocols that the Agent adaptors will use
*/
private String agentSSLProtocols;
/**
* The SSL Ciphers that the Agent adaptors will use
*/
private String agentSSLCiphers;
/**
* True if Agent adaptors require authentication when SSL is enabled
*/
private boolean agentSSLRequireAuth;
/**
* HttpAdaptor won't work with ssl authentication required, so this attribute allows this option
* to be turned on for RMI but off for HTTP in the event that both adaptors are being used with
* ssl.
*/
private boolean httpSSLRequireAuth;
/**
* True if HttpAdaptor authentication is enabled
*/
private boolean httpAuthEnabled;
/**
* The login user for HttpAdaptor authentication
*/
private String httpAuthUser;
/**
* The login password for HttpAdaptor authentication
*/
private String httpAuthPassword;
/**
* True if the HttpAdaptor is enabled
*/
private boolean httpEnabled;
/**
* The port for the MX4J HttpAdatper
*/
private int httpPort;
/**
* The host for the MX4J HttpAdatper
*/
private String httpBindAddress;
/**
* True if the RMIConnectorServer is enabled
*/
private boolean rmiEnabled;
/**
* True if the Agent is to create its own RMI registry
*/
private boolean rmiRegistryEnabled;
/**
* The host for the MX4J RMIConnectorServer
*/
private String rmiBindAddress;
/**
* The port for the RMI Registry created by the Agent
*/
private int rmiPort;
/**
* The port for the MX4J RMIConnectorServer
*/
private int rmiServerPort;
/**
* True if the SnmpAdaptor is enabled
*/
private boolean snmpEnabled;
/**
* The bind address for sockets used by the SNMP adapter
*/
private String snmpBindAddress;
/**
* Path to the directory containing the SNMP Adaptor and its sub-dirs
*/
private String snmpDirectory;
/**
* Is Email notification enabled
*/
private boolean isEmailNotificationEnabled;
/**
* Email notification from: emailID
*/
private String emailNotificationFrom;
/**
* The host name of the mail server to be used for email communication.
*/
private String emailNotificationHostName;
/**
* Email notification to: emailIDs list
*/
private String emailNotificationToList;
/**
* State Save File Name
*/
private String stateSaveFile;
/**
* Describes the property file used to load configuration from. Null if no file was found.
*/
private URL url;
/**
* Original command line arguments
*/
private String[] originalCmdLineArgs = null;
/**
* The <code>Agent</code> that is configured by this <code>AgentConfigImpl</code>
*/
private Agent agent;
// -------------------------------------------------------------------------
// Constructor(s)
// -------------------------------------------------------------------------
/**
* Constructs new instance of <code>AgentConfigImpl</code> with the default configuration.
*/
public AgentConfigImpl() {
this(getDefaultProperties());
}
/**
* Constructs new instance of AgentConfig. Supplied command-line arguments are used to create a
* set of non-default properties for initializing this AgentConfig.
*
* @param args array of non-default configuration arguments
*/
public AgentConfigImpl(String[] args) {
this(toProperties(args));
this.originalCmdLineArgs = args;
}
/**
* Creates a new <code>AgentConfig</code> with the given non-default configuration properties.
*
* @param props overriding non-default configuration properties
*/
public AgentConfigImpl(Properties props) {
// for admin bug #40434
super(filterOutAgentProperties(appendOptionalPropertyFileProperties(props)),
true/* ignore gemfire.properties */);
// first get any property values set in the optional property file
this.url = getPropertyFileURL(retrievePropertyFile());
initialize(appendOptionalPropertyFileProperties(props));
}
/**
* Constructs new instance of AgentConfig using the specified property file.
*
* @param propFile the file to load configuration properties from
*/
public AgentConfigImpl(File propFile) {
// Initialize default values
this();
Properties props = new Properties();
if (propFile.exists()) {
try {
FileInputStream in = new FileInputStream(propFile);
props.load(in);
in.close();
} catch (java.io.IOException e) {
throw new GemFireIOException(
String.format("Failed reading %s", propFile), e);
}
} else {
throw new IllegalArgumentException(
String.format("Specified properties file does not exist: %s",
propFile));
}
initialize(props);
}
////////////////////// Instance Methods //////////////////////
/**
* Sets the <code>Agent</code> associated with this <code>AgentConfigImpl</code>.
*/
void setAgent(Agent agent) {
this.agent = agent;
}
/**
* Checks to see if this config object is "read only". If it is, then an
* {@link IllegalStateException} is thrown.
*
* @since GemFire 4.0
*/
@Override
protected void checkReadOnly() {
if (this.agent != null) {
throw new IllegalStateException(
"An AgentConfig object cannot be modified after it has been used to create an Agent.");
}
super.checkReadOnly();
}
// -------------------------------------------------------------------------
// Methods for handling Properties and the Properties file
// -------------------------------------------------------------------------
/**
* Returns a description of the property file used to load this config. If no property file was
* used then the description will say so.
*/
public String getPropertyFileDescription() {
/*
* Checking if the specified or the default properties file exists. If not, just log this as an
* information.
*/
if (this.url == null) {
return "Using default configuration because property file was not found.";
} else {
return String.format("Configuration loaded from: %s.",
this.url);
}
}
/**
* Returns the default property file that will be used when configuration is saved.
*/
public File getPropertyFile() {
File f;
if (this.url == null) {
f = new File(retrievePropertyFile());
if (!f.isAbsolute()) {
// save to <cwd>/propertyFile
f = new File(System.getProperty("user.dir"), retrievePropertyFile());
}
} else {
f = new File(this.url.getFile());
}
return f;
}
/**
* Converts the contents of this config to a property instance and Stringifies it
*
* @return contents of this config as String
*/
public String toPropertiesAsString() {
Properties p = toProperties(true /* include DS properties */);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.println("Agent Configuration:");
Enumeration e = p.propertyNames();
while (e.hasMoreElements()) {
String pn = (String) e.nextElement();
String pv = p.getProperty(pn);
pw.println(" " + pn + " = " + pv);
}
pw.close();
return sw.toString();
}
/**
* Converts the contents of this config to a property instance.
*
* @return contents of this config as java.util.Properties
*/
public Properties toProperties() {
return toProperties(false /* include DS properties */);
}
/**
* Converts the contents of this config to a property instance.
*
* @param includeDSProperties Should distributed system properties be included in the
* <code>Properties</code> object? See bug 32682.
*
* @return contents of this config as java.util.Properties
*/
public Properties toProperties(boolean includeDSProperties) {
Properties props = new Properties();
props.setProperty(AUTO_CONNECT_NAME, toString(AUTO_CONNECT_NAME, getAutoConnect()));
props.setProperty(HTTP_ENABLED_NAME, toString(HTTP_ENABLED_NAME, isHttpEnabled()));
props.setProperty(HTTP_BIND_ADDRESS_NAME,
toString(HTTP_BIND_ADDRESS_NAME, getHttpBindAddress()));
props.setProperty(HTTP_PORT_NAME, toString(HTTP_PORT_NAME, getHttpPort()));
props.setProperty(RMI_ENABLED_NAME, toString(RMI_ENABLED_NAME, isRmiEnabled()));
props.setProperty(RMI_REGISTRY_ENABLED_NAME,
toString(RMI_REGISTRY_ENABLED_NAME, isRmiRegistryEnabled()));
props.setProperty(RMI_BIND_ADDRESS_NAME, toString(RMI_BIND_ADDRESS_NAME, getRmiBindAddress()));
props.setProperty(RMI_PORT_NAME, toString(RMI_PORT_NAME, getRmiPort()));
props.setProperty(RMI_SERVER_PORT_NAME, toString(RMI_SERVER_PORT_NAME, getRmiServerPort()));
props.setProperty(SNMP_ENABLED_NAME, toString(SNMP_ENABLED_NAME, isSnmpEnabled()));
props.setProperty(SNMP_BIND_ADDRESS_NAME,
toString(SNMP_BIND_ADDRESS_NAME, getSnmpBindAddress()));
props.setProperty(SNMP_DIRECTORY_NAME, toString(SNMP_DIRECTORY_NAME, getSnmpDirectory()));
props.setProperty(AGENT_SSL_ENABLED_NAME,
toString(AGENT_SSL_ENABLED_NAME, isAgentSSLEnabled()));
props.setProperty(AGENT_SSL_PROTOCOLS_NAME,
toString(AGENT_SSL_PROTOCOLS_NAME, getAgentSSLProtocols()));
props.setProperty(AGENT_SSL_CIPHERS_NAME,
toString(AGENT_SSL_CIPHERS_NAME, getAgentSSLCiphers()));
props.setProperty(AGENT_SSL_REQUIRE_AUTHENTICATION_NAME,
toString(AGENT_SSL_REQUIRE_AUTHENTICATION_NAME, isAgentSSLRequireAuth()));
props.setProperty(HTTP_SSL_REQUIRE_AUTHENTICATION_NAME,
toString(HTTP_SSL_REQUIRE_AUTHENTICATION_NAME, isHttpSSLRequireAuth()));
props.setProperty(HTTP_AUTHENTICATION_ENABLED_NAME,
toString(HTTP_AUTHENTICATION_ENABLED_NAME, isHttpAuthEnabled()));
props.setProperty(HTTP_AUTHENTICATION_USER_NAME,
toString(HTTP_AUTHENTICATION_USER_NAME, getHttpAuthUser()));
props.setProperty(HTTP_AUTHENTICATION_PASSWORD_NAME,
toString(HTTP_AUTHENTICATION_PASSWORD_NAME, getHttpAuthPassword()));
props.setProperty(EMAIL_NOTIFICATIONS_ENABLED_NAME,
toString(EMAIL_NOTIFICATIONS_ENABLED_NAME, isEmailNotificationEnabled()));
props.setProperty(EMAIL_NOTIFICATIONS_HOST_NAME,
toString(EMAIL_NOTIFICATIONS_HOST_NAME, getEmailNotificationHost()));
props.setProperty(EMAIL_NOTIFICATIONS_FROM_NAME,
toString(EMAIL_NOTIFICATIONS_FROM_NAME, getEmailNotificationFrom()));
props.setProperty(EMAIL_NOTIFICATIONS_TO_LIST_NAME,
toString(EMAIL_NOTIFICATIONS_TO_LIST_NAME, getEmailNotificationToList()));
props.setProperty(STATE_SAVE_FILE_NAME, toString(STATE_SAVE_FILE_NAME, getStateSaveFile()));
props.setProperty(EMAIL_NOTIFICATIONS_ENABLED_NAME,
toString(EMAIL_NOTIFICATIONS_ENABLED_NAME, isEmailNotificationEnabled()));
props.setProperty(EMAIL_NOTIFICATIONS_HOST_NAME,
toString(EMAIL_NOTIFICATIONS_HOST_NAME, getEmailNotificationHost()));
props.setProperty(EMAIL_NOTIFICATIONS_FROM_NAME,
toString(EMAIL_NOTIFICATIONS_FROM_NAME, getEmailNotificationFrom()));
props.setProperty(EMAIL_NOTIFICATIONS_TO_LIST_NAME,
toString(EMAIL_NOTIFICATIONS_TO_LIST_NAME, getEmailNotificationToList()));
props.setProperty(CLUSTER_SSL_ENABLED, toString(CLUSTER_SSL_ENABLED, isSSLEnabled()));
props.setProperty(CLUSTER_SSL_PROTOCOLS, toString(CLUSTER_SSL_PROTOCOLS, getSSLProtocols()));
props.setProperty(CLUSTER_SSL_CIPHERS, toString(CLUSTER_SSL_CIPHERS, getSSLCiphers()));
props.setProperty(CLUSTER_SSL_REQUIRE_AUTHENTICATION,
toString(CLUSTER_SSL_REQUIRE_AUTHENTICATION, isSSLAuthenticationRequired()));
Properties sslProps = getSSLProperties();
if (sslProps.size() > 0) {
int sequence = 0;
for (Iterator iter = sslProps.keySet().iterator(); iter.hasNext();) {
String key = (String) iter.next();
String value = sslProps.getProperty(key);
props.setProperty("ssl-property-" + sequence, key + "=" + OBFUSCATED_STRING);
sequence++;
}
}
if (this.getDistributionLocatorConfigs().length > 0) {
DistributionLocatorConfig[] configs = this.getDistributionLocatorConfigs();
for (int i = 0; i < configs.length; i++) {
DistributionLocatorConfig locator = configs[i];
props.setProperty(LOCATOR_HOST_NAME + i, toString(LOCATOR_HOST_NAME, locator.getHost()));
props.setProperty(LOCATOR_PORT_NAME + i, toString(LOCATOR_PORT_NAME, locator.getPort()));
props.setProperty(LOCATOR_PRODUCT_DIRECTORY_NAME + i,
toString(LOCATOR_PRODUCT_DIRECTORY_NAME, locator.getProductDirectory()));
props.setProperty(LOCATOR_WORKING_DIRECTORY_NAME + i,
toString(LOCATOR_WORKING_DIRECTORY_NAME, locator.getWorkingDirectory()));
props.setProperty(LOCATOR_REMOTE_COMMAND + i,
toString(LOCATOR_REMOTE_COMMAND, locator.getRemoteCommand()));
props.setProperty(LOCATOR_BIND_ADDRESS + i,
toString(LOCATOR_BIND_ADDRESS, locator.getBindAddress()));
}
}
if (includeDSProperties) {
props.setProperty(ENTITY_CONFIG_XML_FILE_NAME,
toString(ENTITY_CONFIG_XML_FILE_NAME, getEntityConfigXMLFile()));
props.setProperty(MCAST_PORT, toString(MCAST_PORT, getMcastPort()));
props.setProperty(MCAST_ADDRESS, toString(MCAST_ADDRESS, getMcastAddress()));
props.setProperty(LOCATORS, toString(LOCATORS, getLocators()));
props.setProperty(MEMBERSHIP_PORT_RANGE_NAME, getMembershipPortRange());
props.setProperty(TCP_PORT, "" + getTcpPort());
props.setProperty(BIND_ADDRESS, toString(BIND_ADDRESS, getBindAddress()));
props.setProperty(REMOTE_COMMAND_NAME, toString(REMOTE_COMMAND_NAME, getRemoteCommand()));
props.setProperty(LOG_FILE_NAME, toString(LOG_FILE_NAME, getLogFile()));
props.setProperty(LOG_LEVEL_NAME, toString(LOG_LEVEL_NAME, getLogLevel()));
props.setProperty(LOG_DISK_SPACE_LIMIT_NAME,
toString(LOG_DISK_SPACE_LIMIT_NAME, getLogDiskSpaceLimit()));
props.setProperty(LOG_FILE_SIZE_LIMIT_NAME,
toString(LOG_FILE_SIZE_LIMIT_NAME, getLogFileSizeLimit()));
props.setProperty(REFRESH_INTERVAL_NAME,
toString(REFRESH_INTERVAL_NAME, getRefreshInterval()));
}
return props;
}
// -------------------------------------------------------------------------
// Agent specific properties
// -------------------------------------------------------------------------
@Override
public boolean isAgentSSLEnabled() {
return this.agentSSLEnabled;
}
@Override
public void setAgentSSLEnabled(boolean agentSSLEnabled) {
checkReadOnly();
this.agentSSLEnabled = agentSSLEnabled;
configChanged();
}
@Override
public String getAgentSSLProtocols() {
return this.agentSSLProtocols;
}
@Override
public void setAgentSSLProtocols(String agentSSLProtocols) {
checkReadOnly();
this.agentSSLProtocols = agentSSLProtocols;
configChanged();
}
@Override
public String getAgentSSLCiphers() {
return this.agentSSLCiphers;
}
@Override
public void setAgentSSLCiphers(String agentSSLCiphers) {
checkReadOnly();
this.agentSSLCiphers = agentSSLCiphers;
configChanged();
}
@Override
public boolean isAgentSSLRequireAuth() {
return this.agentSSLRequireAuth;
}
@Override
public void setAgentSSLRequireAuth(boolean agentSSLRequireAuth) {
checkReadOnly();
this.agentSSLRequireAuth = agentSSLRequireAuth;
configChanged();
}
@Override
public boolean isHttpSSLRequireAuth() {
return this.httpSSLRequireAuth;
}
@Override
public void setHttpSSLRequireAuth(boolean httpSSLRequireAuth) {
checkReadOnly();
this.httpSSLRequireAuth = httpSSLRequireAuth;
configChanged();
}
@Override
public boolean isHttpAuthEnabled() {
return this.httpAuthEnabled;
}
@Override
public void setHttpAuthEnabled(boolean httpAuthEnabled) {
checkReadOnly();
this.httpAuthEnabled = httpAuthEnabled;
configChanged();
}
@Override
public String getHttpAuthUser() {
return this.httpAuthUser;
}
@Override
public void setHttpAuthUser(String httpAuthUser) {
checkReadOnly();
this.httpAuthUser = httpAuthUser;
configChanged();
}
@Override
public String getHttpAuthPassword() {
return this.httpAuthPassword;
}
@Override
public void setHttpAuthPassword(String httpAuthPassword) {
checkReadOnly();
this.httpAuthPassword = httpAuthPassword;
configChanged();
}
@Override
public boolean isSnmpEnabled() {
return this.snmpEnabled;
}
@Override
public void setSnmpEnabled(boolean snmpEnabled) {
checkReadOnly();
this.snmpEnabled = snmpEnabled;
configChanged();
}
@Override
public String getSnmpBindAddress() {
return this.snmpBindAddress;
}
@Override
public void setSnmpBindAddress(String snmpBindAddress) {
checkReadOnly();
this.snmpBindAddress = validateSnmpBindAddress(snmpBindAddress);
configChanged();
}
@Override
public String getSnmpDirectory() {
return this.snmpDirectory;
}
@Override
public void setSnmpDirectory(String snmpDirectory) {
checkReadOnly();
this.snmpDirectory = validateSnmpDirectory(snmpDirectory);
configChanged();
}
@Override
public boolean isRmiEnabled() {
return this.rmiEnabled;
}
@Override
public void setRmiEnabled(boolean rmiEnabled) {
checkReadOnly();
this.rmiEnabled = rmiEnabled;
configChanged();
}
@Override
public boolean isRmiRegistryEnabled() {
return this.rmiRegistryEnabled;
}
@Override
public void setRmiRegistryEnabled(boolean rmiRegistryEnabled) {
checkReadOnly();
this.rmiRegistryEnabled = rmiRegistryEnabled;
configChanged();
}
@Override
public String getRmiBindAddress() {
return this.rmiBindAddress;
}
@Override
public void setRmiBindAddress(String rmiBindAddress) {
checkReadOnly();
this.rmiBindAddress = validateRmiBindAddress(rmiBindAddress);
configChanged();
}
@Override
public int getRmiPort() {
return this.rmiPort;
}
@Override
public void setRmiPort(int rmiPort) {
checkReadOnly();
this.rmiPort = validateRmiPort(rmiPort);
configChanged();
}
/**
* Returns the port of the RMI Connector Server.
* <p>
* See <a href="#rmi-server-port">description</a> above.
*
* @return the value set for rmi-server-port
*
* @since GemFire 6.5
*/
@Override
public int getRmiServerPort() {
return this.rmiServerPort;
}
/**
* Sets the port of the RMI Connector Server.
*
* @param port rmi-server-port to set.
*
* @since GemFire 6.5
*/
@Override
public void setRmiServerPort(int port) {
checkReadOnly();
this.rmiServerPort = validateRmiServerPort(rmiServerPort);
configChanged();
}
@Override
public boolean isHttpEnabled() {
return this.httpEnabled;
}
@Override
public void setHttpEnabled(boolean httpEnabled) {
checkReadOnly();
this.httpEnabled = httpEnabled;
configChanged();
}
@Override
public int getHttpPort() {
return this.httpPort;
}
@Override
public void setHttpPort(int httpPort) {
checkReadOnly();
this.httpPort = validateHttpPort(httpPort);
configChanged();
}
@Override
public String getHttpBindAddress() {
return this.httpBindAddress;
}
@Override
public void setHttpBindAddress(String httpBindAddress) {
checkReadOnly();
this.httpBindAddress = validateHttpBindAddress(httpBindAddress);
configChanged();
}
public void setHttpBindAddress(InetAddress httpBindAddress) {
checkReadOnly();
this.httpBindAddress = validateHttpBindAddress(httpBindAddress);
configChanged();
}
@Override
public boolean getAutoConnect() {
return this.autoConnect;
}
@Override
public void setAutoConnect(boolean v) {
checkReadOnly();
this.autoConnect = v;
configChanged();
}
// -------------------------------------------------------------------------
// Implementation methods
// -------------------------------------------------------------------------
/**
* Initialize the values of this AgentConfig.
*
* @param props the configuration values to use
*/
private void initialize(Properties props) {
this.autoConnect = validateBoolean(props.getProperty(AUTO_CONNECT_NAME), DEFAULT_AUTO_CONNECT);
this.httpEnabled = validateBoolean(props.getProperty(HTTP_ENABLED_NAME), DEFAULT_HTTP_ENABLED);
this.httpBindAddress = validateHttpBindAddress(props.getProperty(HTTP_BIND_ADDRESS_NAME));
this.httpPort = validateHttpPort(props.getProperty(HTTP_PORT_NAME));
this.rmiEnabled = validateBoolean(props.getProperty(RMI_ENABLED_NAME), DEFAULT_RMI_ENABLED);
this.rmiRegistryEnabled =
validateBoolean(props.getProperty(RMI_REGISTRY_ENABLED_NAME), DEFAULT_RMI_REGISTRY_ENABLED);
this.rmiBindAddress = validateRmiBindAddress(props.getProperty(RMI_BIND_ADDRESS_NAME));
this.rmiPort = validateRmiPort(props.getProperty(RMI_PORT_NAME));
this.rmiServerPort = validateRmiServerPort(props.getProperty(RMI_SERVER_PORT_NAME));
this.snmpEnabled = validateBoolean(props.getProperty(SNMP_ENABLED_NAME), DEFAULT_SNMP_ENABLED);
this.snmpDirectory = validateSnmpDirectory(props.getProperty(SNMP_DIRECTORY_NAME));
this.agentSSLEnabled =
validateBoolean(props.getProperty(AGENT_SSL_ENABLED_NAME), DEFAULT_AGENT_SSL_ENABLED);
this.agentSSLProtocols = validateNonEmptyString(props.getProperty(AGENT_SSL_PROTOCOLS_NAME),
DEFAULT_AGENT_SSL_PROTOCOLS);
this.agentSSLCiphers = validateNonEmptyString(props.getProperty(AGENT_SSL_CIPHERS_NAME),
DEFAULT_AGENT_SSL_CIPHERS);
this.agentSSLRequireAuth =
validateBoolean(props.getProperty(AGENT_SSL_REQUIRE_AUTHENTICATION_NAME),
DEFAULT_AGENT_SSL_REQUIRE_AUTHENTICATION);
this.httpSSLRequireAuth =
validateBoolean(props.getProperty(HTTP_SSL_REQUIRE_AUTHENTICATION_NAME),
DEFAULT_HTTP_SSL_REQUIRE_AUTHENTICATION);
this.httpAuthEnabled = validateBoolean(props.getProperty(HTTP_AUTHENTICATION_ENABLED_NAME),
DEFAULT_HTTP_AUTHENTICATION_ENABLED);
this.httpAuthUser = validateNonEmptyString(props.getProperty(HTTP_AUTHENTICATION_USER_NAME),
DEFAULT_HTTP_AUTHENTICATION_USER);
this.httpAuthPassword = validateNonEmptyString(
props.getProperty(HTTP_AUTHENTICATION_PASSWORD_NAME), DEFAULT_HTTP_AUTHENTICATION_PASSWORD);
this.sslEnabled = validateBoolean(props.getProperty(CLUSTER_SSL_ENABLED), DEFAULT_SSL_ENABLED);
this.sslProtocols =
validateNonEmptyString(props.getProperty(CLUSTER_SSL_PROTOCOLS), DEFAULT_SSL_PROTOCOLS);
this.sslCiphers =
validateNonEmptyString(props.getProperty(CLUSTER_SSL_CIPHERS), DEFAULT_SSL_CIPHERS);
this.sslAuthenticationRequired = validateBoolean(
props.getProperty(CLUSTER_SSL_REQUIRE_AUTHENTICATION), DEFAULT_SSL_REQUIRE_AUTHENTICATION);
this.sslProperties = new Properties();
for (int i = 0; true; i++) {
String key = "ssl-property-" + i;
String value = props.getProperty(key);
if (value == null) {
break;
}
StringTokenizer st = new StringTokenizer(value, "=");
if (!st.hasMoreTokens()) {
break;
}
String propKey = st.nextToken();
if (!st.hasMoreTokens()) {
break;
}
String propValue = st.nextToken();
this.sslProperties.put(propKey, propValue);
}
this.isEmailNotificationEnabled =
validateBoolean(props.getProperty(AgentConfig.EMAIL_NOTIFICATIONS_ENABLED_NAME),
DEFAULT_EMAIL_NOTIFICATIONS_ENABLED);
this.emailNotificationHostName = validateNonEmptyString(
props.getProperty(AgentConfig.EMAIL_NOTIFICATIONS_HOST_NAME), DEFAULT_EMAIL_HOST);
this.emailNotificationFrom = validateNonEmptyString(
props.getProperty(AgentConfig.EMAIL_NOTIFICATIONS_FROM_NAME), DEFAULT_EMAIL_FROM);
this.emailNotificationToList = validateNonEmptyString(
props.getProperty(AgentConfig.EMAIL_NOTIFICATIONS_TO_LIST_NAME), DEFAULT_EMAIL_TO_LIST);
this.stateSaveFile = validateNonEmptyString(props.getProperty(AgentConfig.STATE_SAVE_FILE_NAME),
DEFAULT_STATE_SAVE_FILE);
try {
for (int i = 0; true; i++) {
String hostProp = props.getProperty(LOCATOR_HOST_NAME + i);
if (isEmpty(hostProp)) {
break;
}
String host = hostProp;
int port = Integer.parseInt(props.getProperty(LOCATOR_PORT_NAME + i));
File workDir =
validateWorkingDirectory(props.getProperty(LOCATOR_WORKING_DIRECTORY_NAME + i));
File prodDir = new File(
validateProductDirectory(props.getProperty(LOCATOR_PRODUCT_DIRECTORY_NAME + i)));
String remoteCmd = props.getProperty(LOCATOR_REMOTE_COMMAND + i);
String bindAddr = props.getProperty(LOCATOR_BIND_ADDRESS + i);
DistributionLocatorConfig config = this.createDistributionLocatorConfig();
config.setHost(host);
config.setPort(port);
config.setBindAddress(bindAddr);
config.setWorkingDirectory(workDir.getAbsolutePath());
config.setProductDirectory(prodDir.getAbsolutePath());
config.setRemoteCommand(remoteCmd);
}
} catch (IllegalArgumentException e) {
// This is how we break out of the loop? Yuck!
/*
* LogWriter is initialized afterwards. Hence printing the stack trace. This is done to avoid
* creation of duplicate log writer.
*/
e.printStackTrace();
}
}
/**
* Filter all agent configuration attributes out of the given <code>Properties</code> object.
* <p/>
*
* @param props the <code>Properties</code> object of filter agent configuration attributes out
* of.
*
* @see AgentConfigImpl#_getPropertyDescription(String)
*/
private static Properties filterOutAgentProperties(final Properties props) {
final Properties filteredProps = new Properties();
for (final Object key : props.keySet()) {
if (_getPropertyDescription(key.toString()) == null) {
final String value = props.getProperty(key.toString());
if (value != null) {
filteredProps.setProperty(key.toString(), value);
}
}
}
appendLogFileProperty(filteredProps);
return filteredProps;
}
/**
* Appends the log-file property to the Properties object if set of properties does not already
* define the log-file property or the gemfire.agent.log-file property.
* <p/>
*
* @param props the <code>Properties</code> to append the log-file property to if the property
* does not exist.
*/
private static void appendLogFileProperty(final Properties props) {
if (!(props.containsKey(DistributedSystemConfig.LOG_FILE_NAME)
|| props.containsKey(SYSTEM_PROPERTY_PREFIX + DistributedSystemConfig.LOG_FILE_NAME))) {
props.put(DistributedSystemConfig.LOG_FILE_NAME, DEFAULT_LOG_FILE);
}
}
/**
* Appends any additional property-file specified properties to the supplied Properties. If the
* supplied property overrides the property in the property-file, then property-file value is
* ignored. System Properties always override the supplied properties
*
* @return appendedProps Properties appened to from the property-file if any
*/
private static Properties appendOptionalPropertyFileProperties(final Properties props) {
final URL url = getPropertyFileURL(retrievePropertyFile());
final Properties appendedProps = new Properties();
appendedProps.putAll(props);
// first, get any property values set in the optional property file
if (url != null) {
InputStream in = null;
try {
in = url.openStream();
final Properties agentPropertyFileProperties = new Properties();
agentPropertyFileProperties.load(in);
// don't let any properties from the file override those on the command-line
for (final Object key : agentPropertyFileProperties.keySet()) {
if (props.getProperty(key.toString()) == null) {
appendedProps.setProperty(key.toString(),
agentPropertyFileProperties.getProperty(key.toString()));
}
}
} catch (IOException e) {
throw new GemFireIOException(
String.format("Failed reading %s", url.toString()), e);
} finally {
IOUtils.close(in);
}
}
// last override values with those from the system properties
// TODO this is not exactly overriding!
for (final Object propSuffix : props.keySet()) {
final String key = SYSTEM_PROPERTY_PREFIX + propSuffix;
final String value = System.getProperty(key);
if (value != null) {
appendedProps.put(key, value);
}
}
return appendedProps;
}
/**
* Returns a description of the given agent config property
*
* @throws IllegalArgumentException If <code>prop</code> is not a recognized agent configuration
* property
*/
public static String getPropertyDescription(String prop) {
if (prop.equals(LOG_FILE_NAME)) {
return "Name of the agent's log file";
} else if (prop.equals(LOG_LEVEL_NAME)) {
return "Minimum level of logging performed by agent. Valid values are: all, finest, finer, fine, config, info, warning, error, severe and none.";
} else if (prop.equals(AGENT_DEBUG)) {
return "Whether the agent should print debugging information";
} else if (prop.equals(LOG_DISK_SPACE_LIMIT_NAME)) {
return "Limit, in megabytes, of how much disk space can be consumed by old inactive log files. This value (in megabytes) should be in the range: 0-1000000.";
} else if (prop.equals(LOG_FILE_SIZE_LIMIT_NAME)) {
return "Limit, in megabytes, of how large the current log file can grow before it is closed and log rolls on to a new file. This value (in megabytes) should be in the range: 0-1000000.";
} else if (prop.equals(MCAST_PORT)) {
return "Multicast port used to connect to distributed system. To use IP multicast, you must also define mcast-address. The value must be in the range: 0-65535.";
} else if (prop.equals(MCAST_ADDRESS)) {
return "Multicast address used to connect to distributed system. To use multicast, you must also define mcast-port, the IP port.";
} else if (prop.equals(BIND_ADDRESS)) {
return "An IP address of the JMX Agent's distributed system on a multi-homed host. On a multi-homed host, you must explicitly specify the bind address.";
} else if (prop.equals(TCP_PORT)) {
return "TCP/IP port number to use in the agent's distributed system";
} else if (prop.equals(LOCATORS)) {
return "A comma-separated list of address(es) of the locator(s) in the distributed system in host[port] form. E.g. locators=host1[port1],host2[port2],...,hostn[portn]";
} else if (prop.equals(MEMBERSHIP_PORT_RANGE_NAME)) {
return "The allowed range of UDP ports for use in forming an unique membership identifier. This range is given as two numbers separated by a minus sign.";
} else if (prop.equals(ENTITY_CONFIG_XML_FILE_NAME)) {
return "The name of an XML file that specifies the configuration for the managed entity administered by the Distributed System. The XML file must conform to the dtd - doc-files/ds5_0.dtd.";
} else if (prop.equals(REFRESH_INTERVAL_NAME)) {
return "Refresh Interval, in seconds, to be used for auto-refresh of SystemMember, StatisticResource and CacheServer refreshes";
} else if (prop.equals(REMOTE_COMMAND_NAME)) {
return "Command prefix used for launching members of the distributed system";
} else if (prop.equals(CLUSTER_SSL_ENABLED)) {
return "Whether to use the SSL protocol for communication between members of the admin distributed system. If set to true, locators should be used.";
} else if (prop.equals(CLUSTER_SSL_PROTOCOLS)) {
return "A space-separated list of the SSL protocols used to communicate with distributed system.";
} else if (prop.equals(CLUSTER_SSL_CIPHERS)) {
return "A space-separated list of the SSL ciphers to be used to communicate with distributed system.";
} else if (prop.equals(CLUSTER_SSL_REQUIRE_AUTHENTICATION)) {
return "Whether connection to the distributed system needs SSL authentication.";
} else {
String description = _getPropertyDescription(prop);
if (description == null) {
throw new IllegalArgumentException(
String.format("Unknown config property: %s", prop));
} else {
return description;
}
}
}
/**
* Returns a description of the given agent config property or <code>null</code> if
* <code>prop</code> is not a recognized agent property.
*/
public static String _getPropertyDescription(String prop) {
if (prop.equals(AUTO_CONNECT_NAME)) {
return "Whether the JMX agent will connect 'automatically' to the distributed system that it is configured to monitor.";
} else if (prop.equals(HTTP_ENABLED_NAME)) {
return "Whether the HTTP adapter is enabled in the JMX agent.";
} else if (prop.equals(HTTP_BIND_ADDRESS_NAME)) {
return "Bind address of HTTP adapter's sockets";
} else if (prop.equals(HTTP_PORT_NAME)) {
return "The port on which the HTTP adapter will be started. This value should be in the range: 0-65535.";
} else if (prop.equals(RMI_ENABLED_NAME)) {
return "Whether the RMI JMX adapter is enabled.";
} else if (prop.equals(RMI_REGISTRY_ENABLED_NAME)) {
return "Whether the JMX agent should start RMI registry. Alternatively, a registry outside of the JMX agent VM can be used.";
} else if (prop.equals(RMI_BIND_ADDRESS_NAME)) {
return "Bind address of RMI adapter's sockets";
} else if (prop.equals(RMI_PORT_NAME)) {
return "The port on which to contact the RMI registry. The value must be in the range: 0-65535.";
} else if (prop.equals(RMI_SERVER_PORT_NAME)) {
return "The port on which the RMI Connector Server should start. The value must be in the range: 0-65535.";
} else if (prop.equals(SNMP_ENABLED_NAME)) {
return "Whether the SNMP JMX adapter will be enabled.";
} else if (prop.equals(SNMP_BIND_ADDRESS_NAME)) {
return "Bind address of SNMP adapter's sockets";
} else if (prop.equals(SNMP_DIRECTORY_NAME)) {
return "The directory in which SNMP configuration resides";
} else if (prop.equals(AGENT_SSL_ENABLED_NAME)) {
return "Whether the JMX Agent will use the SSL protocol for communication.";
} else if (prop.equals(AGENT_SSL_PROTOCOLS_NAME)) {
return "The space-separated list of the SSL protocols to be used when connecting to the JMX agent.";
} else if (prop.equals(AGENT_SSL_CIPHERS_NAME)) {
return "The space-separated list of the SSL ciphers to be used when connecting to the JMX Agent.";
} else if (prop.equals(AGENT_SSL_REQUIRE_AUTHENTICATION_NAME)) {
return "Whether or not SSL connections to the RMI adapter require authentication. If true, needs client authentication for RMI and other non-HTTP connectors/adaptors.";
} else if (prop.equals(HTTP_SSL_REQUIRE_AUTHENTICATION_NAME)) {
return "Whether SSL connections to the HTTP adapter will need authentication.";
} else if (prop.equals(HTTP_AUTHENTICATION_ENABLED_NAME)) {
return "Whether the HTTP adapter will use HTTP authentication.";
} else if (prop.equals(HTTP_AUTHENTICATION_USER_NAME)) {
return "The user name for authentication in the HTTP JMX adapter";
} else if (prop.equals(HTTP_AUTHENTICATION_PASSWORD_NAME)) {
return "The password for authentication in the HTTP JMX adapter";
} else if (prop.equals(PROPERTY_FILE_NAME)) {
return "Name and path of the Agent's properties file from which agent reads configuration";
} else if (prop.equals(LOCATOR_HOST_NAME)) {
return "Host on which the distributed system's locator runs";
} else if (prop.equals(LOCATOR_PORT_NAME)) {
return "Host on which the distributed system's locator runs";
} else if (prop.equals(LOCATOR_PRODUCT_DIRECTORY_NAME)) {
return "GemFire product directory used to launch a locator";
} else if (prop.equals(LOCATOR_WORKING_DIRECTORY_NAME)) {
return "Directory in which a locator will be launched";
} else if (prop.equals(LOCATOR_REMOTE_COMMAND)) {
return "Command prefix used when launching a locator";
} else if (prop.equals(LOCATOR_BIND_ADDRESS)) {
return "IP address to use when contacting locator";
} else if (prop.equals(LOCATOR_DS_PROPERTIES)) {
return "Properties for configuring a locator's distributed system";
} else if (prop.equals(EMAIL_NOTIFICATIONS_ENABLED_NAME)) {
return "Whether the e-mail notifications are enabled.";
} else if (prop.equals(EMAIL_NOTIFICATIONS_FROM_NAME)) {
return "E-mail address to be used to send e-mail notifications.";
} else if (prop.equals(EMAIL_NOTIFICATIONS_HOST_NAME)) {
return "The host name of the e-mail server to be used for sending email notification.";
} else if (prop.equals(EMAIL_NOTIFICATIONS_TO_LIST_NAME)) {
return "A comma-separated list of recipient e-mail addresses to send e-mail notifications to.";
} else if (prop.equals(STATE_SAVE_FILE_NAME)) {
return "The name(not the path) of the file to be used for saving agent state. The file is stored in the same directory in which the agent.properties file is located.";
} else {
return null;
}
}
/**
* Parses the array of command-line arguments (format: key=value) into an instance of Properties.
*
* @param args the command-line arguments to convert into a Properties
*/
private static Properties toProperties(String[] args) {
Properties props = new Properties();
// loop all args and pick out key=value pairs...
for (int i = 0; i < args.length; i++) {
// VM args...
if (args[i].startsWith("-J")) {
int eq = args[i].indexOf("=");
String key = args[i].substring(2, eq);
String value = args[i].substring(eq + 1);
System.setProperty(key, value);
} else if (args[i].indexOf(AGENT_DEBUG) > 0) {
int eq = args[i].indexOf("=");
String key = args[i].substring(2, eq);
String value = args[i].substring(eq + 1);
System.setProperty(key, value);
}
// all other args
else if (args[i].indexOf("=") > 0) {
int eq = args[i].indexOf("=");
String key = args[i].substring(0, eq);
String value = args[i].substring(eq + 1);
props.setProperty(key, value);
}
}
return props;
}
/**
* Returns the original command-line arguments.
*/
public String[] getOriginalArgs() {
return this.originalCmdLineArgs;
}
// -------------------------------------------------------------------------
// Validation methods for configuration options
// -------------------------------------------------------------------------
/**
* Makes sure that the mcast port and locators are correct and consistent.
*
* @throws IllegalArgumentException If configuration is not valid
*/
@Override
public void validate() {
super.validate();
if (this.httpPort < 0 || this.httpPort > MAX_HTTP_PORT) {
throw new IllegalArgumentException(
String.format("%s must be zero or an integer between %s and %s.",
new Object[] {HTTP_PORT_NAME, Integer.valueOf(MIN_HTTP_PORT),
Integer.valueOf(MAX_HTTP_PORT)}));
}
if (this.rmiPort < 0 || this.rmiPort > MAX_RMI_PORT) {
throw new IllegalArgumentException(
String.format("%s must be zero or an integer between %s and %s.",
new Object[] {RMI_PORT_NAME, Integer.valueOf(MIN_RMI_PORT),
Integer.valueOf(MAX_RMI_PORT)}));
}
if (this.rmiServerPort < 0 || this.rmiServerPort > MAX_RMI_PORT) {
throw new IllegalArgumentException(
String.format("%s must be zero or an integer between %s and %s.",
new Object[] {RMI_SERVER_PORT_NAME, Integer.valueOf(MIN_RMI_PORT),
Integer.valueOf(MAX_RMI_PORT)}));
}
}
/**
* Returns defaultValue if value is empty.
*/
private String validateNonEmptyString(String value, String defaultValue) {
return isEmpty(value) ? defaultValue : value;
}
/**
* Validates that systemHost can be used for an InetAddress.
*/
private String validateSystemHost(String systemHost) {
return validateHost(systemHost);
}
/**
* Returns null if productDir is empty; else converts it to File.
*/
private String validateProductDirectory(String productDir) {
if (isEmpty(productDir)) {
return null;
}
return productDir;
}
/**
* Returns true if value parses as true; null value returns defaultValue.
*/
private boolean validateBoolean(String value, boolean defaultValue) {
if (isEmpty(value)) {
return defaultValue;
}
return Boolean.valueOf(value).booleanValue();
}
// HttpAdaptor property validators...
/**
* Returns {@link org.apache.geode.admin.jmx.AgentConfig#DEFAULT_HTTP_PORT} if httpPort is empty;
* else validates that it's an integer and returns the int form.
*/
private int validateHttpPort(String val) {
if (isEmpty(val)) {
return DEFAULT_HTTP_PORT;
} else {
return validateHttpPort(Integer.parseInt(val));
}
}
/**
* Validates that httpPort is either zero or within the
* {@link org.apache.geode.admin.jmx.AgentConfig#MIN_HTTP_PORT} and
* {@link org.apache.geode.admin.jmx.AgentConfig#MAX_HTTP_PORT} values.
*/
private int validateHttpPort(int val) {
if (val < 0 || val > MAX_HTTP_PORT) {
throw new IllegalArgumentException(
String.format("%s must be zero or an integer between %s and %s.",
new Object[] {HTTP_PORT_NAME, Integer.valueOf(MIN_HTTP_PORT),
Integer.valueOf(MAX_HTTP_PORT)}));
}
return val;
}
/**
* Returns {@link org.apache.geode.admin.jmx.AgentConfig#DEFAULT_HTTP_BIND_ADDRESS} unless
* httpBindAddress can be used to create a valid InetAddress.
*/
private String validateHttpBindAddress(String val) {
String value = validateHost(val);
if (value == null) {
return DEFAULT_HTTP_BIND_ADDRESS;
} else {
return value;
}
}
/**
* Validates that httpBindAddress is not null and then returns the string form of it.
*/
private String validateHttpBindAddress(InetAddress val) {
if (val == null) {
throw new IllegalArgumentException(
"HttpBindAddress must not be null");
}
return toString("", val);
}
// SnmpAdaptor property validators...
/**
* Returns {@link org.apache.geode.admin.jmx.AgentConfig#DEFAULT_SNMP_BIND_ADDRESS} unless
* snmpBindAddress can be used to create a valid InetAddress.
*/
private String validateSnmpBindAddress(String val) {
String value = validateHost(val);
if (value == null) {
return DEFAULT_SNMP_BIND_ADDRESS;
} else {
return value;
}
}
/**
* SnmpDirectory must be specified if SNMP is enabled. This directory must also exist.
*/
private String validateSnmpDirectory(String snmpDir) {
return snmpDir;
}
// RMIConnectorServer property validators...
/**
* Returns {@link org.apache.geode.admin.jmx.AgentConfig#DEFAULT_RMI_PORT} if rmiPort is empty;
* else validates that it's an integer and returns the int form.
*/
private int validateRmiPort(String val) {
if (isEmpty(val)) {
return DEFAULT_RMI_PORT;
} else {
return validateRmiPort(Integer.parseInt(val));
}
}
/**
* Validates that rmiPort is either zero or within the
* {@link org.apache.geode.admin.jmx.AgentConfig#MIN_RMI_PORT} and
* {@link org.apache.geode.admin.jmx.AgentConfig#MAX_RMI_PORT} values.
*/
private int validateRmiPort(int val) {
if (val < MIN_RMI_PORT || val > MAX_RMI_PORT) {
throw new IllegalArgumentException(
String.format("%s must be zero or an integer between %s and %s.",
new Object[] {RMI_PORT_NAME, Integer.valueOf(MIN_RMI_PORT),
Integer.valueOf(MAX_RMI_PORT)}));
}
return val;
}
/**
* Returns {@link org.apache.geode.admin.jmx.AgentConfig#DEFAULT_RMI_SERVER_PORT} if
* rmi-server-port is empty; else validates that it's an integer within the allowed range and
* returns the int form.
*/
private int validateRmiServerPort(String val) {
if (isEmpty(val)) {
return DEFAULT_RMI_SERVER_PORT;
} else {
return validateRmiServerPort(Integer.parseInt(val));
}
}
/**
* Validates that rmiPort is either zero or within the
* {@link org.apache.geode.admin.jmx.AgentConfig#MIN_RMI_PORT} and
* {@link org.apache.geode.admin.jmx.AgentConfig#MAX_RMI_PORT} values.
*/
private int validateRmiServerPort(int val) {
if (val < MIN_RMI_PORT || val > MAX_RMI_PORT) {
throw new IllegalArgumentException(
String.format("%s must be zero or an integer between %s and %s.",
new Object[] {RMI_SERVER_PORT_NAME, Integer.valueOf(MIN_RMI_PORT),
Integer.valueOf(MAX_RMI_PORT)}));
}
return val;
}
/**
* Returns {@link org.apache.geode.admin.jmx.AgentConfig#DEFAULT_RMI_BIND_ADDRESS} unless
* rmiBindAddress can be used to create a valid InetAddress.
*/
private String validateRmiBindAddress(String val) {
String value = validateHost(val);
if (value == null) {
return DEFAULT_RMI_BIND_ADDRESS;
} else {
return value;
}
}
/**
* Validates working directory is not null or empty.
*/
private File validateWorkingDirectory(String workingDir) {
if (isEmpty(workingDir)) {
throw new IllegalArgumentException(
"Locator WorkingDirectory must not be null");
}
return new File(workingDir);
}
// -------------------------------------------------------------------------
// Static utility methods
// -------------------------------------------------------------------------
/**
* Gets an <code>URL</code> for the property file, if one can be found, that the create method
* would use to determine the systemName and product home.
* <p>
* The file will be searched for, in order, in the following locations:
* <ol>
* <li>the current directory
* <li>the home directory
* <li>the class path
* </ol>
* Only the first file found will be used.
*
* @return a <code>URL</code> that names the property file; otherwise Null if no property file was
* found.
*/
public static URL getPropertyFileURL(final String propFileLocation) {
File propFile = new File(propFileLocation);
// first, try the current directory...
if (propFile.exists()) {
propFile = IOUtils.tryGetCanonicalFileElseGetAbsoluteFile(propFile);
try {
return propFile.toURI().toURL();
} catch (java.net.MalformedURLException ignore) {
}
}
// next, try the user's home directory...
if (propFileLocation != null && propFileLocation.length() > 0) {
propFile = new File(System.getProperty("user.home"), propFileLocation);
if (propFile.exists()) {
propFile = IOUtils.tryGetCanonicalFileElseGetAbsoluteFile(propFile);
try {
return propFile.toURI().toURL();
} catch (java.net.MalformedURLException ignore) {
}
}
}
// finally, try the classpath...
return ClassPathLoader.getLatest().getResource(AgentConfigImpl.class, propFileLocation);
}
private static boolean okToDisplayPropertyValue(String attName) {
if (attName.startsWith(HTTP_AUTHENTICATION_USER_NAME)) {
return false;
}
if (attName.startsWith(HTTP_AUTHENTICATION_PASSWORD_NAME)) {
return false;
}
if (attName.startsWith(AGENT_SSL_PROTOCOLS_NAME)) {
return false;
}
if (attName.startsWith(AGENT_SSL_CIPHERS_NAME)) {
return false;
}
if (attName.toLowerCase().contains("javax.net.ssl")) {
return false;
}
if (attName.toLowerCase().contains("password")) {
return false;
}
return true;
}
/**
* Returns string representation of the specified object with special handling for InetAddress.
*
* @param obj the object to convert to string
*
* @return string representation of the specified object
*/
private static String toString(String attName, java.lang.Object obj) {
if (okToDisplayPropertyValue(attName)) {
if (obj == null) {
return "";
}
if (obj instanceof InetAddress) {
return toHostString(obj);
}
return obj.toString();
} else {
return OBFUSCATED_STRING;
}
}
/**
* Returns string representation of the int.
*/
private static String toString(String attName, int num) {
if (okToDisplayPropertyValue(attName)) {
return String.valueOf(num);
} else {
return OBFUSCATED_STRING;
}
}
/**
* Returns string representation of the boolean value.
*/
private static String toString(String attName, boolean v) {
if (okToDisplayPropertyValue(attName)) {
return String.valueOf(v);
} else {
return OBFUSCATED_STRING;
}
}
/**
* Returns true if the string is null or empty.
*/
public static boolean isEmpty(String string) {
return string == null || string.length() == 0;
}
// -------------------------------------------------------------------------
// SSL support...
// -------------------------------------------------------------------------
private boolean sslEnabled = DEFAULT_SSL_ENABLED;
private String sslProtocols = DEFAULT_SSL_PROTOCOLS;
private String sslCiphers = DEFAULT_SSL_CIPHERS;
private boolean sslAuthenticationRequired = DEFAULT_SSL_REQUIRE_AUTHENTICATION;
private Properties sslProperties = new Properties();
@Override
public boolean isSSLEnabled() {
return this.sslEnabled;
}
@Override
public void setSSLEnabled(boolean enabled) {
this.sslEnabled = enabled;
configChanged();
}
@Override
public String getSSLProtocols() {
return this.sslProtocols;
}
@Override
public void setSSLProtocols(String protocols) {
this.sslProtocols = protocols;
configChanged();
}
@Override
public String getSSLCiphers() {
return this.sslCiphers;
}
@Override
public void setSSLCiphers(String ciphers) {
this.sslCiphers = ciphers;
configChanged();
}
@Override
public boolean isSSLAuthenticationRequired() {
return this.sslAuthenticationRequired;
}
@Override
public void setSSLAuthenticationRequired(boolean authRequired) {
this.sslAuthenticationRequired = authRequired;
configChanged();
}
@Override
public Properties getSSLProperties() {
return this.sslProperties;
}
@Override
public void setSSLProperties(Properties sslProperties) {
this.sslProperties = sslProperties;
if (this.sslProperties == null) {
this.sslProperties = new Properties();
}
configChanged();
}
@Override
public String getStateSaveFile() {
return this.stateSaveFile;
}
@Override
public void setStateSaveFile(String file) {
checkReadOnly();
this.stateSaveFile = file;
configChanged();
}
@Override
public boolean isEmailNotificationEnabled() {
return this.isEmailNotificationEnabled;
}
@Override
public void setEmailNotificationEnabled(boolean enabled) {
checkReadOnly();
this.isEmailNotificationEnabled = enabled;
configChanged();
}
@Override
public String getEmailNotificationFrom() {
return this.emailNotificationFrom;
}
@Override
public void setEmailNotificationFrom(String emailID) {
this.emailNotificationFrom = emailID;
configChanged();
}
@Override
public String getEmailNotificationHost() {
return this.emailNotificationHostName;
}
@Override
public void setEmailNotificationHost(String hostName) {
this.emailNotificationHostName = hostName;
configChanged();
}
@Override
public String getEmailNotificationToList() {
return this.emailNotificationToList;
}
@Override
public void setEmailNotificationToList(String emailIDs) {
this.emailNotificationToList = emailIDs;
configChanged();
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}