/***********************************************************
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.codec.domain;

import java.util.Vector;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.verisign.epp.codec.gen.EPPAuthInfo;
import com.verisign.epp.codec.gen.EPPCodecException;
import com.verisign.epp.codec.gen.EPPCreateCmd;
import com.verisign.epp.codec.gen.EPPDecodeException;
import com.verisign.epp.codec.gen.EPPEncodeException;
import com.verisign.epp.codec.gen.EPPFactory;
import com.verisign.epp.codec.gen.EPPUtil;


/**
 * Represents an EPP Domain &lt;create&gt; command, which provides a transform
 * operation that allows a client to create a domain object. In addition to the
 * standard EPP command elements, the &lt;create&gt; command MUST contain a
 * &lt;domain:create&gt; element that identifies the domain namespace and the
 * location of the domain schema. The &lt;domain:create&gt; element MUST contain
 * the following child elements: <br>
 * <br>
 *
 * <ul>
 * <li>A &lt;domain:name&gt; element that contains the fully qualified domain
 * name of the object to be created. Use {@code getName} and {@code setName} to
 * get and set the element.</li>
 * <li>An OPTIONAL &lt;domain:period&gt; element that contains the initial
 * registration period of the domain object. Use {@code getPeriod} and
 * {@code setPeriod} to get and set the element. If return {@code null}, period
 * has not been specified yet.</li>
 * <li>Zero or more &lt;domain:ns&gt; elements that contain the fully qualified
 * host name of a known host object to provide resolution services for the
 * domain. A host object MUST be known to the server before a domain can be
 * delegated to the host. A server MUST provide host object services to provide
 * domain name services. The EPP mapping for host objects is described in
 * [EPP-H]. Use {@code getServers} and {@code setServers} to get and set the
 * elements.</li>
 * <li>An OPTIONAL &lt;domain:registrant&gt; element that contains the
 * identifier for the human or organizational social information (contact)
 * object to be associated with the domain object as the object registrant. This
 * object identifier MUST be known to the server before the contact object can
 * be associated with the domain object. Use {@code getRegistrant} and
 * {@code setRegistrant} to get and set the elements.</li>
 * <li>Zero or more &lt;domain:contact&gt; elements that contain the registrant,
 * administrative, technical, and billing contact identifiers to be associated
 * with the domain. A contact identifier MUST be known to the server before the
 * contact can be associated with the domain. Only one contact identifier of
 * each type MAY be specified. A server MAY provide contact object services when
 * providing domain name object services. The EPP mapping for contact objects is
 * described in [EPP-C]. Use {@code getContacts} and {@code setContacts} to get
 * and set the elements. Contacts should only be specified if the Contact
 * Mapping is supported.</li>
 * <li>A &lt;domain:authInfo&gt; element that contains authorization information
 * to be associated with the domain object.</li>
 * </ul>
 *
 * <br>
 * It is important to note that the transaction identifier associated with
 * successful creation of a domain object becomes the authorization identifier
 * required to transfer sponsorship of the domain object. A client MUST retain
 * all transaction identifiers associated with domain object creation and
 * protect them from disclosure. A client MUST also provide a copy of the
 * transaction identifier information to the domain registrant, who will need
 * this information to request a domain transfer through a different client.
 * <br>
 * <br>
 * {@code EPPDomainCreateResp} is the concrete {@code EPPReponse} associated
 * with {@code EPPDomainCreateCmd}.<br>
 * <br>
 *
 * @see com.verisign.epp.codec.domain.EPPDomainCreateResp
 */
public class EPPDomainCreateCmd extends EPPCreateCmd {
	/**
	 * XML local name for {@code EPPDomainCreateCmd}.
	 */
	public static final String ELM_LOCALNAME = "create";

	/**
	 * XML Element Name of {@code EPPDomainCreateCmd} root element.
	 */
	public static final String ELM_NAME = EPPDomainMapFactory.NS_PREFIX + ":" + ELM_LOCALNAME;

	/** XML Element Name of {@code EPPDomainCreateCmd} root element. */
	final static String ELM_REGISTRANT = "registrant";

	/** XML Element Name for the {@code name} attribute. */
	private final static String ELM_DOMAIN_NAME = "name";

