/***********************************************************
Copyright (C) 2004 VeriSign, Inc.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library 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
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

http://www.verisign.com/nds/naming/namestore/techdocs.html
 ***********************************************************/

package com.verisign.epp.util;

import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;

import com.verisign.epp.codec.gen.EPPPollMessageFilter;
import com.verisign.epp.interfaces.EPPLoginAdapter;
import com.verisign.epp.interfaces.EPPSession;

/**
 * Utility class that contains all of the SDK environment property values.
 */
public abstract class EPPEnv extends Environment {

	/**
	 * Initialize the environment
	 *
	 * @param aConfigFileName
	 *           The config file read value pairs from
	 * @param aClassLoader
	 *           Java {@code ClassLoader} to load the configuration file
	 * @exception EPPEnvException
	 *               Error initializing the configuration settings
	 */
	public void initialize(String aConfigFileName, ClassLoader aClassLoader) throws EPPEnvException {
		String st = null;

		/** list of required properties. */
		String[] listArr = { "EPP.ServerName",

		      "EPP.ServerPort",

		      "EPP.ConTimeOut",

		      "EPP.MapFactories",

		      "EPP.ProtocolExtensions",

		      "EPP.CmdRspExtensions",

		      "EPP.ServerEventHandlers",

		      "EPP.LogMode" };

		/*
		 * Get the properties
		 */
		try {
			envInitialize(aConfigFileName, aClassLoader);
		}
		catch (EnvException myException) {
			throw new EPPEnvException("Environment Exception : (" + aConfigFileName + ") " + myException.getMessage());
		}

		/*
		 * Validate the required properties
		 */
		try {
			for (int i = 0; i < listArr.length; i++) {
				if (getEnv(listArr[i]) == null) {
					throw new EPPEnvException("EPPEnv : " + listArr[i] + " is Missing from Configuration file");
				}
			}
		}
		catch (EnvException myException) {
			throw new EPPEnvException("Environment Exception : " + myException.getMessage());
		}
	}

	/**
	 * Initialize the environment
	 *
	 * @param aConfigFileName
	 *           The configuration file to read from
	 * @exception EPPEnvException
	 *               Error initializing the configuration settings
	 */
	public void initialize(String aConfigFileName) throws EPPEnvException {
		String st = null;

		/** list of required properties. */
		String[] listArr = { "EPP.ServerName",

		      "EPP.ServerPort",

		      "EPP.ConTimeOut",

		      "EPP.MapFactories",

		      "EPP.ProtocolExtensions",

		      "EPP.CmdRspExtensions" };

		/*
		 * Get the properties
		 */
		try {
			envInitialize(aConfigFileName);
		}
		catch (EnvException myException) {
			throw new EPPEnvException("Environment Exception : (" + aConfigFileName + ") " + myException.getMessage());
		}

		/*
		 * Validate the required properties
		 */
		try {
			for (int i = 0; i < listArr.length; i++) {
				if (getEnv(listArr[i]) == null) {
					throw new EPPEnvException("EPPEnv : " + listArr[i] + " is Missing from Configuration file");
				}
			}
		}
		catch (EnvException myException) {
			throw new EPPEnvException("Environment Exception : " + myException.getMessage());
		}
	}

	/**
	 * Gets the client host name / IP address to connect from.
	 *
	 * @return Client host name / IP address if defined;{@code null} otherwise
	 */
	public static String getClientHost() {
		return Environment.getOption("EPP.ClientHost");
	}

	/**
	 * Returns the value of the EPP.ServerName property specified in the config
	 * file.
	 *
	 * @return String value for the property
	 * @exception EPPEnvException
	 *               The &quot;EPP.ServerName&quot; property does not exist.
	 */
	public static String getServerName() throws EPPEnvException {
		String st = null;

		try {
			st = Environment.getEnv("EPP.ServerName");
		}
		catch (EnvException myException) {
			throw new EPPEnvException("EPP Environment Exception : " + myException.getMessage());
		}

		return st;
	}

	/**
	 * Gets the server name to use in the EPP greeting. If not set in the
	 * configuration file, the default value of "EPP Server Stub" is returned;
	 *
	 * @return Greeting Server Name if defined; {@code "EPP Server Stub"}
	 *         otherwise.
	 */
	public static String getGreetingServerName() {
		String st = "EPP Server Stub";

		try {
			st = Environment.getEnv("EPP.GreetingServerName");
		}
		catch (EnvException myException) {
			// Do nothing, since this is not a required setting.
		}

		return st;
	}

