/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at
* trunk/opends/resource/legal-notices/OpenDS.LICENSE
* or https://OpenDS.dev.java.net/OpenDS.LICENSE.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at
* trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
* add the following below this CDDL HEADER, with the fields enclosed
* by brackets "[]" replaced with your own identifying * information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Portions Copyright 2006 Sun Microsystems, Inc.
*/
package org.opends.server.protocols.jmx;
import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.loggers.Debug.debugConstructor;
import static org.opends.server.loggers.Debug.debugEnter;
import static org.opends.server.loggers.Debug.debugException;
import static org.opends.server.loggers.Error.logError;
import static org.opends.server.messages.ConfigMessages.*;
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.messages.ProtocolMessages.*;
import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import org.opends.server.api.AlertGenerator;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.ConfigAddListener;
import org.opends.server.api.ConfigChangeListener;
import org.opends.server.api.ConfigDeleteListener;
import org.opends.server.api.ConfigurableComponent;
import org.opends.server.api.ConnectionHandler;
import org.opends.server.api.KeyManagerProvider;
import org.opends.server.config.BooleanConfigAttribute;
import org.opends.server.config.ConfigAttribute;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.config.IntegerConfigAttribute;
import org.opends.server.config.StringConfigAttribute;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DN;
import org.opends.server.types.ErrorLogCategory;
import org.opends.server.types.ErrorLogSeverity;
import org.opends.server.types.HostPort;
import org.opends.server.types.InitializationException;
import org.opends.server.types.ResultCode;
/**
* This class defines a connection handler that will be used for
* communicating with administrative clients over JMX. The connection
* handler is responsible for accepting new connections, reading requests
* from the clients and parsing them as operations. A single request
* handler should be used.
*/
public class JmxConnectionHandler
extends ConnectionHandler implements ConfigurableComponent,
ConfigChangeListener, ConfigDeleteListener, ConfigAddListener,
AlertGenerator
{
/**
* The fully-qualified name of this class for debugging purposes.
*/
private static final String CLASS_NAME =
"org.opends.server.protocols.jmx.JMXConnectionHandler";
/**
* The DN of the configuration entry for this connection handler.
*/
private DN configEntryDN;
/**
* The RDN of the key Manager, if exists.
* TODO Should we move this 'static' definition into another file?
*/
private final static String KeyManagerRDN = "cn=Key Manager Provider";
/**
* Indicates whether this connection handler is enabled.
*/
protected boolean enabled;
/**
* The attribute which whether this connection handler is enabled.
*/
BooleanConfigAttribute enabledAtt;
/**
* Indicates whether to use SSL to communicate with the clients.
*/
protected boolean useSSL;
/**
* The attribute which indicates whether to use SSL to communicate with
* the clients.
*/
BooleanConfigAttribute useSslAtt;
/**
* The nickname of the SSL certificate that should be used if SSL is
* enabled.
*/
protected String sslServerCertNickname;
/**
* The attribute which represents the nickname of the SSL certificate
* that should be used if SSL is enabled.
*/
StringConfigAttribute sslServerCertNickNameAtt;
/**
* The unique name assigned to this connection handler.
*/
private String handlerName;
/**
* The JMX RMI Connector associated with the Connection handler.
*/
protected RmiConnector rmiConnector;
/**
* The port on which this connection handler should listen for
* requests.
*/
protected int listenPort;
/**
* The attibute which represents the port on which this connection
* handler should listen for requests.
*/
private IntegerConfigAttribute listenPortAtt;
/**
* The key manager to used for encryption.
*/
protected KeyManagerProvider jmxKeyManager;
/**
* Key that may be placed into a JMX connection environment map to
* provide a custom javax.net.ssl.TrustManager array for
* a connection.
*/
public static final String TRUST_MANAGER_ARRAY_KEY =
"org.opends.server.protocol.jmx.ssl.trust.manager.array";
/**
* Configuration attributes that are associated
* with this configurable component.
*
*/
private LinkedList configAttrs =
new LinkedList();
/**
* The unique name for this connection handler.
*/
protected String connectionHandlerName;
/**
* The protocol used to communicate with clients.
*/
protected String protocol;
/**
* The set of listeners for this connection handler.
*/
protected LinkedList listeners = new LinkedList();
/**
* The list of active client connection.
*/
protected LinkedList connectionList =
new LinkedList();
/**
* Creates a new instance of this JMX connection handler. It must be
* initialized before it may be used.
*/
public JmxConnectionHandler()
{
super("JMX Connection Handler Thread");
assert debugConstructor(CLASS_NAME);
// No real implementation is required. Do all the work in the
// initializeConnectionHandler method.
}
/**
* Indicates whether the configuration entry that will result from a
* proposed add is acceptable to this add listener.
*
* Up to now, only a keyManager could be added under the JMX
* Connector.
*
* @param configEntry
* The configuration entry that will result from the
* requested add.
* @param unacceptableReason
* A buffer to which this method can append a human-readable
* message explaining why the proposed entry is not
* acceptable.
* @return true if the proposed entry contains an
* acceptable configuration, or false if it does
* not.
*/
public boolean configAddIsAcceptable(
ConfigEntry configEntry, StringBuilder unacceptableReason)
{
assert debugEnter(CLASS_NAME, "configAddIsAcceptable");
//
// First check if we already have a key manager. If yes, this means
// that the enter is already here and cannot be added ...
if (jmxKeyManager != null)
{
return false;
}
// Check if it's the correct DN:
// - Only child "key manager" is registered
// - We should have no more than one child under the JMX connection
// handler ...
DN JmxKeymanagerDN = null;
try
{
JmxKeymanagerDN = DN.decode(KeyManagerRDN + ", " + this.configEntryDN);
}
catch (Exception e)
{
return false;
}
if (!(JmxKeymanagerDN.equals(configEntry.getDN())))
{
return false;
}
//
// return part: all other cases are valid
return true;
}
/**
* Attempts to apply a new configuration based on the provided added
* entry.
*
* @param configEntry
* The new configuration entry that contains the
* configuration to apply.
* @return Information about the result of processing the configuration
* change.
*/
public ConfigChangeResult applyConfigurationAdd(ConfigEntry configEntry)
{
assert debugEnter(CLASS_NAME, "applyConfigurationAdd");
jmxKeyManager = getJmxKeyManager(configEntry);
//
// Ok, we have a key manager and if we have to use SSL, just do it.
if (useSSL)
{
applyNewConfiguration(listenPort, useSSL, sslServerCertNickname);
}
return new ConfigChangeResult(ResultCode.SUCCESS, false);
}
/**
* Indicates whether it is acceptable to remove the provided
* configuration entry.
*
* @param configEntry
* The configuration entry that will be removed from the
* configuration.
* @param unacceptableReason
* A buffer to which this method can append a human-readable
* message explaining why the proposed delete is not
* acceptable.
* @return true if the proposed entry may be removed
* from the configuration, or false if not.
*/
public boolean configDeleteIsAcceptable(
ConfigEntry configEntry, StringBuilder unacceptableReason)
{
//
// We can allow to remove the key manager only if we don't use it.
if (useSSL)
{
return false;
}
else
{
return true;
}
}
/**
* Attempts to apply a new configuration based on the provided deleted
* entry.
*
* @param configEntry
* The new configuration entry that has been deleted.
* @return Information about the result of processing the configuration
* change.
*/
public ConfigChangeResult applyConfigurationDelete(ConfigEntry configEntry)
{
//
// Just set the key manager to null
jmxKeyManager = null;
return new ConfigChangeResult(ResultCode.SUCCESS, false);
}
/**
* Indicates whether the configuration entry that will result from a
* proposed modification is acceptable to this change listener.
*
* @param configEntry
* The configuration entry that will result from the
* requested update.
* @param unacceptableReason
* A buffer to which this method can append a human-readable
* message explaining why the proposed change is not
* acceptable.
* @return true if the proposed entry contains an
* acceptable configuration, or false if it does
* not.
*/
public boolean configChangeIsAcceptable(
ConfigEntry configEntry, StringBuilder unacceptableReason)
{
//
// We are checking first if we are dealing with a change
// in the current entry.
// Always return true as the check will be performed by the
// hasAcceptableConfiguration call
if (configEntry.getDN().equals(configEntryDN))
{
return true;
}
//
// Then, we are checking that a change in the key manager
// is acceptable.
if (useSSL)
{
return false;
}
else
{
return true;
}
}
/**
* Attempts to apply a new configuration to this Directory Server
* component based on the provided changed entry.
*
* @param configEntry
* The configuration entry that containing the updated
* configuration for this component.
* @return Information about the result of processing the configuration
* change.
*/
public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry)
{
//
// We are checking first if we are dealing with a change
// in the current entry.
if (configEntry.getDN().equals(configEntryDN))
{
ArrayList messages = new ArrayList();
return new ConfigChangeResult(ResultCode.SUCCESS, false, messages);
}
//
// Only child "key manager" are registered
jmxKeyManager = getJmxKeyManager(configEntry);
return new ConfigChangeResult(ResultCode.SUCCESS, false);
}
/**
* Initializes this connection handler based on the information in the
* provided configuration entry.
*
* @param configEntry
* The configuration entry that contains the information to
* use to initialize this connection handler.
* @throws ConfigException
* If there is a problem with the configuration for this
* connection handler.
* @throws InitializationException
* If a problem occurs while attempting to initialize this
* connection handler.
*/
public void initializeConnectionHandler(ConfigEntry configEntry)
throws ConfigException, InitializationException
{
assert debugEnter(CLASS_NAME, "initializeConnectionHandler", String
.valueOf(configEntry));
//
// If the initializeConnectionHandler method is called,
// it means that the "enabled" attribure was true.
enabledAtt = getEnabledAtt(configEntry);
configAttrs.add(enabledAtt);
enabled = enabledAtt.activeValue();
//
// Set the entry DN
configEntryDN = configEntry.getDN();
//
// Determine the port on which to listen. There should be a single
// port specified.
listenPortAtt = getListenPort(configEntry);
configAttrs.add(listenPortAtt);
listenPort = listenPortAtt.activeIntValue();
//
// Determine whether to use SSL.
useSslAtt = getUseSSL(configEntry);
configAttrs.add(useSslAtt);
useSSL = useSslAtt.activeValue();
//
// Determine which SSL certificate to use.
sslServerCertNickNameAtt = getServerCertNickname(configEntry);
configAttrs.add(sslServerCertNickNameAtt);
sslServerCertNickname = sslServerCertNickNameAtt.activeValue();
//
// At this point, we have a configuration entry. Register a change
// listener with it so we can be notified of changes to it over
// time.
// We will also want to register a delete and add listeners with
// its parent.
configEntry.registerDeleteListener(this);
configEntry.registerChangeListener(this);
configEntry.registerAddListener(this);
//
// Get the KeyManager, if specified.
if (useSSL)
{
ConfigEntry keyManagerConfigEntry;
try
{
DN KeyManagerDN = DN.decode(KeyManagerRDN + ", " + configEntryDN);
keyManagerConfigEntry = DirectoryServer.getConfigEntry(KeyManagerDN);
jmxKeyManager = getJmxKeyManager(keyManagerConfigEntry);
}
catch (Exception e)
{
assert debugException(CLASS_NAME, "initializeKeyManagerProvider", e);
logError(
ErrorLogCategory.CONFIGURATION,
ErrorLogSeverity.SEVERE_ERROR,
MSGID_CONFIG_KEYMANAGER_CANNOT_GET_CONFIG_ENTRY,
stackTraceToSingleLineString(e));
configEntry.registerAddListener(this);
jmxKeyManager = null;
}
}
else
{
jmxKeyManager = null;
}
// Create the associated RMI Connector
rmiConnector = new RmiConnector(DirectoryServer.getJMXMBeanServer(), this);
//
// Register this JMX ConnectionHandler as an MBean
DirectoryServer.registerConfigurableComponent(this);
//
// Check if we have a correct SSL configuration
if ((useSSL && jmxKeyManager == null))
{
//
// TODO : give a more useful feedback message
logError(
ErrorLogCategory.CONFIGURATION,
ErrorLogSeverity.SEVERE_WARNING,
MSGID_CONFIG_KEYMANAGER_NO_ENABLED_ATTR);
int msgID = MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_USE_SSL;
String message = getMessage(msgID, String.valueOf(configEntryDN), "");
throw new InitializationException(msgID, message);
}
if (useSSL)
{
protocol = "JMX+SSL";
}
else
{
protocol = "JMX";
}
listeners.clear();
listeners.add(new HostPort("0.0.0.0", listenPort));
connectionHandlerName = "JMX Connection Handler "+ listenPort;
}
/**
* Closes this connection handler so that it will no longer accept new
* client connections. It may or may not disconnect existing client
* connections based on the provided flag.
*
* @param finalizeReason
* The reason that this connection handler should be
* finalized.
* @param closeConnections
* Indicates whether any established client connections
* associated with the connection handler should also be
* closed.
*/
public void finalizeConnectionHandler(
String finalizeReason, boolean closeConnections)
{
assert debugEnter(CLASS_NAME, "finalizeConnectionHandler");
// We should also close the RMI registry.
rmiConnector.finalizeConnectionHandler(closeConnections, true);
}
/**
* {@inheritDoc}
*/
public String getConnectionHandlerName()
{
assert debugEnter(CLASS_NAME, "getConnectionHandlerName");
return connectionHandlerName;
}
/**
* {@inheritDoc}
*/
public String getProtocol()
{
assert debugEnter(CLASS_NAME, "getProtocol");
return protocol;
}
/**
* {@inheritDoc}
*/
public Collection getListeners()
{
assert debugEnter(CLASS_NAME, "getListeners");
return listeners;
}
/**
* Retrieves the set of active client connections that have been
* established through this connection handler.
*
* @return The set of active client connections that have been
* established through this connection handler.
*/
public Collection getClientConnections()
{
assert debugEnter(CLASS_NAME, "getClientConnections");
return connectionList;
}
/**
* Start the JMX RMI Connector.
*/
public void run()
{
rmiConnector.initialize();
}
/**
* Retrieves the human-readable name for this shutdown listener.
*
* @return The human-readable name for this shutdown listener.
*/
public String getShutdownListenerName()
{
assert debugEnter(CLASS_NAME, "getShutdownListenerName");
return handlerName;
}
/**
* Indicates that the Directory Server has received a request to stop
* running and that this shutdown listener should take any action
* necessary to prepare for it.
*
* @param reason
* The human-readable reason for the shutdown.
*/
public void processServerShutdown(String reason)
{
assert debugEnter(CLASS_NAME, "processServerShutdown");
// We should also close the RMI registry.
rmiConnector.finalizeConnectionHandler(true, true);
}
/**
* Retrieves the DN of the configuration entry with which this
* component is associated.
*
* @return The DN of the configuration entry with which this component
* is associated.
*/
public DN getConfigurableComponentEntryDN()
{
assert debugEnter(CLASS_NAME, "getConfigurableComponentEntryDN");
return configEntryDN;
}
/**
* Retrieves the set of configuration attributes that are associated
* with this configurable component.
*
* @return The set of configuration attributes that are associated with
* this configurable component.
*/
public List getConfigurationAttributes()
{
assert debugEnter(CLASS_NAME, "getConfigurationAttributes");
return configAttrs;
}
/**
* Indicates whether the provided configuration entry has an acceptable
* configuration for this component. If it does not, then detailed
* information about the problem(s) should be added to the provided
* list.
*
* @param configEntry
* The configuration entry for which to make the
* determination.
* @param unacceptableReasons
* A list that can be used to hold messages about why the
* provided entry does not have an acceptable configuration.
* @return true if the provided entry has an acceptable
* configuration for this component, or false if
* not.
*/
public boolean hasAcceptableConfiguration(
ConfigEntry configEntry, List unacceptableReasons)
{
assert debugEnter(CLASS_NAME, "hasAcceptableConfiguration", String
.valueOf(configEntry), "java.util.List");
boolean configValid = true;
//
// Determine the port on which to listen.
try
{
getListenPort(configEntry);
}
catch (Exception e)
{
int msgID = MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_LISTEN_PORT;
unacceptableReasons.add(getMessage(
msgID,
String.valueOf(configEntryDN),
stackTraceToSingleLineString(e)));
configValid = false;
}
//
// Determine whether to use SSL.
try
{
boolean newUseSSL = getUseSSL(configEntry).activeValue();
if (newUseSSL && (jmxKeyManager == null))
{
//
// TODO Set an appropriate message (instead of null)
int msgID = MSGID_JMX_CONNHANDLER_DESCRIPTION_USE_SSL;
unacceptableReasons.add(getMessage(msgID, String
.valueOf(configEntryDN), null));
configValid = false;
}
}
catch (Exception e)
{
int msgID = MSGID_JMX_CONNHANDLER_DESCRIPTION_USE_SSL;
unacceptableReasons.add(getMessage(
msgID,
String.valueOf(configEntryDN),
stackTraceToSingleLineString(e)));
configValid = false;
}
//
// Determine which SSL certificate to use.
try
{
getServerCertNickname(configEntry);
}
catch (Exception e)
{
configValid = false;
assert debugException(CLASS_NAME, "hasAcceptableConfiguration", e);
int msgID = MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_SSL_CERT_NICKNAME;
unacceptableReasons.add(getMessage(
msgID,
String.valueOf(configEntryDN),
stackTraceToSingleLineString(e)));
}
//
// return part
return configValid;
}
/**
* Makes a best-effort attempt to apply the configuration contained in
* the provided entry. Information about the result of this processing
* should be added to the provided message list. Information should
* always be added to this list if a configuration change could not be
* applied. If detailed results are requested, then information about
* the changes applied successfully (and optionally about parameters
* that were not changed) should also be included.
*
* @param configEntry
* The entry containing the new configuration to apply for
* this component.
* @param detailedResults
* Indicates whether detailed information about the
* processing should be added to the list.
* @return Information about the result of the configuration update.
*/
public ConfigChangeResult applyNewConfiguration(
ConfigEntry configEntry, boolean detailedResults)
{
assert debugEnter(CLASS_NAME, "applyNewConfiguration", String
.valueOf(configEntry), String.valueOf(detailedResults));
//
// Create variables to include in the response.
ResultCode resultCode = ResultCode.SUCCESS;
boolean rmiConnectorRestart = false;
ArrayList messages = new ArrayList();
//
// Determine the port on which to listen.
int newListenPort = listenPort;
try
{
if ((newListenPort = getListenPort(configEntry).activeIntValue())
!= listenPort)
{
rmiConnectorRestart = true;
}
}
catch (Exception e)
{
int msgID = MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_LISTEN_PORT;
messages.add(getMessage(
msgID,
String.valueOf(configEntryDN),
stackTraceToSingleLineString(e)));
resultCode = DirectoryServer.getServerErrorResultCode();
}
//
// Determine whether to use SSL.
boolean newUseSSL = useSSL;
try
{
if ((newUseSSL = getUseSSL(configEntry).activeValue()) != useSSL)
{
rmiConnectorRestart = true;
}
}
catch (Exception e)
{
int msgID = MSGID_JMX_CONNHANDLER_DESCRIPTION_USE_SSL;
messages.add(getMessage(
msgID,
String.valueOf(configEntryDN),
stackTraceToSingleLineString(e)));
resultCode = DirectoryServer.getServerErrorResultCode();
}
//
// Determine which SSL certificate to use.
String newSslServerCertNickname = sslServerCertNickname;
try
{
if ((newSslServerCertNickname = getServerCertNickname(configEntry)
.activeValue()) != sslServerCertNickname)
{
rmiConnectorRestart = true;
}
}
catch (Exception e)
{
assert debugException(CLASS_NAME, "applyNewConfiguration", e);
int msgID = MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_SSL_CERT_NICKNAME;
messages.add(getMessage(
msgID,
String.valueOf(configEntryDN),
stackTraceToSingleLineString(e)));
resultCode = DirectoryServer.getServerErrorResultCode();
}
//
// Apply new config, best effort mode
if (rmiConnectorRestart)
{
applyNewConfiguration(
newListenPort,
newUseSSL,
newSslServerCertNickname);
}
//
// return part
return new ConfigChangeResult(resultCode, false, messages);
}
/**
* Apply the configuration.
*
* @param newListenPort
* the new listen port
* @param newUseSSL
* Indicates if we should use ssl
* @param newSslServerCertNickname
* Indicates the new server certificate nickname
*/
private void applyNewConfiguration(
int newListenPort, boolean newUseSSL, String newSslServerCertNickname)
{
//
// Stop the current connector
// TODO Set Msg
this.rmiConnector.finalizeConnectionHandler(true,
(listenPort != newListenPort));
//
// set new params and update JMX attributes
if (listenPort != newListenPort)
{
try
{
listenPortAtt.setValue(newListenPort);
listenPort = newListenPort;
}
catch (Exception e)
{
// TODO
// Print error message
}
}
if (useSSL != newUseSSL)
{
useSSL = newUseSSL;
useSslAtt.setValue(newUseSSL);
}
if (sslServerCertNickname != newSslServerCertNickname)
{
try
{
sslServerCertNickNameAtt.setValue(newSslServerCertNickname);
sslServerCertNickname = newSslServerCertNickname;
}
catch (Exception e)
{
// TODO
// Print error message
}
}
if (useSSL)
{
protocol = "JMX+SSL";
}
else
{
protocol = "JMX";
}
listeners.clear();
listeners.add(new HostPort(listenPort));
//
// Start the new RMI Connector
rmiConnector.initialize();
}
/**
* Appends a string representation of this connection handler to the
* provided buffer.
*
* @param buffer
* The buffer to which the information should be appended.
*/
public void toString(StringBuilder buffer)
{
assert debugEnter(CLASS_NAME, "toString", "java.lang.StringBuilder");
buffer.append(handlerName);
}
/**
* Retrieves the DN of the configuration entry with which this alert
* generator is associated.
*
* @return The DN of the configuration entry with which this alert
* generator is associated.
*/
public DN getComponentEntryDN()
{
assert debugEnter(CLASS_NAME, "getComponentEntryDN");
return configEntryDN;
}
/**
* Retrieves the fully-qualified name of the Java class for this alert
* generator implementation.
*
* @return The fully-qualified name of the Java class for this alert
* generator implementation.
*/
public String getClassName()
{
assert debugEnter(CLASS_NAME, "getClassName");
return CLASS_NAME;
}
/**
* Retrieves information about the set of alerts that this generator
* may produce. The map returned should be between the notification
* type for a particular notification and the human-readable
* description for that notification. This alert generator must not
* generate any alerts with types that are not contained in this list.
*
* @return Information about the set of alerts that this generator may
* produce.
*/
public LinkedHashMap getAlerts()
{
assert debugEnter(CLASS_NAME, "getAlerts");
LinkedHashMap alerts = new LinkedHashMap();
return alerts;
}
/**
* Retrieves the enabled attribure from the configuration entry with
* which this component is associated.
*
* @param configEntry
* The configuration entry for which to make the determination.
* @return The enabled attribute
* @throws ConfigException
* If there is a problem with the configuration for this
* connection handler.
* @throws InitializationException
* If a problem occurs while attempting to initialize this
* connection handler.
*/
private BooleanConfigAttribute getEnabledAtt(ConfigEntry configEntry)
throws InitializationException, ConfigException
{
int msgID = MSGID_CONFIG_CONNHANDLER_ATTR_DESCRIPTION_ENABLED;
BooleanConfigAttribute enabledStub =
new BooleanConfigAttribute(ATTR_CONNECTION_HANDLER_ENABLED,
getMessage(msgID), false);
BooleanConfigAttribute attr = null;
try
{
attr = (BooleanConfigAttribute) configEntry
.getConfigAttribute(enabledStub);
if (attr == null)
{
msgID = MSGID_CONFIG_CONNHANDLER_NO_ENABLED_ATTR;
String message = getMessage(msgID, String.valueOf(configEntryDN));
throw new ConfigException(msgID, message);
}
}
catch (ConfigException ce)
{
assert debugException(CLASS_NAME, "initializeConnectionHandler", ce);
throw ce;
}
catch (Exception e)
{
assert debugException(CLASS_NAME, "initializeConnectionHandler", e);
msgID = MSGID_CONFIG_CONNHANDLER_NO_ENABLED_ATTR;
String message = getMessage(
msgID,
String.valueOf(configEntryDN),
stackTraceToSingleLineString(e));
throw new InitializationException(msgID, message, e);
}
return attr;
}
/**
* Retrieves the listen port of the configuration entry with which this
* component is associated.
*
* @param configEntry
* The configuration entry for which to make the
* determination.
* @return The listen port
*
* @throws ConfigException
* If there is a problem with the configuration for this
* connection handler.
* @throws InitializationException
* If a problem occurs while attempting to initialize this
* connection handler.
*/
private IntegerConfigAttribute getListenPort(ConfigEntry configEntry)
throws InitializationException, ConfigException
{
int msgID = MSGID_JMX_CONNHANDLER_DESCRIPTION_LISTEN_PORT;
IntegerConfigAttribute portStub = new IntegerConfigAttribute(
ATTR_LISTEN_PORT, getMessage(msgID), true, false, false, true, 1,
true, 65535);
IntegerConfigAttribute portAttr = null;
try
{
portAttr = (IntegerConfigAttribute) configEntry
.getConfigAttribute(portStub);
if (portAttr == null)
{
msgID = MSGID_JMX_CONNHANDLER_NO_LISTEN_PORT;
String message = getMessage(msgID, String.valueOf(configEntryDN));
throw new ConfigException(msgID, message);
}
}
catch (ConfigException ce)
{
assert debugException(CLASS_NAME, "initializeConnectionHandler", ce);
throw ce;
}
catch (Exception e)
{
assert debugException(CLASS_NAME, "initializeConnectionHandler", e);
msgID = MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_LISTEN_PORT;
String message = getMessage(
msgID,
String.valueOf(configEntryDN),
stackTraceToSingleLineString(e));
throw new InitializationException(msgID, message, e);
}
return portAttr;
}
/**
* Determine if the specified Configuration entry defines the
* use-ssl attribute.
* @param configEntry The entry to check
* @return true if we should use SSL, else false
* @throws InitializationException
* If a problem occurs while attempting to get the entry
* useSSL attribute
*/
private BooleanConfigAttribute getUseSSL(ConfigEntry configEntry)
throws InitializationException
{
//
// Determine whether to use SSL.
int msgID = MSGID_JMX_CONNHANDLER_DESCRIPTION_USE_SSL;
BooleanConfigAttribute useSSLStub = new BooleanConfigAttribute(
ATTR_USE_SSL, getMessage(msgID), false);
BooleanConfigAttribute useSSLAttr = null;
try
{
useSSLAttr = (BooleanConfigAttribute) configEntry
.getConfigAttribute(useSSLStub);
if (useSSLAttr == null)
{
//
// This is fine -- we'll just use the default value.
useSSLAttr = new BooleanConfigAttribute(ATTR_USE_SSL,
getMessage(msgID), false, DEFAULT_USE_SSL, DEFAULT_USE_SSL);
}
}
catch (Exception e)
{
assert debugException(CLASS_NAME, "initializeConnectionHandler", e);
msgID = MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_USE_SSL;
String message = getMessage(
msgID,
String.valueOf(configEntryDN),
stackTraceToSingleLineString(e));
throw new InitializationException(msgID, message, e);
}
return useSSLAttr;
}
/**
* Determine if the specified Configuration entry defines the
* server certificate nickname.
* @param configEntry The entry to check
* @return The server certificate nickname
* @throws InitializationException
* If a problem occurs while attempting to get the entry
* certificate nickname
*/
private StringConfigAttribute getServerCertNickname(ConfigEntry configEntry)
throws InitializationException
{
int msgID = MSGID_JMX_CONNHANDLER_DESCRIPTION_SSL_CERT_NICKNAME;
StringConfigAttribute certNameStub = new StringConfigAttribute(
ATTR_SSL_CERT_NICKNAME, getMessage(msgID), false, false, false);
StringConfigAttribute certNameAttr = null;
try
{
certNameAttr = (StringConfigAttribute) configEntry
.getConfigAttribute(certNameStub);
if (certNameAttr == null)
{
//
// This is fine -- we'll just use the default.
certNameAttr = new StringConfigAttribute(ATTR_SSL_CERT_NICKNAME,
getMessage(msgID), false, false, false, DEFAULT_SSL_CERT_NICKNAME);
}
return certNameAttr;
}
catch (Exception e)
{
assert debugException(CLASS_NAME, "initializeConnectionHandler", e);
msgID = MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_SSL_CERT_NICKNAME;
String message = getMessage(
msgID,
String.valueOf(configEntryDN),
stackTraceToSingleLineString(e));
throw new InitializationException(msgID, message, e);
}
}
/**
* Retrieve the KeyManager configured for the JMX Connection handler.
* With look for the child config entry (We should have no more than
* one child entry)
*
* @param jmxConnectorDN the DN of the associated JMX connector
* entry
*
* @return the configured key manager if set or the server
* key manager
*/
private KeyManagerProvider getJmxKeyManager(
ConfigEntry keyManagerConfigEntry)
{
//
// Get the key manager provider configuration entry. If it is not
// present, then register an add listener.
boolean shouldReturnNull = false;
if (keyManagerConfigEntry == null)
{
logError(
ErrorLogCategory.CONFIGURATION,
ErrorLogSeverity.SEVERE_WARNING,
MSGID_CONFIG_KEYMANAGER_NO_CONFIG_ENTRY);
return null;
}
//
// See if the entry indicates whether the key manager provider
// should be enabled.
int msgID = MSGID_CONFIG_KEYMANAGER_DESCRIPTION_ENABLED;
BooleanConfigAttribute enabledStub = new BooleanConfigAttribute(
ATTR_KEYMANAGER_ENABLED, getMessage(msgID), false);
try
{
BooleanConfigAttribute enabledAttr = (BooleanConfigAttribute)
keyManagerConfigEntry.getConfigAttribute(enabledStub);
if (enabledAttr == null)
{
//
// The attribute is not present, so the key manager
// provider will be disabled.
// Log a warning message and return.
// FIXME -- Message shouldn't be the same than the server one
logError(
ErrorLogCategory.CONFIGURATION,
ErrorLogSeverity.SEVERE_WARNING,
MSGID_CONFIG_KEYMANAGER_NO_ENABLED_ATTR);
shouldReturnNull = true;
}
else if (!enabledAttr.activeValue())
{
//
// The key manager provider is explicitly disabled. Log a
// mild warning and return.
// FIXME -- Message shouldn't be the same than the server one
logError(
ErrorLogCategory.CONFIGURATION,
ErrorLogSeverity.MILD_WARNING,
MSGID_CONFIG_KEYMANAGER_DISABLED);
shouldReturnNull = true;
}
}
catch (Exception e)
{
assert debugException(CLASS_NAME, "initializeKeyManagerProvider", e);
// FIXME -- Message shouldn't be the same than the server one
logError(
ErrorLogCategory.CONFIGURATION,
ErrorLogSeverity.SEVERE_ERROR,
MSGID_CONFIG_KEYMANAGER_UNABLE_TO_DETERMINE_ENABLED_STATE,
stackTraceToSingleLineString(e));
return null;
}
//
// See if it specifies the class name for the key manager provider
// implementation.
String className;
msgID = MSGID_CONFIG_KEYMANAGER_DESCRIPTION_CLASS;
StringConfigAttribute classStub = new StringConfigAttribute(
ATTR_KEYMANAGER_CLASS, getMessage(msgID), true, false, false);
try
{
StringConfigAttribute classAttr = (StringConfigAttribute)
keyManagerConfigEntry.getConfigAttribute(classStub);
if (classAttr == null)
{
// FIXME -- Message shouldn't be the same than the server one
logError(
ErrorLogCategory.CONFIGURATION,
ErrorLogSeverity.SEVERE_ERROR,
MSGID_CONFIG_KEYMANAGER_NO_CLASS_ATTR);
return null;
}
else
{
className = classAttr.activeValue();
}
}
catch (Exception e)
{
assert debugException(CLASS_NAME, "initializeKeyManagerProvider", e);
// FIXME Message shouldn't be the same than the server one
logError(
ErrorLogCategory.CONFIGURATION,
ErrorLogSeverity.SEVERE_ERROR,
MSGID_CONFIG_KEYMANAGER_CANNOT_DETERMINE_CLASS,
stackTraceToSingleLineString(e));
return null;
}
//
// Try to load the class and instantiate it as a key manager
// provider.
Class keyManagerProviderClass;
try
{
// FIXME -- Should we use a custom class loader for this?
keyManagerProviderClass = Class.forName(className);
}
catch (Exception e)
{
assert debugException(CLASS_NAME, "initializeKeyManagerProvider", e);
// FIXME -- Message shouldn't be the same than the server one
logError(
ErrorLogCategory.CONFIGURATION,
ErrorLogSeverity.SEVERE_ERROR,
MSGID_CONFIG_KEYMANAGER_CANNOT_LOAD_CLASS,
String.valueOf(className),
stackTraceToSingleLineString(e));
return null;
}
KeyManagerProvider keyManagerProvider;
try
{
keyManagerProvider = (KeyManagerProvider) keyManagerProviderClass
.newInstance();
}
catch (Exception e)
{
assert debugException(CLASS_NAME, "initializeKeyManagerProvider", e);
// FIXME -- Message shouldn't be the same than the server one
logError(
ErrorLogCategory.CONFIGURATION,
ErrorLogSeverity.SEVERE_ERROR,
MSGID_CONFIG_KEYMANAGER_CANNOT_INSTANTIATE_CLASS,
String.valueOf(className),
stackTraceToSingleLineString(e));
return null;
}
//
// Try to initialize the key manager provider with the contents of
// the configuration entry.
try
{
keyManagerProvider.initializeKeyManagerProvider(keyManagerConfigEntry);
}
catch (Exception e)
{
assert debugException(CLASS_NAME, "initializeKeyManagerProvider", e);
// FIXME -- Message shouldn't be the same than the server one
logError(
ErrorLogCategory.CONFIGURATION,
ErrorLogSeverity.SEVERE_WARNING,
MSGID_CONFIG_KEYMANAGER_CANNOT_INITIALIZE,
String.valueOf(className),
e.getMessage());
return null;
}
if (shouldReturnNull)
{
return null;
}
else
{
return keyManagerProvider;
}
}
}