	/** XML tag name for the {@code servers} attribute. */
	private final static String ELM_SERVER = "ns";

	/** XML tag name for host object reference */
	private final static String ELM_HOST_OBJ = "hostObj";

	/** XML tag name for host attribute */
	private final static String ELM_HOST_ATTR = EPPHostAttr.ELM_NAME;

	/** XML tag name for the {@code contacts} attribute. */
	private final static String ELM_CONTACT = "contact";

	/** Category for logging */
	    private static Logger cat = LoggerFactory.getLogger(EPPDomainCreateCmd.class);
	      

	/** Domain Name of domain to create. */
	private String name = null;

	/** Registration Period. */
	private EPPDomainPeriod period = null;

	/** Domain Name Server Names */
	private Vector<String> servers = null;

	/**
	 * name server attributes.
	 */
	private Vector<EPPHostAttr> serverAttrs = null;

	/** Domain Contacts */
	private Vector<EPPDomainContact> contacts = null;

	/** authorization information. */
	private EPPAuthInfo authInfo = null;

	/** registrant. */
	private String registrant = null;

	/**
	 * Allocates a new {@code EPPDomainCreateCmd} with default attribute values.
	 * the defaults include the following: <br>
	 * <br>
	 *
	 * <ul>
	 * <li>name is set to {@code null}</li>
	 * <li>period is set to {@code UNSPEC_PERIOD}</li>
	 * <li>servers is set to to {@code null}</li>
	 * <li>contacts is set to to {@code null}</li>
	 * <li>transaction id is set to {@code null}.</li>
	 * </ul>
	 *
	 * <br>
	 * The name must be set before invoking {@code encode}.
	 */
	public EPPDomainCreateCmd() {
		this.name = null;
		this.period = null;
		this.servers = null;
		this.contacts = null;
	}

	/**
	 * Allocates a new {@code EPPDomainCreateCmd} with a domain name. The other
	 * attributes are initialized as follows: <br>
	 * <br>
	 *
	 * <ul>
	 * <li>period is set to {@code UNSPEC_PERIOD}</li>
	 * <li>servers is set to {@code null}</li>
	 * <li>contacts is set to {@code null}</li>
	 * </ul>
	 *
	 *
	 * @param aTransId
	 *           Transaction Id associated with command.
	 * @param aName
	 *           Domain name
	 * @param aAuthInfo
	 *           EPPAuthInfo authorization information
	 */
	public EPPDomainCreateCmd(String aTransId, String aName, EPPAuthInfo aAuthInfo) {
		super(aTransId);

		this.name = aName;
		this.authInfo = aAuthInfo;
		this.authInfo.setRootName(EPPDomainMapFactory.NS, EPPDomainMapFactory.ELM_DOMAIN_AUTHINFO);
		this.period = null;
		this.servers = null;
		this.contacts = null;
	}

	/**
	 * Allocates a new {@code EPPDomainCreateCmd} with all attributes specified
	 * by the arguments.
	 *
	 * @param aTransId
	 *           Transaction Id associated with command.
	 * @param aName
	 *           Domain name
	 * @param aServers
	 *           Domain name servers names. Set to {@code null} if undefined.
	 * @param aContacts
	 *           Domain contacts. Should be {@code null} if the Contact Mapping
	 *           is not supported.
	 * @param aPeriod
	 *           Value greater than or equal to {@code MIN_PERIOD} or less than
	 *           or equal to {@code MAX_PERIOD}.
	 * @param aAuthInfo
	 *           EPPAuthInfo authorization information.
	 */
	public EPPDomainCreateCmd(String aTransId, String aName, Vector<String> aServers, Vector<EPPDomainContact> aContacts,
	      EPPDomainPeriod aPeriod, EPPAuthInfo aAuthInfo) {
		super(aTransId);

		this.name = aName;
		this.period = aPeriod;
		this.servers = aServers;
		this.contacts = aContacts;
		this.authInfo = aAuthInfo;
		this.authInfo.setRootName(EPPDomainMapFactory.NS, EPPDomainMapFactory.ELM_DOMAIN_AUTHINFO);
	}