	/**
	 * Returns the value of the EPP.ServerPort property specified in the config
	 * file.
	 *
	 * @return {@code int} value for the property
	 * @exception EPPEnvException
	 *               The &quot;EPP.ServerPort&quot; property does not exist.
	 */
	public static int getServerPort() throws EPPEnvException {
		String st = null;

		try {
			st = Environment.getEnv("EPP.ServerPort");
		}
		catch (EnvException myException) {
			throw new EPPEnvException("EPP Environment Exception : " + myException.getMessage());
		}

		return Integer.valueOf(st).intValue();
	}

	/**
	 * Returns the connection timeout in number of milliseconds specified by the
	 * &quot;EPP.ConTimeOut&quot; property in the config file.
	 *
	 * @return int value for the property
	 * @exception EPPEnvException
	 *               The &quot;EPP.ConTimeOut&quot; property does not exist.
	 */
	public static int getConTimeOut() throws EPPEnvException {
		String st = null;

		try {
			st = Environment.getEnv("EPP.ConTimeOut");
		}
		catch (EnvException myException) {
			throw new EPPEnvException("EPP Environment Exception : " + myException.getMessage());
		}

		return Integer.valueOf(st).intValue();
	}

	/**
	 * Returns the read timeout in number of milliseconds specified by the
	 * &quot;EPP.ReadTimeOut&quot; property in the config file. If the
	 * &quot;EPP.ReadTimeOut&quot; property is not set, then the
	 * &quot;EPP.ConTimeOut&quot; property is used.
	 * 
	 *
	 * @return int value for the property
	 * @exception EPPEnvException
	 *               The &quot;EPP.ReadTimeOut&quot; property and the
	 *               &quot;EPP.ConTimeOut&quot; property does not exist.
	 */
	public static int getReadTimeOut() throws EPPEnvException {
		String st = null;

		try {
			st = Environment.getOption("EPP.ReadTimeOut");

			if (st == null) {
				st = Environment.getEnv("EPP.ConTimeOut");
			}
		}
		catch (EnvException myException) {
			throw new EPPEnvException("EPP Environment Exception : " + myException.getMessage());
		}

		return Integer.valueOf(st).intValue();
	}

	/**
	 * Gets the proxy server locator {@code Class} as a {@code String} as defined
	 * by the {@code EPP.ProxyServersLcoator} property.
	 * 
	 * @return Proxy server locator {@code Class} as a {@code String}
	 * @exception EPPEnvException
	 *               The &quot;EPP.ProxyServersLocator&quot; property does not
	 *               exist.
	 */
	public static String getProxyServerLocator() throws EPPEnvException {
		String st = null;

		try {
			st = Environment.getEnv("EPP.ProxyServersLocator");
		}
		catch (EnvException ex) {
			throw new EPPEnvException("EPP Environment Exception : " + ex.getMessage());
		}

		return st;
	}

	/**
	 * Returns the list of proxy servers defined by the EPP.ProxyServers
	 * property. The format of the EPP.ProxyServers property should be:<br>
	 * <br>
	 * &lt;server name&gt;:&lt;port&gt;[,&lt;server name&gt;:&lt;port&gt;]*<br>
	 * <br>
	 * &lt;server name&gt; ::= &lt;ip&gt; | logical server name<br>
	 * &lt;ip&gt; ::= IPv4 address | [&lt;IPv6 address&gt;]<br>
	 * <br>
	 * An example of a EPP.ProxyServers value is:<br>
	 * <br>
	 * samplehost:80,[2620:74:13:3000::80]:80,192.168.10.10:88
	 *
	 * @return String value for the property
	 * @exception EPPEnvException
	 *               The &quot;EPP.ProxyServers&quot; property does not exist.
	 */
	public static String getProxyServers() throws EPPEnvException {
		String st = null;

		try {
			st = Environment.getEnv("EPP.ProxyServers");
		}
		catch (EnvException ex) {
			throw new EPPEnvException("EPP Environment Exception : " + ex.getMessage());
		}

		return st;
	}

