/*
 * RHQ Management Platform
 * Copyright (C) 2005-2008 Red Hat, Inc.
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
package org.rhq.enterprise.server.core.comm;

import java.io.File;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;

import mazz.i18n.Logger;

import org.rhq.enterprise.communications.ServiceContainerConfiguration;
import org.rhq.enterprise.communications.command.client.ClientCommandSenderConfiguration;
import org.rhq.enterprise.communications.command.client.PersistentFifo;
import org.rhq.enterprise.communications.command.client.RemoteInputStream;

/**
 * Just provides some convienence methods to extract server configuration properties. The bulk of the server
 * configuration really is just the {@link ServiceContainerConfiguration}, with some additional client-side type
 * preferences to support {@link RemoteInputStream remote streaming}.
 *
 * @author John Mazzitelli
 */
public class ServerConfiguration {
    /**
     * Logger
     */
    private static final Logger LOG = ServerI18NFactory.getLogger(ServerConfiguration.class);

    /**
     * The server configuration properties this object wraps. This should be the server preferences node.
     */
    private final Preferences m_preferences;

    /**
     * Wraps a preferences object in this instance.
     *
     * @param  prefs the configuration preferences
     *
     * @throws IllegalArgumentException if props is <code>null</code>
     */
    public ServerConfiguration(Preferences prefs) {
        if (prefs == null) {
            throw new IllegalArgumentException("prefs=null");
        }

        m_preferences = prefs;
    }

    /**
     * Returns the raw preferences containing the server configuration.
     *
     * @return the server configuration preferences
     */
    public Preferences getPreferences() {
        return m_preferences;
    }

    /**
     * Returns the service container configuration object that provides strongly typed methods to retrieve the
     * server-side communications preferences.
     *
     * @return server-side communications preferences
     */
    public ServiceContainerConfiguration getServiceContainerPreferences() {
        return new ServiceContainerConfiguration(m_preferences);
    }

    /**
     * Returns the version of the configuration schema.
     *
     * @return configuration version; if the configuration isn't versioned, 0 is returned
     */
    public int getServerConfigurationVersion() {
        int value = m_preferences.getInt(ServerConfigurationConstants.CONFIG_SCHEMA_VERSION, 0);

        return value;
    }

    /**
     * This tags the existing preferences by setting the configuration schema version preference appropriately.
     */
    public void tagWithServerConfigurationVersion() {
        m_preferences.putInt(ServerConfigurationConstants.CONFIG_SCHEMA_VERSION,
            ServerConfigurationConstants.CURRENT_CONFIG_SCHEMA_VERSION);
    }

    /**
     * Returns the data directory where all internally persisted data can be written to. If the data directory does not
     * exist, it will be created. The data directory is the one that is defined in the
     * {@link #getServiceContainerPreferences() service container configuration}. See
     * {@link ServiceContainerConfiguration#getDataDirectory()}.
     *
     * <p>Because this does alittle extra work, it may not be suitable to call if you just want to get the value of the
     * data directory or if you just want to know if its defined or not. In those instances, use
     * {@link #getDataDirectoryIfDefined()} instead.</p>
     *
     * @return the data directory
     */
    public File getDataDirectory() {
        return getServiceContainerPreferences().getDataDirectory();
    }

    /**
     * This will return the data directory string as found in the preferences. If the data directory is not defined in
     * the preferences, <code>null</code> is returned. The data directory is the one that is defined in the
     * {@link #getServiceContainerPreferences() service container configuration}. See
     * {@link ServiceContainerConfiguration#getDataDirectoryIfDefined()}.
     *
     * @return the data directory string as defined in the preferences or <code>null</code> if it is not defined
     *
     * @see    #getDataDirectory()
     */
    public String getDataDirectoryIfDefined() {
        return getServiceContainerPreferences().getDataDirectoryIfDefined();
    }

    /**
     * This will return the directory name where the server stores all the files it can distribute to its agents. If
     * this directory is not defined, <code>null</code> is returned. If <code>null</code> is returned, the server is not
     * configured to distribute any files remotely.
     *
     * @return the directory string as defined in the preferences or <code>null</code> if it is not defined
     */
    public String getAgentFilesDirectory() {
        String dir_str = m_preferences.get(ServerConfigurationConstants.AGENT_FILES_DIRECTORY, null);

        return dir_str;
    }