	/**
	 * Get the EPP command Namespace associated with EPPDomainCreateCmd.
	 *
	 * @return {@code EPPDomainMapFactory.NS}
	 */
	@Override
	public String getNamespace() {
		return EPPDomainMapFactory.NS;
	}

	/**
	 * Validate the state of the {@code EPPDomainCreateCmd} instance. A valid
	 * state means that all of the required attributes have been set. If
	 * validateState returns without an exception, the state is valid. If the
	 * state is not valid, the {@code EPPCodecException} will contain a
	 * description of the error. throws EPPCodecException State error. This will
	 * contain the name of the attribute that is not valid.
	 *
	 * @throws EPPCodecException
	 *            On invalid state
	 */
	void validateState() throws EPPCodecException {
		// Domain name
		if (this.name == null) {
			throw new EPPCodecException("name required attribute is not set");
		}

		// AuthInfo
		if (this.authInfo == null) {
			throw new EPPCodecException("authInfo required attribute is not set");
		}

		if (this.hasServers() && this.hasServerAttrs()) {
			throw new EPPCodecException("both name server objects and attributes are defined");
		}

	}

	/**
	 * Get the domain name to create.
	 *
	 * @return Domain Name
	 */
	public String getName() {
		return this.name;
	}

	/**
	 * Set the domain name to create.
	 *
	 * @param aName
	 *           Domain Name
	 */
	public void setName(String aName) {
		this.name = aName;
	}

	/**
	 * Are there name servers set?
	 * 
	 * @return {@code true} if name servers have been set; {@code false}
	 *         otherwise.
	 */
	public boolean hasServers() {
		return (this.servers != null ? !this.servers.isEmpty() : false);
	}

	/**
	 * Gets the name servers. The name servers can either be {@code String}
	 * instances containing the fully qualified name of a known name server host
	 * object, or {@code EPPHostAttr} instances containing the fully qualified
	 * name of a host and optionally the host IP addresses.
	 *
	 * @return {@code Vector} of name server {@code String} instances for host
	 *         object references or {@code EPPHostAttr} instances for host
	 *         attribute values if exists; {@code null} otherwise.
	 */
	public Vector<String> getServers() {
		return this.servers;
	}

	/**
	 * Sets the name servers. The name servers can either be {@code String}
	 * instances containing the fully qualified name of a known name server host
	 * object, or {@code EPPHostAttr} instances containing the fully qualified
	 * name of a host and optionally the host IP addresses.
	 *
	 * @param aServers
	 *           {@code Vector} of name server {@code String} instances for host
	 *           object references or {@code EPPHostAttr} instances for host
	 *           attribute values.
	 */
	public void setServers(Vector<String> aServers) {
		this.servers = aServers;
	}

	/**
	 * Add a name serve instance that is a fully qualified name of a known name
	 * server host object.
	 *
	 * @param aServer
	 *           Fully qualified name of a known name server host object.
	 */
	public void addServer(String aServer) {
		if (this.servers == null) {
			this.servers = new Vector();
		}

		this.servers.add(aServer);
	}

	/**
	 * Are there name server attributes set?
	 * 
	 * @return {@code true} if name server attributes have been set;
	 *         {@code false} otherwise.
	 */
	public boolean hasServerAttrs() {
		return (this.serverAttrs != null ? !this.serverAttrs.isEmpty() : false);
	}

	/**
	 * Gets the name server attributes. The name servers attributes are
	 * {@code EPPHostAttr} instances containing the fully qualified name of a
	 * host and optionally the host IP addresses.
	 *
	 * @return {@code Vector} of name server {@code EPPHostAttr} instances for
	 *         host attribute values if exists; {@code null} otherwise.
	 */
	public Vector<EPPHostAttr> getServerAttrs() {
		return this.serverAttrs;
	}

	/**
	 * Sets the name server attributes. The name servers attributes are
	 * {@code EPPHostAttr} instances containing the fully qualified name of a
	 * host and optionally the host IP addresses.
	 *
	 * @param aServerAttrs
	 *           {@code Vector} of name server {@code EPPHostAttr} instances for
	 *           host attribute values.
	 */
	public void setServerAttrs(Vector<EPPHostAttr> aServerAttrs) {
		this.serverAttrs = aServerAttrs;
	}