	/**
	 * Returns whether not to randomize the proxy servers connected through. The
	 * {@code EPP.ProxyServersRandomize} configuration property is used and if it
	 * is not set the default value of {@code true} is returned.
	 * 
	 * @return {@code true} to randomize;{@code false} otherwise.
	 * @exception EPPEnvException
	 *               The &quot;EPP.ProxyServersRandomizes&quot; property does not
	 *               exist.
	 */
	public static boolean getProxyServersRandomize() throws EPPEnvException {
		String st = null;

		st = Environment.getOption("EPP.ProxyServersRandomize");

		if (st != null) {
			return Boolean.valueOf(st).booleanValue();
		}
		else {
			return true;
		}
	}

	/**
	 * Returns the value of the EPP.ClientSocketName property specified in the
	 * config file.
	 *
	 * @return String value for the property
	 * @exception EPPEnvException
	 *               The &quot;EPP.ClientSocketName&quot; property does not
	 *               exist.
	 */
	public static String getClientSocketName() throws EPPEnvException {
		String st = null;

		try {
			st = Environment.getEnv("EPP.ClientSocketName");
		}
		catch (EnvException myException) {
			throw new EPPEnvException("EPP Environment Exception : " + myException.getMessage());
		}

		return st;
	}

	/**
	 * Returns the value of the EPP.ServerSocketName property specified in the
	 * config file. This is the class that is instantiated that listens for
	 * connections.
	 *
	 * @return int value for the property
	 * @exception EPPEnvException
	 *               Error with &quot;EPP.ServerSocketName&quot; property.
	 */
	public static String getServerSocketName() throws EPPEnvException {
		String st = null;

		try {
			st = Environment.getEnv("EPP.ServerSocketName");
		}
		catch (EnvException myException) {
			throw new EPPEnvException("EPP Environment Exception : " + myException.getMessage());
		}

		return st;
	}

	/**
	 * Returns a vector of class names that are factories for each EPP Mapping.
	 * These are the values specified by the EPP.MapFactories property in the
	 * config file.
	 *
	 * @return {@code Vector} of fully qualified {@code EPPMapFactory} class
	 *         {@code Strings}.
	 * @exception EPPEnvException
	 *               Error with &quot;EPP.MapFactories&quot; property.
	 */
	public static Vector getMapFactories() throws EPPEnvException {
		Vector ret = new Vector();

		try {
			String setting = Environment.getEnv("EPP.MapFactories");

			StringTokenizer tokenizer = new StringTokenizer(setting);

			while (tokenizer.hasMoreElements()) {
				ret.addElement(tokenizer.nextElement());
			}
		}
		catch (EnvException myException) {
			throw new EPPEnvException("EPP Environment Exception : " + myException.getMessage());
		}

		return ret;
	}

	/**
	 * Returns a vector of class names that are ProtocolExtensions. These are the
	 * values specified by the EPP.ProtocolExtensions property in the config
	 * file.
	 *
	 * @return {@code Vector} of fully qualified {@code EPPProtocolExtension}
	 *         class {@code Strings}.
	 * @exception EPPEnvException
	 *               Error with &quot;EPP.ProtocolExtensions&quot; property.
	 */
	public static Vector getProtocolExtensions() throws EPPEnvException {
		Vector ret = new Vector();

		try {
			String setting = Environment.getEnv("EPP.ProtocolExtensions");

			StringTokenizer tokenizer = new StringTokenizer(setting);

			while (tokenizer.hasMoreElements()) {
				ret.addElement(tokenizer.nextElement());
			}
		}
		catch (EnvException myException) {
			throw new EPPEnvException("EPP Environment Exception : " + myException.getMessage());
		}

		return ret;
	}

	/**
	 * Returns a vector of class names that are CommandResponseExtensions. These
	 * are the values specified by the EPP.CmdRspExtensions property in the
	 * config file.
	 *
	 * @return {@code Vector} of fully qualified {@code EPPCmdRspExtensions}
	 *         class {@code Strings}.
	 * @exception EPPEnvException
	 *               Error with &quot;EPP.CmdRspExtensions&quot; property.
	 */
	public static Vector getCmdResponseExtensions() throws EPPEnvException {
		Vector ret = new Vector();

		try {
			String setting = Environment.getEnv("EPP.CmdRspExtensions");

			StringTokenizer tokenizer = new StringTokenizer(setting);

			while (tokenizer.hasMoreElements()) {
				ret.addElement(tokenizer.nextElement());
			}
		}
		catch (EnvException myException) {
			throw new EPPEnvException("EPP Environment Exception : " + myException.getMessage());
		}

		return ret;
	}