    /**
     * Returns the client sender queue size which determines how many commands can be queued up for sending. If this is
     * 0 or less, it means the queue is unbounded.
     *
     * @return queue size
     *
     * @see    #getClientCommandSenderConfiguration()
     */
    public int getClientSenderQueueSize() {
        int value = m_preferences.getInt(ServerConfigurationConstants.CLIENT_SENDER_QUEUE_SIZE,
            ServerConfigurationConstants.DEFAULT_CLIENT_SENDER_QUEUE_SIZE);

        return value;
    }

    /**
     * Returns the maximum number of concurrent commands that the client sender will send at any one time.
     *
     * @return max concurrent value
     *
     * @see    #getClientCommandSenderConfiguration()
     */
    public int getClientSenderMaxConcurrent() {
        int value = m_preferences.getInt(ServerConfigurationConstants.CLIENT_SENDER_MAX_CONCURRENT,
            ServerConfigurationConstants.DEFAULT_CLIENT_SENDER_MAX_CONCURRENT);

        if (value < 1) {
            LOG.warn(ServerI18NResourceKeys.PREF_MUST_BE_GREATER_THAN_0,
                ServerConfigurationConstants.CLIENT_SENDER_MAX_CONCURRENT, value,
                ServerConfigurationConstants.DEFAULT_CLIENT_SENDER_MAX_CONCURRENT);

            value = ServerConfigurationConstants.DEFAULT_CLIENT_SENDER_MAX_CONCURRENT;
        }

        return value;
    }

    /**
     * Returns the default timeout that the client sender will wait for a command to be processed by the remote
     * endpoint. The timeout may be less than or equal to zero in which case the default will be to never timeout
     * commands.
     *
     * @return timeout in milliseconds
     *
     * @see    #getClientCommandSenderConfiguration()
     */
    public long getClientSenderCommandTimeout() {
        long value = m_preferences.getLong(ServerConfigurationConstants.CLIENT_SENDER_COMMAND_TIMEOUT,
            ServerConfigurationConstants.DEFAULT_CLIENT_SENDER_COMMAND_TIMEOUT);
        return value;
    }

    /**
     * Returns the time in milliseconds the client sender should wait in between retries of commands that have failed.
     * This is a minimum but by no means is the limit before the command must be retried. The command may, in fact, be
     * retried any amount of time after this retry interval.
     *
     * @return retry interval in milliseconds
     *
     * @see    #getClientCommandSenderConfiguration()
     */
    public long getClientSenderRetryInterval() {
        long value = m_preferences.getLong(ServerConfigurationConstants.CLIENT_SENDER_RETRY_INTERVAL,
            ServerConfigurationConstants.DEFAULT_CLIENT_SENDER_RETRY_INTERVAL);

        return value;
    }

    /**
     * Returns the number of times a guaranteed message is retried, if it fails for a reason other than a "cannot
     * connect" to server.
     *
     * @return maximum number of retry attempts that will be made to send a guaranteed delivery message when it fails
     *         for some reason other than being unable to communicate with the server.
     *
     * @see    #getClientCommandSenderConfiguration()
     */
    public int getClientSenderMaxRetries() {
        int value = m_preferences.getInt(ServerConfigurationConstants.CLIENT_SENDER_MAX_RETRIES,
            ServerConfigurationConstants.DEFAULT_CLIENT_SENDER_MAX_RETRIES);

        return value;
    }

    /**
     * This will return the name of the command spool file (to be located in the
     * {@link #getDataDirectory() data directory}). If this is not defined, <code>null</code> is returned to indicate
     * that commands should not be spooled to disk (thus implicitly disabling guaranteed delivery).
     *
     * @return the command spool file name or <code>null</code> if it is not defined
     */
    public String getClientSenderCommandSpoolFileName() {
        String str = m_preferences.get(ServerConfigurationConstants.CLIENT_SENDER_COMMAND_SPOOL_FILE_NAME,
            ServerConfigurationConstants.DEFAULT_CLIENT_SENDER_COMMAND_SPOOL_FILE_NAME);

        if (str != null && str.length() == 0) {
            str = null;
        }

        return str;
    }