	/**
	 * Add a name serve attribute instance that is a fully qualified name of a
	 * host and optionally the host IP addresses.
	 *
	 * @param aServerAttr
	 *           A fully qualified name of a host and optionally the host IP
	 *           addresses.
	 */
	public void addServerAttr(EPPHostAttr aServerAttr) {
		if (this.serverAttrs == null) {
			this.serverAttrs = new Vector<EPPHostAttr>();
		}

		this.serverAttrs.add(aServerAttr);
	}

	/**
	 * Are there contacts set?
	 * 
	 * @return {@code true} if contacts have been set; {@code false} otherwise.
	 */
	public boolean hasContacts() {
		return (this.contacts != null ? !this.contacts.isEmpty() : false);
	}

	/**
	 * Gets the contacts.
	 *
	 * @return {@code Vector} of {@link EPPDomainContact} instances if defined;
	 *         {@code null} otherwise.
	 */
	public Vector<EPPDomainContact> getContacts() {
		return this.contacts;
	}

	/**
	 * Sets the contacts.
	 *
	 * @param aContacts
	 *           {@code Vector} of {@link EPPDomainContact} instances.
	 */
	public void setContacts(Vector<EPPDomainContact> aContacts) {
		this.contacts = aContacts;
	}

	/**
	 * Adds a contact to the list of domain contacts.
	 *
	 * @param aContact
	 *           Contact to add to the domain.
	 */
	public void addContact(EPPDomainContact aContact) {
		if (this.contacts == null) {
			this.contacts = new Vector<EPPDomainContact>();
		}

		this.contacts.add(aContact);
	}

	/**
	 * Compare an instance of {@code EPPDomainCreateCmd} with this instance.
	 *
	 * @param aObject
	 *           Object to compare with.
	 *
	 * @return {@code true} if equal; {@code false} otherwise.
	 */
	@Override
	public boolean equals(Object aObject) {
		if (!(aObject instanceof EPPDomainCreateCmd)) {
			cat.error("EPPDomainCreateCmd.equals(): " + aObject.getClass().getName() + " not EPPDomainCreateCmd instance");

			return false;
		}

		if (!super.equals(aObject)) {
			cat.error("EPPDomainCreateCmd.equals(): super class not equal");

			return false;
		}

		EPPDomainCreateCmd theComp = (EPPDomainCreateCmd) aObject;

		// Name
		if (!((this.name == null) ? (theComp.name == null) : this.name.equals(theComp.name))) {
			cat.error("EPPDomainCreateCmd.equals(): name not equal");

			return false;
		}

		// Period
		if (!((this.period == null) ? (theComp.period == null) : this.period.equals(theComp.period))) {
			cat.error("EPPDomainCreateCmd.equals(): period not equal");

			return false;
		}

		// AuthInfo
		if (!((this.authInfo == null) ? (theComp.authInfo == null) : this.authInfo.equals(theComp.authInfo))) {
			cat.error("EPPDomainCreateCmd.equals(): authInfo not equal");

			return false;
		}

		// Domain Name Server
		if (!EPPUtil.equalVectors(this.servers, theComp.servers)) {
			cat.error("EPPDomainCreateCmd.equals(): servers not equal");

			return false;
		}
		if (!EPPUtil.equalVectors(this.serverAttrs, theComp.serverAttrs)) {
			cat.error("EPPDomainCreateCmd.equals(): serverAttrs not equal");

			return false;
		}

		// Domain Contacts
		if (EPPFactory.getInstance().hasService(EPPDomainMapFactory.NS_CONTACT)) {
			if (!EPPUtil.equalVectors(this.contacts, theComp.contacts)) {
				cat.error("EPPDomainCreateCmd.equals(): contacts not equal");

				return false;
			}
		}

		// registrant
		if (!((this.registrant == null) ? (theComp.registrant == null) : this.registrant.equals(theComp.registrant))) {
			cat.error("EPPDomainCreateCmd.equals(): registrant not equal");

			return false;
		}

		return true;
	}