	/**
	 * Returns a vector of class names that are factories for each EPP Mapping.
	 * These are the values specified by the EPP.MapFactories property in the
	 * config file.
	 *
	 * @return {@code Vector} of fully qualified {@code EPPMapFactory} class
	 *         {@code Strings}.
	 * @exception EPPEnvException
	 *               Error with &quot;EPP.ServerEventHandlers&quot; property.
	 */
	public static Vector getServerEventHandlers() throws EPPEnvException {
		Vector ret = new Vector();

		try {
			String setting = Environment.getEnv("EPP.ServerEventHandlers");

			StringTokenizer tokenizer = new StringTokenizer(setting);

			while (tokenizer.hasMoreElements()) {
				ret.addElement(tokenizer.nextElement());
			}
		}
		catch (EnvException myException) {
			throw new EPPEnvException("EPP Environment Exception : " + myException.getMessage());
		}

		return ret;
	}

	/**
	 * Returns a vector of class names that are factories for each EPP Mapping.
	 * These are the values specified by the EPP.MapFactories property in the
	 * config file.
	 *
	 * @return {@code Vector} of fully qualified {@code EPPMapFactory} class
	 *         {@code Strings}.
	 */
	public static String getServerEPPAssembler() {
		return Environment.getOption("EPP.ServerAssembler");
	}

	/**
	 * SSL Socket Option. Returns the type of SSL protocol
	 *
	 * @return String value for the property
	 */
	public static String getSSLProtocol() {
		return Environment.getOption("EPP.SSLProtocol");
	}

	/**
	 * SSL Socket Option. Returns the SSL protocols supported.
	 *
	 * @return {@code String} array of protocols if defined; {@code null}
	 *         otherwise
	 */
	public static String[] getSSLEnabledProtocols() {
		String[] theProtocols = null;
		String thePropValue = Environment.getOption("EPP.SSLEnabledProtocols");

		// Property is defined?
		if ((thePropValue != null) && (thePropValue.length() != 0)) {
			StringTokenizer tokenizer = new StringTokenizer(thePropValue);

			int numProtocols = tokenizer.countTokens();

			theProtocols = new String[numProtocols];

			for (int i = 0; i < numProtocols; i++) {
				theProtocols[i] = tokenizer.nextToken();
			}

		}

		return theProtocols;
	}

	/**
	 * SSL Socket Option. Returns the type of KeyManager used by ssl sockets
	 *
	 * @return String value for the property
	 * @deprecated With change to JDK 1.4
	 */
	@Deprecated
	public static String getSSLKeyManager() {
		return Environment.getOption("EPP.SSLKeyManager");
	}

	/**
	 * SSL Socket Option. Returns the type of KeyStore used by ssl sockets
	 *
	 * @return String value for the property
	 */
	public static String getKeyStore() {
		return Environment.getOption("EPP.SSLKeyStore");
	}

	/**
	 * SSL Socket Option. Returns the SSL Keys filename.
	 *
	 * @return String value for the property
	 */
	public static String getSSLKeyFileName() {
		return Environment.getOption("EPP.SSLKeyFileName");
	}

	/**
	 * Gets the SSL trust store file name.
	 * 
	 * @return SSL trust store file name if defined;{@code null} otherwise.
	 */
	public static String getSSLTrustStoreFileName() {
		return Environment.getOption("EPP.SSLTrustStoreFileName");
	}

	/**
	 * Gets the SSL trust store passphrase.
	 * 
	 * @return SSL trust store passphrase if defined;{@code null} otherwise.
	 */
	public static String getSSLTrustStorePassPhrase() {
		return Environment.getOption("EPP.SSLTrustStorePassPhrase");
	}

	/**
	 * Gets the SSL debug setting with the default of &quot;none&quot;. Possible
	 * values include:<br>
	 * <br>
	 * <ul>
	 * <li>none - No debug
	 * <li>all - All debug
	 * </ul>
	 * 
	 * @return Value of javax.net.debug property if defined; &quot;none&quot;
	 *         otherwise.
	 */
	public static String getSSLDebug() {
		return Environment.getProperty("javax.net.debug", "none");
	}