    /**
     * Returns an array of command spool file parameters. The first element of the array is the maximum file size
     * threshold. The second element is the purge percentage. See {@link PersistentFifo} for the meanings of these
     * settings.
     *
     * <p>Because this is a weakly typed method (i.e. you have to know what the elements in the returned array
     * represent), it is recommended that you call {@link #getClientCommandSenderConfiguration()} because it will return
     * all the configuration, including the spool file parameters, in a more strongly typed data object.</p>
     *
     * @return array of command spool file parameters
     *
     * @see    #getClientCommandSenderConfiguration()
     */
    public long[] getClientSenderCommandSpoolFileParams() {
        String value = m_preferences.get(ServerConfigurationConstants.CLIENT_SENDER_COMMAND_SPOOL_FILE_PARAMS,
            ServerConfigurationConstants.DEFAULT_CLIENT_SENDER_COMMAND_SPOOL_FILE_PARAMS);

        long[] ret_params = isClientSenderCommandSpoolFileParamsValueValid(value);

        return ret_params;
    }

    /**
     * Given a command spool file parameters value, will determine if its valid or not. If its valid, its individual
     * parameter values are returned. If not valid, <code>null</code> is returned.
     *
     * @param  pref_value the command spool file parameters value
     *
     * @return the individual parameters values or <code>null</code> if not valid
     */
    public long[] isClientSenderCommandSpoolFileParamsValueValid(String pref_value) {
        long[] ret_params = null;

        try {
            String[] numbers = pref_value.split("\\s*:\\s*");
            if (numbers.length == 2) {
                ret_params = new long[2];
                ret_params[0] = Long.parseLong(numbers[0]);
                ret_params[1] = Long.parseLong(numbers[1]);

                if (ret_params[0] < 10000L) {
                    throw new NumberFormatException(LOG
                        .getMsgString(ServerI18NResourceKeys.COMMAND_SPOOL_INVALID_MAX_SIZE));
                }

                if ((ret_params[1] < 0L) || (ret_params[1] >= 100L)) {
                    throw new NumberFormatException(LOG
                        .getMsgString(ServerI18NResourceKeys.COMMAND_SPOOL_INVALID_PURGE_PERCENTAGE));
                }
            } else {
                throw new NumberFormatException(LOG.getMsgString(ServerI18NResourceKeys.COMMAND_SPOOL_INVALID_FORMAT));
            }
        } catch (Exception e) {
            ret_params = null;

            LOG.warn(ServerI18NResourceKeys.BAD_COMMAND_SPOOL_PREF,
                ServerConfigurationConstants.CLIENT_SENDER_COMMAND_SPOOL_FILE_PARAMS, pref_value, e);
        }

        return ret_params;
    }

    /**
     * Returns the command spool file compression flag that, if true, indicates the data in the command spool file
     * should be compressed.
     *
     * @return <code>true</code> if the command spool file should compress its data; <code>false</code> means the data
     *         should be stored in its uncompressed format.
     */
    public boolean isClientSenderCommandSpoolFileCompressed() {
        boolean flag = m_preferences.getBoolean(
            ServerConfigurationConstants.CLIENT_SENDER_COMMAND_SPOOL_FILE_COMPRESSED,
            ServerConfigurationConstants.DEFAULT_CLIENT_SENDER_COMMAND_SPOOL_FILE_COMPRESSED);

        return flag;
    }

    /**
     * Returns an array of send throttling parameters or <code>null</code> if send throttling is to be disabled. The
     * first element of the array is the maximum number of commands that can be sent before the quiet period must start.
     * The second element is the length of time (in milliseconds) that each quiet period lasts. Once that time period
     * expires, commands can again be sent, up to the maximum (and the cycle repeats).
     *
     * <p>Because this is a weakly typed method (i.e. you have to know what the elements in the returned array
     * represent), it is recommended that you call {@link #getClientCommandSenderConfiguration()} because it will return
     * all the configuration, including the throttling configuration, in a more strongly typed data object.</p>
     *
     * @return array of send throttling parameters, <code>null</code> if send throttling is disabled
     *
     * @see    #getClientCommandSenderConfiguration()
     */
    public long[] getClientSenderSendThrottling() {
        String value = m_preferences.get(ServerConfigurationConstants.CLIENT_SENDER_SEND_THROTTLING, null);

        long[] ret_throttling_params = isClientSenderSendThrottlingValueValid(value);

        return ret_throttling_params;
    }