	/**
	 * Clone {@code EPPDomainCreateCmd}.
	 *
	 * @return clone of {@code EPPDomainCreateCmd}
	 *
	 * @exception CloneNotSupportedException
	 *               standard Object.clone exception
	 */
	@Override
	public Object clone() throws CloneNotSupportedException {
		EPPDomainCreateCmd clone = (EPPDomainCreateCmd) super.clone();

		if (this.servers != null) {
			clone.servers = (Vector<String>) this.servers.clone();
		}

		if (this.serverAttrs != null) {
			clone.serverAttrs = (Vector<EPPHostAttr>) this.serverAttrs.clone();
		}

		if (this.contacts != null) {
			clone.contacts = (Vector<EPPDomainContact>) this.contacts.clone();

			for (int i = 0; i < this.contacts.size(); i++) {
				clone.contacts.setElementAt((EPPDomainContact) (this.contacts.elementAt(i)).clone(), i);
			}
		}

		if (this.authInfo != null) {
			clone.authInfo = (EPPAuthInfo) this.authInfo.clone();
		}

		if (this.period != null) {
			clone.period = (EPPDomainPeriod) this.period.clone();
		}

		return clone;
	}

	/**
	 * Implementation of {@code Object.toString}, which will result in an
	 * indented XML {@code String} representation of the concrete
	 * {@code EPPCodecComponent}.
	 *
	 * @return Indented XML {@code String} if successful; {@code ERROR}
	 *         otherwise.
	 */
	@Override
	public String toString() {
		return EPPUtil.toString(this);
	}

	/**
	 * Get authorization information
	 *
	 * @return EPPAuthInfo
	 */
	public EPPAuthInfo getAuthInfo() {
		return this.authInfo;
	}

	/**
	 * Gets the registration period in years.
	 *
	 * @return Registration Period in years.
	 */
	public EPPDomainPeriod getPeriod() {
		return this.period;
	}

	/**
	 * Get registrant.
	 *
	 * @return String
	 */
	public String getRegistrant() {
		return this.registrant;
	}

	/**
	 * Set authorization information
	 *
	 * @param aAuthInfo
	 *           String
	 */
	public void setAuthInfo(EPPAuthInfo aAuthInfo) {
		if (aAuthInfo != null) {
			this.authInfo = aAuthInfo;
			this.authInfo.setRootName(EPPDomainMapFactory.NS, EPPDomainMapFactory.ELM_DOMAIN_AUTHINFO);
		}
	}

	/**
	 * Sets the registration period in years.
	 *
	 * @param aPeriod
	 *           Registration Period in years.
	 */
	public void setPeriod(EPPDomainPeriod aPeriod) {
		this.period = aPeriod;
	}

	/**
	 * Set registrant.
	 *
	 * @param newRegistrant
	 *           String
	 */
	public void setRegistrant(String newRegistrant) {
		this.registrant = newRegistrant;
	}