	/**
	 * Gets the optional SSL enabled cipher suites
	 * 
	 * @return {@code >String} array if defined; {@code null} otherwise.
	 */
	public static String[] getSSLEnabledCipherSuites() {
		String[] theSSLEnabledCipherSuites = null;
		String theValue = Environment.getOption("EPP.SSLEnabledCipherSuites");
		// Property is defined?
		if ((theValue != null) && (theValue.length() != 0)) {
			StringTokenizer tokenizer = new StringTokenizer(theValue);

			int numSSLEnabledCipherSuites = tokenizer.countTokens();

			theSSLEnabledCipherSuites = new String[numSSLEnabledCipherSuites];

			for (int i = 0; i < numSSLEnabledCipherSuites; i++) {
				theSSLEnabledCipherSuites[i] = tokenizer.nextToken();
			}

		}

		return theSSLEnabledCipherSuites;
	}

	/**
	 * SSL Socket Option. Returns the SSL Passphrase
	 *
	 * @return String value for the property
	 */
	public static String getSSLPassPhrase() {
		return Environment.getOption("EPP.SSLPassPhrase");
	}

	/**
	 * SSL Socket Option. Returns the SSL Key Passphrase. If this property is not
	 * defined, than EPP.SSLPassPhrase should be used for both the store
	 * passphrase and the key passphrase.
	 *
	 * @return String value for the property
	 */
	public static String getSSLKeyPassPhrase() {
		return Environment.getOption("EPP.SSLKeyPassPhrase");
	}

	/**
	 * The number of Client XML Parsers to initialize in the
	 * {@code EPPXMLClientParserPool}, with a default size of 10.
	 *
	 * @return XML Server Parsers to initialize in the
	 *         {@code EPPXMLClientParserPool}
	 */
	public static int getXMLClientParserPoolSize() {
		String opt = Environment.getOption("EPP.XMLClientParserPool.size");

		if (opt == null) {
			return 10;
		}

		else {
			return Integer.valueOf(opt).intValue();
		}
	}

	/**
	 * The number of schema caching XML Parsers to initialize in the
	 * {@code EPPSchemaCachingParserPool}, with a default size of 10.
	 *
	 * @return Number of schema caching XML Parsers to initialize in the
	 *         {@code EPPSchemaCachingParserPool}
	 */
	public static int getSchemaCachingParserPoolSize() {
		String opt = Environment.getOption("EPP.SchemaCachingParserPool.size");

		if (opt == null) {
			return 10;
		}

		else {
			return Integer.valueOf(opt).intValue();
		}
	}

	/**
	 * The number of transformers to initialize in the
	 * {@code EPPTransformerPool}, with a default size of 10.
	 *
	 * @return Number of transformers to initialize in the
	 *         {@code EPPTransformerPool}
	 */
	public static int getTransformerPoolSize() {
		String opt = Environment.getOption("EPP.TransformerPool.size");

		if (opt == null) {
			return 10;
		}

		else {
			return Integer.valueOf(opt).intValue();
		}
	}

	/**
	 * The number of XML Signature Parsers to initialize in the
	 * {@code EPPXMLSignatureParserPool}, with a default size of 10.
	 *
	 * @return XML Signature Parsers to initialize in the
	 *         {@code EPPXMLSignatureParserPool}
	 */
	public static int getXMLSignatureParserPoolSize() {
		String opt = Environment.getOption("EPP.XMLSignatureParserPool.size");

		if (opt == null) {
			return 10;
		}

		else {
			return Integer.valueOf(opt).intValue();
		}
	}

	/**
	 * Returns a vector of class names that are factories for each EPP Mapping.
	 * These are the values specified by the EPP.MapFactories property in the
	 * config file.
	 *
	 * @return {@code Vector} of fully qualified {@code EPPPollHandler} class
	 *         {@code Strings}.
	 * @exception EPPEnvException
	 *               Error with &quot;EPP.PollHandlers&quot; property.
	 */
	public static Vector getPollHandlers() throws EPPEnvException {
		Vector ret = new Vector();

		try {
			String setting = Environment.getEnv("EPP.PollHandlers");

			StringTokenizer tokenizer = new StringTokenizer(setting);

			while (tokenizer.hasMoreElements()) {
				ret.addElement(tokenizer.nextElement());
			}
		}
		catch (EnvException myException) {
			// No EPP.PollHandlers setting found. This setting
			// is optional, so no exception will be re-thrown and
			// an empty Vector will be returned.
		}

		return ret;
	}