    /**
     * Given a send throttling parameters value, will determine if its valid or not. If its valid, its individual
     * parameter values are returned. If not valid, <code>null</code> is returned. Note that if <code>pref_value</code>
     * is <code>null</code>, then <code>null</code> will be immediately returned.
     *
     * @param  pref_value the send throttling parameters value
     *
     * @return the individual parameters values or <code>null</code> if not valid or the preference value was <code>
     *         null</code>
     */
    public long[] isClientSenderSendThrottlingValueValid(String pref_value) {
        long[] ret_throttling_params = null;

        if (pref_value != null) {
            try {
                String[] numbers = pref_value.split("\\s*:\\s*");
                if (numbers.length == 2) {
                    ret_throttling_params = new long[2];
                    ret_throttling_params[0] = Long.parseLong(numbers[0]);
                    ret_throttling_params[1] = Long.parseLong(numbers[1]);

                    if (ret_throttling_params[0] <= 0L) {
                        throw new NumberFormatException(LOG
                            .getMsgString(ServerI18NResourceKeys.SEND_THROTTLE_INVALID_MAX));
                    }

                    if (ret_throttling_params[1] < 100L) {
                        throw new NumberFormatException(LOG.getMsgString(
                            ServerI18NResourceKeys.SEND_THROTTLE_INVALID_QUIET_PERIOD, 100L));
                    }
                } else {
                    throw new NumberFormatException(LOG
                        .getMsgString(ServerI18NResourceKeys.SEND_THROTTLE_INVALID_FORMAT));
                }
            } catch (Exception e) {
                ret_throttling_params = null;

                LOG.warn(ServerI18NResourceKeys.BAD_SEND_THROTTLE_PREF,
                    ServerConfigurationConstants.CLIENT_SENDER_SEND_THROTTLING, pref_value, e);
            }
        }

        return ret_throttling_params;
    }

    /**
     * Returns an array of queue throttling parameters or <code>null</code> if queue throttling is to be disabled. The
     * first element of the array is the maximum number of commands that can be dequeued in a burst period before the
     * client sender must pause (i.e. cannot dequeue any more commands). The second element is the length of time (in
     * milliseconds) that each burst period lasts. Once that time period expires, commands can again be dequeued, up to
     * the maximum (and the cycle repeats).
     *
     * <p>Because this is a weakly typed method (i.e. you have to know what the elements in the returned array
     * represent), it is recommended that you call {@link #getClientCommandSenderConfiguration()} because it will return
     * all the configuration, including the throttling configuration, in a more strongly typed data object.</p>
     *
     * @return array of queue throttling parameters, <code>null</code> if queue throttling is disabled
     *
     * @see    #getClientCommandSenderConfiguration()
     */
    public int[] getClientSenderQueueThrottling() {
        String value = m_preferences.get(ServerConfigurationConstants.CLIENT_SENDER_QUEUE_THROTTLING, null);

        int[] ret_throttling_params = isClientSenderQueueThrottlingValueValid(value);

        return ret_throttling_params;
    }

    /**
     * Given a queue throttling parameters value, will determine if its valid or not. If its valid, its individual
     * parameter values are returned. If not valid, <code>null</code> is returned. Note that if <code>pref_value</code>
     * is <code>null</code>, then <code>null</code> will be immediately returned.
     *
     * @param  pref_value the queue throttling parameters value
     *
     * @return the individual parameters values or <code>null</code> if not valid or the preference value was <code>
     *         null</code>
     */
    public int[] isClientSenderQueueThrottlingValueValid(String pref_value) {
        int[] ret_throttling_params = null;

        if (pref_value != null) {
            try {
                String[] numbers = pref_value.split("\\s*:\\s*");
                if (numbers.length == 2) {
                    ret_throttling_params = new int[2];
                    ret_throttling_params[0] = Integer.parseInt(numbers[0]);
                    ret_throttling_params[1] = Integer.parseInt(numbers[1]);

                    if (ret_throttling_params[0] <= 0L) {
                        throw new NumberFormatException(LOG
                            .getMsgString(ServerI18NResourceKeys.QUEUE_THROTTLE_INVALID_MAX));
                    }

                    if (ret_throttling_params[1] < 100L) {
                        throw new NumberFormatException(LOG.getMsgString(
                            ServerI18NResourceKeys.QUEUE_THROTTLE_INVALID_BURST_PERIOD, 100L));
                    }
                } else {
                    throw new NumberFormatException(LOG
                        .getMsgString(ServerI18NResourceKeys.QUEUE_THROTTLE_INVALID_FORMAT));
                }
            } catch (Exception e) {
                ret_throttling_params = null;

                LOG.warn(ServerI18NResourceKeys.BAD_QUEUE_THROTTLE_PREF,
                    ServerConfigurationConstants.CLIENT_SENDER_QUEUE_THROTTLING, pref_value, e);
            }
        }

        return ret_throttling_params;
    }