	/**
	 * Encode a DOM Element tree from the attributes of the EPPDomainCreateCmd
	 * instance.
	 *
	 * @param aDocument
	 *           DOM Document that is being built. Used as an Element factory.
	 *
	 * @return Root DOM Element representing the EPPDomainCreateCmd instance.
	 *
	 * @exception EPPEncodeException
	 *               Unable to encode EPPDomainCreateCmd instance.
	 */
	@Override
	protected Element doEncode(Document aDocument) throws EPPEncodeException {
		try {
			// Validate States
			validateState();
		}
		catch (EPPCodecException e) {
			cat.error("EPPDomainCreateCmd.doEncode(): Invalid state on encode: " + e);
			throw new EPPEncodeException("EPPDomainCreateCmd invalid state: " + e);
		}

		Element root = aDocument.createElementNS(EPPDomainMapFactory.NS, ELM_NAME);

		// Name
		EPPUtil.encodeString(aDocument, root, this.name, EPPDomainMapFactory.NS,
		      EPPDomainMapFactory.NS_PREFIX + ":" + ELM_DOMAIN_NAME);

		// Period with Attribute of Unit
		if ((this.period != null) && !this.period.isPeriodUnspec()) {
			EPPUtil.encodeComp(aDocument, root, this.period);
		}

		// Domain Name Servers
		if (this.hasServers() || this.hasServerAttrs()) {
			Element theServersElm = aDocument.createElementNS(EPPDomainMapFactory.NS,
			      EPPDomainMapFactory.NS_PREFIX + ":" + ELM_SERVER);
			root.appendChild(theServersElm);

			// Name Server Host objects?
			if (this.hasServers()) {
				EPPUtil.encodeVector(aDocument, theServersElm, this.servers, EPPDomainMapFactory.NS,
				      EPPDomainMapFactory.NS_PREFIX + ":" + ELM_HOST_OBJ);
			}

			// Name Server Host attributes?
			else { // this.hasServerAttrs()
				EPPUtil.encodeCompVector(aDocument, theServersElm, this.serverAttrs);
			}
		}

		// Registrant
		if (this.registrant != null) {
			EPPUtil.encodeString(aDocument, root, this.registrant, EPPDomainMapFactory.NS,
			      EPPDomainMapFactory.NS_PREFIX + ":" + ELM_REGISTRANT);
		}

		// Contacts
		if (this.contacts != null) {
			if (EPPFactory.getInstance().hasService(EPPDomainMapFactory.NS_CONTACT)) {
				EPPUtil.encodeCompVector(aDocument, root, this.contacts);
			}
			else {
				throw new EPPEncodeException("Contacts specified when the Contact Mapping is not supported");
			}
		}

		// authInfo
		EPPUtil.encodeComp(aDocument, root, this.authInfo);

		return root;
	}

	/**
	 * Decode the EPPDomainCreateCmd attributes from the aElement DOM Element
	 * tree.
	 *
	 * @param aElement
	 *           Root DOM Element to decode EPPDomainCreateCmd from.
	 *
	 * @exception EPPDecodeException
	 *               Unable to decode aElement
	 */
	@Override
	protected void doDecode(Element aElement) throws EPPDecodeException {
		// Domain Name
		this.name = EPPUtil.decodeString(aElement, EPPDomainMapFactory.NS, ELM_DOMAIN_NAME);

		// Period
		this.period = (EPPDomainPeriod) EPPUtil.decodeComp(aElement, EPPDomainMapFactory.NS, EPPDomainPeriod.ELM_NAME,
		      EPPDomainPeriod.class);

		// Servers
		Element theServersElm = EPPUtil.getElementByTagNameNS(aElement, EPPDomainMapFactory.NS, ELM_SERVER);

		if (theServersElm != null) {
			Element theServerElm = EPPUtil.getFirstElementChild(theServersElm);

			if (theServerElm != null) {
				if (theServerElm.getLocalName().equals(EPPUtil.getLocalName(ELM_HOST_OBJ))) {
					this.servers = EPPUtil.decodeVector(theServersElm, EPPDomainMapFactory.NS, ELM_HOST_OBJ);
					if (this.servers.size() == 0) {
						this.servers = null;
					}
					this.serverAttrs = null;

				}
				else if (theServerElm.getLocalName().equals(EPPUtil.getLocalName(ELM_HOST_ATTR))) {
					this.serverAttrs = EPPUtil.decodeCompVector(theServersElm, EPPDomainMapFactory.NS, ELM_HOST_ATTR,
					      EPPHostAttr.class);
					if (this.serverAttrs.size() == 0) {
						this.serverAttrs = null;
					}
					this.servers = null;
				}
				else {
					throw new EPPDecodeException(
					      "EPPDomainCreateCmd.doDecode: Invalid host child element " + theServersElm.getLocalName());
				}

			}

		}

		// Registrant
		this.registrant = EPPUtil.decodeString(aElement, EPPDomainMapFactory.NS, ELM_REGISTRANT);

		// Contacts
		this.contacts = EPPUtil.decodeCompVector(aElement, EPPDomainMapFactory.NS, ELM_CONTACT, EPPDomainContact.class);

		if (this.contacts.size() == 0) {
			this.contacts = null;
		}

		// authInfo
		this.authInfo = (EPPAuthInfo) EPPUtil.decodeComp(aElement, EPPDomainMapFactory.NS,
		      EPPDomainMapFactory.ELM_DOMAIN_AUTHINFO, EPPAuthInfo.class);
	}

}