	/**
	 * Gets if XML Schema Validation is enabled. The default is {@code false},
	 * but this can be changed by setting the {@code EPP.Validating} property.
	 *
	 * @return {@code true} to enable XML Schema Validation; {@code false}
	 *         otherwise.
	 */
	public static boolean getValidating() {
		boolean ret = false;

		try {
			String setting = Environment.getEnv("EPP.Validating");

			ret = Boolean.valueOf(setting).booleanValue();

		}
		catch (EnvException myException) {
			// Do nothing, since this setting is optional
		}
		return ret;
	}

	/**
	 * Gets if FullSchemaChecking is enabled on the Xerces Parser instance.
	 * Enable full schema grammar constraint checking, including checking which
	 * may be time-consuming or memory intensive. Currently, particle unique
	 * attribution constraint checking and particle derivation resriction
	 * checking are controlled by this option. The default is {@code false}, but
	 * this can be changed by setting the {@code EPP.FullSchemaChecking}
	 * property.
	 *
	 * @return {@code true} to enable Full XML Schema Checking; {@code false}
	 *         otherwise.
	 */
	public static boolean getFullSchemaChecking() {
		boolean ret = false;
		try {
			String setting = Environment.getEnv("EPP.FullSchemaChecking");

			ret = Boolean.valueOf(setting).booleanValue();

		}
		catch (EnvException myException) {
			// Do nothing, since this setting is optional
		}
		return ret;
	}

	/**
	 * Checks if relaxed contact validation is enabled or not. If the validation
	 * is relaxed, the a special XSD with relaxed validation will be used. If set
	 * to false, RFC compliant XSD with all validations will be used. The default
	 * is {@code false}, but this can be changed by setting the
	 * {@code EPP.Contact.RelaxedValidation} property.
	 *
	 * @return {@code true} to enable relaxed contact validations; {@code false}
	 *         otherwise.
	 */
	public static boolean isContactRelaxedValidation() {
		boolean isValidationRelaxed = false;
		try {
			String isValidationRelaxedStr = Environment.getEnv("EPP.Contact.RelaxedValidation");
			isValidationRelaxed = Boolean.valueOf(isValidationRelaxedStr).booleanValue();
		}
		catch (EnvException myException) {
			// do nothing, since this flag will default to false if its not
			// explicitly given.
		}
		return isValidationRelaxed;
	}

	/**
	 * Checks if use of the entity resolver is enabled or not. If the entity
	 * resolver is enabled, the {@code EPPSchemaCachingEntityResolver} will be
	 * set in the XML parsers and will dynamically load XML schemas that have not
	 * already been loaded. If the entity resolver is not enabled, only the XML
	 * schemas pre-loaded will be included in the XML parsing. The default is
	 * {@code true}, but this can be changed by setting the
	 * {@code EPP.UseEntityResolver} property.
	 *
	 * @return {@code true} to enable use of the entity resolver; {@code false}
	 *         otherwise.
	 */
	public static boolean isUseEntityResolver() {
		boolean isUseEntityResolver = true;
		try {
			String isUseEntityResolverStr = Environment.getEnv("EPP.UseEntityResolver");
			isUseEntityResolver = Boolean.valueOf(isUseEntityResolverStr).booleanValue();
		}
		catch (EnvException myException) {
			// do nothing, since this flag will default to true if its not
			// explicitly given.
		}
		return isUseEntityResolver;
	}

	/**
	 * Get the {@code EPPSendReceiveLogger} to use for logging packets being sent
	 * or received. The default is to use {@link EPPRawSendReceiveLogger} if not
	 * overridden with the "EPP.SendReceiveLogger" property.
	 * 
	 * @return {@link EPPSendReceiveLogger} instance to use with the default of
	 *         {@link EPPRawSendReceiveLogger}.
	 */
	public static EPPSendReceiveLogger getSendReceiveLogger() {
		EPPSendReceiveLogger theSendReceiveLogger = new EPPRawSendReceiveLogger();

		// Override the default EPPSendReceiveLogger?
		String theSendReceiveLoggerStr = Environment.getProperty("EPP.SendReceiveLogger");
		if (theSendReceiveLoggerStr != null) {
			try {
				theSendReceiveLogger = (EPPSendReceiveLogger) Class.forName(theSendReceiveLoggerStr)
				      .getDeclaredConstructor().newInstance();
			}
			catch (Exception ex) {
				// Ignore error, it will use the default
				// com.verisign.epp.util.EPPRawSendReceiveLogger
			}
		}

		return theSendReceiveLogger;
	}