    /**
     * This is a convienence method that returns the full client sender configuration. It combines all the
     * getClientSenderXXX methods and puts all the data in the returned data object.
     *
     * @return the full client sender configuration
     */
    public ClientCommandSenderConfiguration getClientCommandSenderConfiguration() {
        ClientCommandSenderConfiguration config = new ClientCommandSenderConfiguration();

        config.defaultTimeoutMillis = getClientSenderCommandTimeout();
        config.maxConcurrent = getClientSenderMaxConcurrent();
        config.queueSize = getClientSenderQueueSize();
        config.dataDirectory = getDataDirectory();
        config.serverPollingIntervalMillis = -1;
        config.commandSpoolFileCompressData = isClientSenderCommandSpoolFileCompressed();
        config.retryInterval = getClientSenderRetryInterval();
        config.maxRetries = getClientSenderMaxRetries();
        config.commandSpoolFileName = getClientSenderCommandSpoolFileName();

        long[] cmd_spool_file_params = getClientSenderCommandSpoolFileParams();
        config.commandSpoolFileMaxSize = cmd_spool_file_params[0];
        config.commandSpoolFilePurgePercentage = (int) cmd_spool_file_params[1]; // cast is fine, we've ensured this is between 0 and 99

        int[] queue_throttling = getClientSenderQueueThrottling();
        if (queue_throttling != null) {
            config.enableQueueThrottling = true;
            config.queueThrottleMaxCommands = queue_throttling[0];
            config.queueThrottleBurstPeriodMillis = queue_throttling[1];
        } else {
            config.enableQueueThrottling = false;
        }

        long[] send_throttling = getClientSenderSendThrottling();
        if (send_throttling != null) {
            config.enableSendThrottling = true;
            config.sendThrottleMaxCommands = send_throttling[0];
            config.sendThrottleQuietPeriodDurationMillis = send_throttling[1];
        } else {
            config.enableSendThrottling = false;
        }

        // get the security settings - the client sender probably won't need these
        // these are actually set as part of the RemoteCommunicator configuration (which is passed to remoting Client)
        config.securityServerAuthMode = isClientSenderSecurityServerAuthMode();
        config.securityKeystoreFile = getClientSenderSecurityKeystoreFile();
        config.securityKeystoreType = getClientSenderSecurityKeystoreType();
        config.securityKeystoreAlgorithm = getClientSenderSecurityKeystoreAlgorithm();
        config.securityKeystorePassword = getClientSenderSecurityKeystorePassword();
        config.securityKeystoreKeyPassword = getClientSenderSecurityKeystoreKeyPassword();
        config.securityKeystoreAlias = getClientSenderSecurityKeystoreAlias();
        config.securityTruststoreFile = getClientSenderSecurityTruststoreFile();
        config.securityTruststoreType = getClientSenderSecurityTruststoreType();
        config.securityTruststoreAlgorithm = getClientSenderSecurityTruststoreAlgorithm();
        config.securityTruststorePassword = getClientSenderSecurityTruststorePassword();
        config.securitySecureSocketProtocol = getClientSenderSecuritySocketProtocol();

        return config;
    }

    /**
     * Returns the protocol used over the secure socket.
     *
     * @return protocol name
     */
    public String getClientSenderSecuritySocketProtocol() {
        String value = m_preferences.get(ServerConfigurationConstants.CLIENT_SENDER_SECURITY_SOCKET_PROTOCOL, "TLS");
        return value;
    }

    /**
     * Returns the alias to the client's key in the keystore.
     *
     * @return alias name
     */
    public String getClientSenderSecurityKeystoreAlias() {
        String value = m_preferences.get(ServerConfigurationConstants.CLIENT_SENDER_SECURITY_KEYSTORE_ALIAS, "rhq");
        return value;
    }

    /**
     * Returns the path to the keystore file. This returns a <code>String</code> as opposed to <code>File</code> since
     * some underlying remoting code may allow for this filepath to be relative to a jar inside the classloader.
     *
     * @return keystore file path
     */
    public String getClientSenderSecurityKeystoreFile() {
        String value = m_preferences.get(ServerConfigurationConstants.CLIENT_SENDER_SECURITY_KEYSTORE_FILE, null);

        if (value == null) {
            value = new File(getDataDirectory(), "keystore.dat").getAbsolutePath();
        }

        return value;
    }

    /**
     * Returns the algorithm used to manage the keys in the keystore.
     *
     * @return algorithm name
     */
    public String getClientSenderSecurityKeystoreAlgorithm() {
        String value = m_preferences.get(ServerConfigurationConstants.CLIENT_SENDER_SECURITY_KEYSTORE_ALGORITHM,
            "SunX509");
        return value;
    }

    /**
     * Returns the type of the keystore file.
     *
     * @return keystore file type
     */
    public String getClientSenderSecurityKeystoreType() {
        String value = m_preferences.get(ServerConfigurationConstants.CLIENT_SENDER_SECURITY_KEYSTORE_TYPE, "JKS");
        return value;
    }

    /**
     * Returns the password of the keystore file itself.
     *
     * @return keystore file password
     */
    public String getClientSenderSecurityKeystorePassword() {
        String value = m_preferences.get(ServerConfigurationConstants.CLIENT_SENDER_SECURITY_KEYSTORE_PASSWORD,
            "rhqpwd");
        return value;
    }

    /**
     * Returns the password to gain access to the key in the keystore. If no key password is configured, this returns
     * the {@link #getClientSenderSecurityKeystorePassword() keystore password}.
     *
     * @return password to the key
     */
    public String getClientSenderSecurityKeystoreKeyPassword() {
        String value = m_preferences.get(ServerConfigurationConstants.CLIENT_SENDER_SECURITY_KEYSTORE_KEY_PASSWORD,
            null);
        if (value == null) {
            value = getClientSenderSecurityKeystorePassword();
        }

        return value;
    }

    /**
     * Returns the path to the truststore file. This returns a <code>String</code> as opposed to <code>File</code> since
     * some underlying remoting code may allow for this filepath to be relative to a jar inside the classloader.
     *
     * @return truststore file path
     */
    public String getClientSenderSecurityTruststoreFile() {
        String value = m_preferences.get(ServerConfigurationConstants.CLIENT_SENDER_SECURITY_TRUSTSTORE_FILE, null);

        if (value == null) {
            value = new File(getDataDirectory(), "truststore.dat").getAbsolutePath();
        }

        return value;
    }

    /**
     * Returns the algorithm used to manage the keys in the truststore.
     *
     * @return algorithm name
     */
    public String getClientSenderSecurityTruststoreAlgorithm() {
        String value = m_preferences.get(ServerConfigurationConstants.CLIENT_SENDER_SECURITY_TRUSTSTORE_ALGORITHM,
            "SunX509");
        return value;
    }

    /**
     * Returns the type of the truststore file.
     *
     * @return truststore file type
     */
    public String getClientSenderSecurityTruststoreType() {
        String value = m_preferences.get(ServerConfigurationConstants.CLIENT_SENDER_SECURITY_TRUSTSTORE_TYPE, "JKS");
        return value;
    }

    /**
     * Returns the password of the truststore file itself.
     *
     * @return truststore file password
     */
    public String getClientSenderSecurityTruststorePassword() {
        String value = m_preferences.get(ServerConfigurationConstants.CLIENT_SENDER_SECURITY_TRUSTSTORE_PASSWORD, null);
        return value;
    }

    /**
     * Returns <code>true</code> if the server authentication mode is enabled. If this is enabled, it means when using
     * secure communications, the agents' certificates will be authenticated with the certificates found in the server's
     * truststore. If this is <code>false</code>, the agents do not have to authenticate themselves with a trusted
     * certificate; the server will trust any remote agent (in other words, the secure communications repo will only
     * be used for encryption and not authentication).
     *
     * @return server authenticate mode
     */
    public boolean isClientSenderSecurityServerAuthMode() {
        boolean flag = m_preferences.getBoolean(ServerConfigurationConstants.CLIENT_SENDER_SECURITY_SERVER_AUTH_MODE,
            ServerConfigurationConstants.DEFAULT_CLIENT_SENDER_SECURITY_SERVER_AUTH_MODE);
        return flag;
    }

    /**
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        StringBuffer buf = new StringBuffer(m_preferences.absolutePath());

        buf.append('[');

        try {
            String[] keys = m_preferences.keys();

            for (int i = 0; i < keys.length; i++) {
                String key = keys[i];

                buf.append(key);
                buf.append('=');
                buf.append(m_preferences.get(key, LOG.getMsgString(ServerI18NResourceKeys.UNKNOWN)));

                if ((i + 1) < keys.length) {
                    buf.append(',');
                }
            }
        } catch (BackingStoreException e) {
            buf.append(LOG.getMsgString(ServerI18NResourceKeys.CANNOT_GET_PREFERENCES, e));
        }

        buf.append(']');

        return buf.toString();
    }
}