	/**
	 * Get the {@code EPPLoginAdapter} based on the optional "EPP.LoginAdapter"
	 * property. If the property is not set, there will be no assigned
	 * {@code EPPLoginAdapter}.
	 * 
	 * @return {@link EPPLoginAdapter} instance to use when establishing an
	 *         {@link EPPSession} if defined; {@code null} otherwise.
	 */
	public static EPPLoginAdapter getLoginAdapter() {

		EPPLoginAdapter theLoginAdapter = null;

		String theLoginAdapterStr = Environment.getProperty("EPP.LoginAdapter");
		if (theLoginAdapterStr != null) {
			try {
				theLoginAdapter = (EPPLoginAdapter) Class.forName(theLoginAdapterStr).getDeclaredConstructor()
				      .newInstance();
			}
			catch (Exception ex) {
				// Ignore error, no Login Adapter will be set if there is an issue.
			}
		}

		return theLoginAdapter;
	}

	/**
	 * Checks if inclusion of the login security extension user agent is enabled
	 * or not. The default is {@code true}, but this can be changed by setting
	 * the {@code EPP.UseUserAgent} property to {@code false}.
	 *
	 * @return {@code true} to enable use of the login security extension user
	 *         agent; {@code false} otherwise.
	 */
	public static boolean isUseUserAgent() {
		boolean isUseUserAgent = true;
		try {
			String isUseUserAgentStr = Environment.getEnv("EPP.UseUserAgent");
			isUseUserAgent = Boolean.valueOf(isUseUserAgentStr).booleanValue();
		}
		catch (EnvException myException) {
			// do nothing, since this flag will default to true if its not
			// explicitly given.
		}
		return isUseUserAgent;
	}

	/**
	 * Returns the value of the {@code EPP.SDKVersion} property specified in the
	 * epp.config file.
	 *
	 * @return Value of the {@code EPP.SDKVersion} property if defined;
	 *         {@code null} otherwise.
	 */
	public static String getSDKVersion() {
		return Environment.getOption("EPP.SDKVersion");
	}

	/**
	 * Get the {@code EPPPollMessageFilter} based on the optional
	 * "EPP.PollMessageFilter" property. If the property is not set, there will
	 * be no assigned {@code EPPPollMessageFilter}.
	 * 
	 * @return {@link EPPPollMessageFilter} instance to use returning poll
	 *         messages based on the client login services.
	 */
	public static EPPPollMessageFilter getPollMessageFilter() {

		EPPPollMessageFilter thePollMessageFilter = null;

		String thePollMessageFilterStr = Environment.getProperty("EPP.PollMessageFilter");
		if (thePollMessageFilterStr != null) {
			try {
				thePollMessageFilter = (EPPPollMessageFilter) Class.forName(thePollMessageFilterStr)
				      .getDeclaredConstructor().newInstance();
			}
			catch (Exception ex) {
				// Ignore error, no Poll Message Filter will be set if there is an
				// issue.
			}
		}

		return thePollMessageFilter;
	}

	/**
	 * Returns a list of Registry Policy Adapter class names using the
	 * "EPP.RegistryPolicyAdapters" property, which each must implement the
	 * {@code com.verisign.epp.framework.EPPRegistryPolicyAdapter} class.
	 *
	 * @return List of fully qualified
	 *         {@code com.verisign.epp.framework.EPPRegistryPolicyAdapter} class
	 *         names if defined; {@code null} otherwise.
	 */
	public static List<String> getRegistryPolicyAdapters() {

		String setting = Environment.getOption("EPP.RegistryPolicyAdapters");

		// Undefined?
		if (setting == null) {
			return null;
		}

		// Tokenize the property
		List<String> theAdapters = new ArrayList<String>();

		StringTokenizer tokenizer = new StringTokenizer(setting);

		while (tokenizer.hasMoreElements()) {
			theAdapters.add((String) tokenizer.nextElement());
		}

		return theAdapters;
	}

}
