Index: fedd/abac-src/rtml/src/edu/stanford/rt/parser/RTParser.java
===================================================================
--- fedd/abac-src/rtml/src/edu/stanford/rt/parser/RTParser.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/rtml/src/edu/stanford/rt/parser/RTParser.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,2525 @@
+package edu.stanford.rt.parser;
+
+//imports Apache Xerces API
+import org.apache.xerces.parsers.DOMParser;
+import org.xml.sax.InputSource;
+import org.w3c.dom.*;
+
+// imports XML Security PublicKey api
+import org.apache.xml.security.keys.content.keyvalues.DSAKeyValue;
+import org.apache.xml.security.keys.content.keyvalues.RSAKeyValue;
+import org.apache.xml.security.exceptions.XMLSecurityException;
+
+import java.io.*;
+import java.util.*;
+
+import edu.stanford.rt.datatype.*;
+import edu.stanford.rt.credential.*;
+import edu.stanford.rt.util.*;
+
+/**
+ * @author Ninghui Li, Sandra Qiu <br>
+ * 
+ * RTParser parses a XML-format CredentialStore document and transforms
+ * the various elements into their corresponding Java objects.
+ */
+public class RTParser implements TagNameConstants, Constants
+{
+	/** The DOM parser this transformer uses*/
+	private DOMParser parser;
+
+	/** 
+	 * Constructor for RTParser.
+	 */
+	public RTParser() throws Exception
+	{
+		parser = new DOMParser();
+		parser.setFeature(
+			"http://apache.org/xml/features/validation/schema",
+			true);
+		parser.setErrorHandler(new ParsingErrorHandler());
+	}
+
+	/**
+	 * Method createSystemDomain.
+	 *      The method for creating system domain. 
+	 *      *** Only useful for our parser.
+	 * @return ApplicationDomain
+	 * @throws Exception
+	 */
+	public synchronized ApplicationDomain createSystemDomain()
+		throws Exception
+	{
+        String spec = 
+            System.getProperty("edu.stanford.rt.SystemDomain",
+                               "C:\\rtml\\schemas\\systemSpec.xml");
+		return parseSystemDomain(new FileInputStream(new File(spec)));
+	}
+
+	/**
+	 * Method parseSystemDomain. <br>
+	 *      parses system domain from a XML input source, typically a 
+	 *      XML file. The system domain element in the source should be
+	 *      the root element.
+	 * @param in
+	 * @return ApplicationDomain
+	 * @throws Exception
+	 */
+	public synchronized ApplicationDomain parseSystemDomain(InputStream in)
+		throws Exception
+	{
+		parser.parse(new InputSource(in));
+		Document document = parser.getDocument();
+		Element root = document.getDocumentElement();
+		return transformSystemDomain(root);
+	}
+
+	/**
+	 * Method parseSystemDomain. <br>
+	 *      parses system domain from a XML input source, typically a 
+	 *      XML file. The system domain element in the source should be
+	 *      the root element.
+	 * @param in
+	 * @return CredentialDomain
+	 * @throws Exception
+	 */
+        public synchronized CredentialDomain 
+	    parseCredentialDomain(InputStream in, RTContext context) 
+	    throws Exception
+        {
+	    parser.parse(new InputSource(in));
+	    Document document = parser.getDocument();
+		Element root = document.getDocumentElement();
+		return transformCredential(root, context);
+	}
+
+
+	/**
+	 * Method transformSystemDomain.<br>
+	 *    transforms the XML element to the built-in system 
+	 *    <code>ApplicationDomain</code>.
+	 * @param root
+	 *      XML element of system domain.
+	 * @return ApplicationDomain
+	 * @throws DomainSpecException
+	 */
+	public synchronized ApplicationDomain transformSystemDomain(Element root)
+		throws DomainSpecException
+	{
+		if (!root.getTagName().equals(APP_DOMAIN_SPEC))
+			throw new DomainSpecException("Not an ApplicationDomainSpecification element.");
+		String uri = root.getAttribute(URI);
+		ApplicationDomain spec =
+			new ApplicationDomain(uri, true, null);
+		String hashID = root.getAttribute(ID);
+		if (hashID.length() == 0)
+		{
+			// compute the hashID ourselves.
+			// hashID = getHash(spec);
+		}
+		HashID id = new HashID(HashID.APPLICATION_DOMAIN, hashID);
+		spec.setHashID(id);
+		// Add XML schema date types
+		spec.addType(new TimeType("dateTime"));
+		spec.addType(new TimeType("date"));
+		spec.addType(new TimeType("time"));
+		spec.addType(new TimeType("gYear"));
+		spec.addType(new TimeType("gYearMonth"));
+		spec.addType(new TimeType("gMonth"));
+		spec.addType(new TimeType("gMonthDay"));
+		spec.addType(new TimeType("gDay"));
+		Element[] elements = RTParser.getChildElements(root);
+		for (int i = 0; i < elements.length; i++)
+		{
+			Element childEle = elements[i];
+			String childName = childEle.getTagName();
+			if (childName.equals(INTEGER_TYPE))
+			{
+				IntegerType intType =
+					transformIntegerTypeDeclaration(childEle);
+				spec.addType(intType);
+			}
+			else if (childName.equals(DECIMAL_TYPE))
+			{
+				DecimalType decimalType =
+					transformDecimalTypeDeclaration(childEle);
+				spec.addType(decimalType);
+			}
+			else if (childName.equals(STRING_TYPE))
+			{
+				StringType stringType =
+					transformStringTypeDeclaration(childEle);
+				spec.addType(stringType);
+			}
+			else if (childName.equals(ENUM_TYPE))
+			{
+				EnumType enumType =
+					transformEnumTypeDeclaration(childEle, spec);
+				spec.addType(enumType);
+			}
+			else if (childName.equals(RECORD_TYPE))
+			{
+				RecordType recordType =
+					transformRecordTypeDeclaration(childEle, spec);
+				spec.addType(recordType);
+			}
+			else if (childName.equals(TREE_TYPE))
+			{
+				TreeType treeType =
+					transformTreeTypeDeclaration(childEle);
+				spec.addType(treeType);
+			}
+		} // end of for()...
+		spec.setComplete();
+		return spec;
+	}
+
+	/**
+	 * Method getFirstChildElement.<br>
+	        Returns the first child element of ELEMENT_NODE type for the 
+	        given parent element. 
+	 * @param parent
+	 * @return Element
+	 */
+	static public Element getFirstChildElement(Element parent)
+	{
+		Element ele = null;
+		NodeList nodes = parent.getChildNodes();
+		int n = nodes.getLength();
+		for (int i = 0; i < n; i++)
+		{
+			Node node = nodes.item(i);
+			short type = node.getNodeType();
+			if (type != org.w3c.dom.Node.ELEMENT_NODE)
+				continue;
+			ele = (Element) node;
+			break;
+		}
+		return ele;
+	}
+
+	/**
+	 * Method getFirstChildElementByTagName.<br>
+	 *   returns the first child element with the given tag name.
+	 * @param parent
+	 * @param tagName
+	 * @return Element
+	 */
+	/**
+	*/
+	static public Element getFirstChildElementByTagName(
+		Element parent,
+		String tagName)
+	{
+		Element ele = null;
+		NodeList nodes = parent.getElementsByTagName(tagName);
+		ele = (Element) nodes.item(0);
+		return ele;
+	}
+
+	/**
+	 * Method getChildElements.<br>
+	 *      returns an array of child elements of ELEMNENT_NODE type.
+	 * @param parent
+	 * @return Element[]
+	 */
+	static public Element[] getChildElements(Element parent)
+	{
+		ArrayList elements = new ArrayList();
+		NodeList nodes = parent.getChildNodes();
+		int n = nodes.getLength();
+		for (int i = 0; i < n; i++)
+		{
+			Node node = nodes.item(i);
+			short type = node.getNodeType();
+			if (type != org.w3c.dom.Node.ELEMENT_NODE)
+				continue;
+			elements.add((Element) node);
+		}
+		// put into an array of Elements.
+		int size = elements.size();
+		Element[] eleArray = new Element[size];
+		for (int i = 0; i < size; i++)
+		{
+			eleArray[i] = (Element) elements.get(i);
+		}
+		return eleArray;
+	}
+
+	/**
+	 * Method parseCredentialStore.<br>
+	 * parses credential store from an XML input source, typically an 
+	 * XML file. The <code>CredentialStore</code> element should be a
+	 * root element. 
+	 * @param in
+	 * @param rtContext
+	 *      the context in which the parsing occurs.
+	 * @param credentialStore
+	 *      the credential store being constructed.
+	 * @throws DomainSpecException
+	 */
+	public synchronized void parseCredentialStore(
+		InputStream in,
+		RTContext rtContext,
+		CredentialStore credentialStore)
+		throws Exception
+	{
+		parser.parse(new InputSource(in));
+		Document document = parser.getDocument();
+		Element root = document.getDocumentElement();
+		transformCredentialStore(root, rtContext, credentialStore);
+	}
+
+	/**
+	 * Method transformCredentialStore.<br>
+	 * @param root
+	 *  the XML element of credential store
+	 * @param rtContext
+	 * @param credentialStore
+	 * @throws DomainSpecException
+	 * @throws CredException
+	 */
+	public synchronized void transformCredentialStore(
+		Element root,
+		RTContext rtContext,
+		CredentialStore credentialStore)
+		throws DomainSpecException, CredException
+	{
+		String rootTag = root.getTagName();
+		if (!rootTag.equals(CREDENTIAL_STORE))
+		{
+			throw new DomainSpecException("Not a CredentialStore document.");
+		}
+		Element[] elements = getChildElements(root);
+		for (int i = 0; i < elements.length; i++)
+		{
+			String tag = elements[i].getTagName();
+			if (tag.equals(APP_DOMAIN_SPEC))
+			{
+				ApplicationDomain spec =
+					transformDomain(elements[i], rtContext);
+				HashID id = spec.getHashID();
+				rtContext.addApplicationDomain(id, spec);
+			}
+			else if (tag.equals(PRINCIPAL_INFO))
+			{
+				// TODO
+				// rtContext.addPrincipal(PublickeyPrincipal, PublicKeyPrincipalInfo);
+			}
+			else if (tag.equals(CREDENTIAL))
+			{
+				CredentialDomain credentialDomain =
+					transformCredential(elements[i], rtContext);
+				HashID id = credentialDomain.getHashID();
+				credentialStore.addCredentialDomain(
+					id,
+					credentialDomain);
+			}
+//			else if (tag.equals(ACCESS_RULE))
+//			{
+//				CredentialDomain accessRuleDomain =
+//					transformAccessRule(elements[i], rtContext);
+//				HashID id = accessRuleDomain.getHashID();
+//				credentialStore.addCredentialDomain(
+//					id,
+//					accessRuleDomain);
+//			}
+		}
+	}
+
+	/**
+	 * Method transformDomain.<br>
+	 *      parses non-system <code>ApplicationDomain</code>.
+	 * @param ele
+	 *  the <code>ApplicationDomain</code> element
+	 * @param rtContext
+	 *  the context in which the transformation occurs.
+	 * @return ApplicationDomain
+	 * @throws DomainSpecException
+	 */
+	public synchronized ApplicationDomain transformDomain(
+		Element ele,
+		RTContext rtContext)
+		throws DomainSpecException
+	{
+		if (!ele.getTagName().equals(APP_DOMAIN_SPEC))
+			throw new DomainSpecException("Not an ApplicationDomainSpecification element");
+		String uri = ele.getAttribute(URI);
+		//		if (uri.length() == 0)
+		//			throw new DomainSpecException(
+		//				missing_attr_value + "'uri'");
+		ApplicationDomain spec =
+			new ApplicationDomain(uri, false, rtContext);
+		String hashID = ele.getAttribute(ID);
+		if (hashID.length() == 0)
+		{
+			// compute the hashID ourselves.
+			// hashID = getHash(spec);
+		}
+		HashID id = new HashID(HashID.APPLICATION_DOMAIN, hashID);
+		spec.setHashID(id);
+		Element[] elements = getChildElements(ele);
+		for (int i = 0; i < elements.length; i++)
+		{
+			Element childEle = elements[i];
+			String childName = childEle.getTagName();
+			if (childName.equals(IMPORT_DOMAIN))
+			{
+				String name = childEle.getAttribute(NAME);
+				if (name.length() == 0)
+					throw new DomainSpecException(
+						missing_attr_value + "'name'");
+				String importedUri = childEle.getAttribute(URI);
+				String idref = childEle.getAttribute(IDREF);
+				if (idref.length() == 0)
+					throw new DomainSpecException(
+						missing_attr_value + "'idref'");
+				ApplicationDomain importedDomain =
+					locateDomain(idref, importedUri, rtContext);
+				spec.importDomain(name, importedDomain);
+			}
+			else if (childName.equals(INTEGER_TYPE))
+			{
+				IntegerType intType =
+					transformIntegerTypeDeclaration(childEle);
+				spec.addType(intType);
+			}
+			else if (childName.equals(DECIMAL_TYPE))
+			{
+				DecimalType decimalType =
+					transformDecimalTypeDeclaration(childEle);
+				spec.addType(decimalType);
+			}
+			else if (childName.equals(ENUM_TYPE))
+			{
+				EnumType enumType =
+					transformEnumTypeDeclaration(childEle, spec);
+				spec.addType(enumType);
+			}
+			else if (childName.equals(STRING_TYPE))
+			{
+				StringType stringType =
+					transformStringTypeDeclaration(childEle);
+				spec.addType(stringType);
+			}
+			else if (childName.equals(RECORD_TYPE))
+			{
+				RecordType recordType =
+					transformRecordTypeDeclaration(childEle, spec);
+				spec.addType(recordType);
+			}
+			else if (childName.equals(TREE_TYPE))
+			{
+				TreeType treeType =
+					transformTreeTypeDeclaration(childEle);
+				spec.addType(treeType);
+			}
+			else if (childName.equals(PRINCIPAL_TYPE))
+			{
+				// This element specifies the principal type for the entire system
+				// Later on, the principal value can be checked against the type 
+				// defined here.
+				SimpleType prinType =
+					transformPrincipalTypeDeclaration(childEle, spec);
+				spec.setPrincipalType(prinType);
+			}
+			else if (childName.equals(ROLE_DECLARATION))
+			{
+				RoleDeclaration role =
+					transformRoleDeclaration(childEle, spec);
+				spec.addRole(role);
+			}
+		} //end of for( )....
+		spec.setComplete();
+		return spec;
+	} //==== End of parseDomainSpec()
+	/**
+	   Parses non-system domain specification object from a file pointed by the 
+	   given uri.
+	*/
+	//	private void parseDomainSpec(String uri)
+	//	{
+	//		DomainSpecification spec = null;
+	//		try
+	//		{
+	//			DOMParser parser = new DOMParser();
+	//			parser.setFeature(
+	//				"http://apache.org/xml/features/validation/schema",
+	//				true);
+	//			parser.parse(new InputSource(new FileInputStream(new File(uri))));
+	//			Document doc = parser.getDocument();
+	//			transform(doc);
+	//		}
+	//		catch (SAXException e)
+	//		{
+	//			System.out.println("error in setting up parser feature");
+	//		}
+	//		catch (Exception ex)
+	//		{
+	//			ex.printStackTrace();
+	//		}
+	//	}
+	//
+	//	private void transform(Document document) throws Exception
+	//	{
+	//		Element root = document.getDocumentElement();
+	//		String rootTag = root.getTagName();
+	//
+	//	}
+	/**
+	 * Method locateDomain.<br>
+	 * @param rtContext
+	 * @param idref
+	 *      the hash value of the target 
+	 *      <code>ApplicationDomainSpecification</code> object.
+	 * @param uri
+	 * @return ApplicationDomain
+	 * @throws DomainSpecException
+	 *  if cannot find the domain by the given idref.
+	 */
+	private ApplicationDomain locateDomain(
+		String idref,
+		String uri,
+		RTContext rtContext)
+		throws DomainSpecException
+	{
+		ApplicationDomain spec = null;
+		if (!rtContext.hasDomainWithID(idref))
+		{
+			//TODO: load domain from given uri, which is optional.
+			//parseDomainSpec(uri);
+			//spec = (DomainSpecification)applicationDomains.get(uri);
+			throw new DomainSpecException(
+				"Cannot find domain with id '" + idref + "'.");
+		}
+		else
+		{
+			spec = rtContext.getApplicationDomain(idref);
+		}
+		if (!spec.isComplete())
+		{
+			throw new DomainSpecException("Circular Dependency");
+		}
+		return spec;
+	}
+	/*###########################################################
+	    #####
+	    ##### Parsing DateType Declaration in DomainSpecification
+	    #####
+	#############################################################*/
+	/**
+	 * Method transformIntegerTypeDeclaration.<br>
+	 * 
+	 * Parses IntegerType declaration in ADSD.
+	 * Returns an IntegerType object by parsing element:<br>
+	    <pre>
+	        &lt;IntegerType name="" min="" max=""/&gt;
+	    </pre>
+	 * @param ele
+	 * @return IntegerType
+	 * @throws DomainSpecException
+	 */
+	private IntegerType transformIntegerTypeDeclaration(Element ele)
+		throws DomainSpecException
+	{
+		if (!ele.getTagName().equals(INTEGER_TYPE))
+			throw new DomainSpecException("Not an IntegerType element");
+		String name = ele.getAttribute(NAME);
+		String minStr = ele.getAttribute(MIN);
+		String maxStr = ele.getAttribute(MAX);
+		if (name.length() == 0)
+			throw new DomainSpecException(
+				missing_attr_value + "'name'");
+		if (minStr.length() == 0)
+			throw new DomainSpecException(
+				missing_attr_value + "'min'");
+		if (maxStr.length() == 0)
+			throw new DomainSpecException(
+				missing_attr_value + "'max'");
+		long min = Long.parseLong(minStr);
+		long max = Long.parseLong(maxStr);
+		//        RTUtil.debugInfo("name = " + name);
+		//        RTUtil.debugInfo("min = " + ele.getAttribute(MIN));
+		//        RTUtil.debugInfo("max = " + ele.getAttribute(MAX));
+		//        RTUtil.debugInfo("base = " + ele.getAttribute(BASE));
+		//        RTUtil.debugInfo("step = " + ele.getAttribute(STEP));
+		//        RTUtil.debugInfo("includeMin = " + ele.getAttribute(INCLUDE_MIN));
+		//        RTUtil.debugInfo("includeMax = " + ele.getAttribute(INCLUDE_MAX));
+		boolean includeMin =
+			RTUtil.parseBoolean(ele.getAttribute(INCLUDE_MIN), true);
+		boolean includeMax =
+			RTUtil.parseBoolean(ele.getAttribute(INCLUDE_MAX), true);
+		long base = RTUtil.parseLong(ele.getAttribute(BASE), 0);
+		long step = RTUtil.parseLong(ele.getAttribute(STEP), 1);
+		return new IntegerType(
+			name,
+			min,
+			max,
+			includeMin,
+			includeMax,
+			base,
+			step);
+	}
+	/**
+	 * Method transformDecimalTypeDeclaration.<br>
+	 * Parses DecimalType declaration in ADSD.
+	    Returns a DecimalType object by parsing element:
+	    <pre>
+	        &lt;DecimalType name="" min="" max=""/&gt;
+	    </pre>
+	 * @param ele
+	 * @return DecimalType
+	 * @throws DomainSpecException
+	 */
+	private DecimalType transformDecimalTypeDeclaration(Element ele)
+		throws DomainSpecException
+	{
+		if (!ele.getTagName().equals(DECIMAL_TYPE))
+			throw new DomainSpecException("Not a DecimalType element");
+		// TODO
+		throw new UnsupportedOperationException(
+			no_support_for + "'DecimalType'");
+	}
+	/**
+	 * Method transformStringTypeDeclaration.<br>
+     * Parses StringType declaration in ADSD.
+        Returns a StringType object by parsing element:<br>
+        <pre>
+            &lt;StringType name="" ignoreCase="false" ordered="false"/&gt;
+        </pre>
+	 * @param ele
+	 * @return StringType
+	 * @throws DomainSpecException
+	 */
+	private StringType transformStringTypeDeclaration(Element ele)
+		throws DomainSpecException
+	{
+		if (!ele.getTagName().equals(STRING_TYPE))
+			throw new DomainSpecException("Not a StringType element");
+		String name = ele.getAttribute(NAME);
+		if (name.length() == 0)
+			throw new DomainSpecException(
+				missing_attr_value + "'name'");
+		boolean ignoreCase =
+			RTUtil.parseBoolean(ele.getAttribute(IGNORE_CASE), false);
+		boolean ordered =
+			RTUtil.parseBoolean(ele.getAttribute(ORDERED), false);
+		return new StringType(name, ignoreCase, ordered);
+	}
+	/**
+	 * Method transformEnumTypeDeclaration.<br>
+     * Parses EnumType declaration in ADSD.
+        Returns an EnumType object by parsing element:<br>
+        <pre>
+            &lt;EnumType name="" ignoreCase="false" ordered="false"/&gt;
+                &lt;EnumValue&gt;Monday&lt;/EnumValue&gt;
+                &lt;EnumValue&gt;Wednesday&lt;/EnumValue&gt;
+                &lt;EnumValue&gt;Friday&lt;/EnumValue&gt;
+                ...
+            &lt;/EnumType&gt;
+        </pre>
+	 * @param ele
+	 * @param currentSpec
+	 * @return EnumType
+	 * @throws DomainSpecException
+	 */
+	private EnumType transformEnumTypeDeclaration(
+		Element ele,
+		DomainSpecification currentSpec)
+		throws DomainSpecException
+	{
+		if (!ele.getTagName().equals(ENUM_TYPE))
+			throw new DomainSpecException("Not an EnumType element");
+		OrderedMap enumValues =
+			new OrderedMap(String.class, Object.class);
+		DataType valueType = null;
+		String name = ele.getAttribute(NAME);
+		if (name.length() == 0)
+			throw new DomainSpecException(
+				missing_attr_value + "'name'");
+		boolean ignoreCase =
+			RTUtil.parseBoolean(ele.getAttribute(IGNORE_CASE), false);
+		boolean ordered =
+			RTUtil.parseBoolean(ele.getAttribute(ORDERED), false);
+		int size = RTUtil.parseInt(ele.getAttribute(SIZE), 0);
+		Element[] elements = getChildElements(ele);
+		for (int i = 0; i < elements.length; i++)
+		{
+			Element child = elements[i];
+			String childName = child.getTagName();
+			if (childName.equals(TYPE)) // nameRef type
+			{
+				// QQ: This element has been removed , as of 8/28/02
+				String domain = child.getAttribute(DOMAIN);
+				String n = child.getAttribute(NAME);
+				valueType = currentSpec.lookupType(domain, n);
+			}
+			else if (childName.equals(ENUM_VALUE))
+			{
+				String value =
+					transformEnumValue(null, child).getValue();
+				//RTUtil.debugInfo("value = " + value);
+				enumValues.put(value, null);
+			}
+		}
+		return new EnumType(
+			name,
+			valueType,
+			enumValues,
+			ignoreCase,
+			ordered,
+			size);
+	}
+	/**
+	 * Method transformTreeTypeDeclaration.<br>
+     * Parses TreeType declaration in ADSD.
+        Returns a TreeType object by parsing element:<br>
+        <pre>
+            &lt;TreeType name="DNSType" sparator="." order="rootLast"/&gt;
+        </pre>
+	 * @param ele
+	 * @return TreeType
+	 * @throws DomainSpecException
+	 */
+	private TreeType transformTreeTypeDeclaration(Element ele)
+		throws DomainSpecException
+	{
+		if (!ele.getTagName().equals(TREE_TYPE))
+			throw new DomainSpecException("Not a TreeType element");
+		String name = ele.getAttribute(NAME);
+		String separator = ele.getAttribute(SEPARATOR);
+		String order = ele.getAttribute(ORDER);
+		if (name.length() == 0)
+			throw new DomainSpecException(
+				missing_attr_value + "'name'");
+		if (separator.length() == 0)
+			throw new DomainSpecException(
+				missing_attr_value + "'sepatator'");
+		if (order.length() == 0)
+			throw new DomainSpecException(
+				missing_attr_value + "'order'");
+		//        RTUtil.debugInfo("name = " +name);
+		//        RTUtil.debugInfo("separator = " + separator);
+		//        RTUtil.debugInfo("order = " + order);
+		return new TreeType(
+			name,
+			separator,
+			order.equals(ROOT_FIRST));
+	}
+	/**
+	 * Method transformRecordTypeDeclaration.<br>
+     * Parses RecordType declaration in ADSD.
+        Returns a RecordType object by parsing element:
+        <pre>
+            &lt;RecordType name="record"&gt;
+                &lt;Field name="field1"&gt;
+                    &lt;Type domain="" name=""/&gt;
+                &lt;/Field&gt;
+                &lt;Field name="field2"&gt;
+                    &lt;Type domain="" name=""/&gt;
+                &lt;/Field&gt;
+                ...
+            &lt;/RecordType&gt;
+        </pre>
+	 * @param ele
+	 * @param currentSpec
+	 * @return RecordType
+	 * @throws DomainSpecException
+	 */
+	private RecordType transformRecordTypeDeclaration(
+		Element ele,
+		DomainSpecification currentSpec)
+		throws DomainSpecException
+	{
+		if (!ele.getTagName().equals(RECORD_TYPE))
+			throw new DomainSpecException("Not a RecordType element");
+		String name = ele.getAttribute(NAME);
+		if (name.length() == 0)
+			throw new DomainSpecException(
+				missing_attr_value + "'name'");
+		RTUtil.debugInfo(
+			"parseRecordTypeDeclaration() > name = " + name);
+		NodeList childNodes = ele.getElementsByTagName(FIELD);
+		int size = childNodes.getLength();
+		if (size < 1)
+			throw new DomainSpecException("No fields specified for the RecordType element.");
+		OrderedMap fieldDeclarations =
+			new OrderedMap(size, String.class, DataType.class);
+		for (int i = 0; i < size; i++)
+		{
+			Element field = (Element) childNodes.item(i);
+			String fieldName = field.getAttribute(NAME);
+			if (fieldName.length() == 0)
+				throw new DomainSpecException(
+					missing_attr_value + "'name'");
+			Element typeRefEle =
+				getFirstChildElementByTagName(field, TYPE);
+			String typeName = typeRefEle.getAttribute(NAME);
+			if (typeName.length() == 0)
+				throw new DomainSpecException(
+					missing_attr_value + "'name'");
+			String typeDomain = typeRefEle.getAttribute(DOMAIN);
+			RTUtil.debugInfo("fieldName = " + fieldName);
+			//            RTUtil.debugInfo("typeName = " + typeName);
+			//            RTUtil.debugInfo("typeDomain = " + typeDomain);
+			DataType fieldType =
+				currentSpec.lookupType(typeDomain, typeName);
+			fieldDeclarations.put(fieldName, fieldType);
+		}
+		return new RecordType(name, fieldDeclarations);
+	}
+	/**
+	 * Method transformPrincipalTypeDeclaration.<br>
+        Parses PrincipalType declaration in ADSD.
+        
+        Returns a SimpleType object by parsing element:
+        <pre>
+            &lt;PrincialType name="prinType"&gt;
+                &lt;TypeRef domain="" name=""/&gt;
+            &lt;/PrincialType&gt;
+        </pre>
+	 * @param ele
+	 * @param currentSpec
+	 * @return SimpleType
+	 * @throws DomainSpecException
+	 */
+	private SimpleType transformPrincipalTypeDeclaration(
+		Element ele,
+		DomainSpecification currentSpec)
+		throws DomainSpecException
+	{
+		if (!ele.getTagName().equals(PRINCIPAL_TYPE))
+			throw new DomainSpecException("Not a PrincipalType element");
+		Element typeRefEle = getFirstChildElementByTagName(ele, TYPE);
+		String domain = typeRefEle.getAttribute(DOMAIN);
+		String name = typeRefEle.getAttribute(NAME);
+		if (name.length() == 0)
+			throw new DomainSpecException(
+				missing_attr_value + "'name'");
+		return (SimpleType) currentSpec.lookupType(domain, name);
+	}
+	/**
+	 * Method transformRoleDeclaration.<br>
+     * Parses RoleDeclaration in ADSD.
+        Returns a RoleDeclaration object by parsing element:
+        <pre>
+            &lt;RoleDeclaration name="record"&gt;
+                &lt;Parameter name="param1"&gt;
+                    &lt;Type domain="" name=""/&gt;
+                &lt;/Parameter&gt;
+                &lt;Parameter name="param2"&gt;
+                    &lt;Type domain="" name=""/&gt;
+                &lt;/Parameter&gt;
+                ...
+            &lt;/RoleDeclaration&gt;
+        </pre>
+	 * @param ele
+	 * @param currentSpec
+     *  the DomainSpecification in which the role is declared.
+	 * @return RoleDeclaration
+	 * @throws DomainSpecException
+	 */
+	private RoleDeclaration transformRoleDeclaration(
+		Element ele,
+		DomainSpecification currentSpec)
+		throws DomainSpecException
+	{
+		if (!ele.getTagName().equals(ROLE_DECLARATION))
+			throw new DomainSpecException("Not a RoleDeclaration element");
+		String roleName = ele.getAttribute(NAME);
+		if (roleName.length() == 0)
+			throw new DomainSpecException(
+				missing_attr_value + "'name'");
+		RTUtil.debugInfo(
+			"parseRoleDeclaration > roleName = " + roleName);
+		boolean isIdentity =
+			RTUtil.parseBoolean(ele.getAttribute(IS_IDENTITY), false);
+
+		int issuerT = RoleDeclaration.DEFAULT_ISSUER_TYPE;
+		int subjectT = RoleDeclaration.DEFAULT_SUBJECT_TYPE;
+
+		RoleDeclaration roleDeclaration = null;
+
+		Element[] elements = getChildElements(ele);
+		int n = elements.length;
+		OrderedMap parameterDeclarations =
+			new OrderedMap(n, String.class, DataType.class);
+		for (int i = 0; i < n; i++)
+		{
+			Element childEle = elements[i];
+			String childName = childEle.getTagName();
+			if (childName.equals(RESTRICTION))
+			{
+				Element baseRoleEle =
+					getFirstChildElementByTagName(
+						childEle,
+						BASE_ROLE);
+				String baseRoleName = baseRoleEle.getAttribute(NAME);
+				if (baseRoleName.length() == 0)
+					throw new DomainSpecException(
+						missing_attr_value + "'name'");
+				String baseRoleDomain =
+					baseRoleEle.getAttribute(DOMAIN);
+				// get base role
+				RoleDeclaration baseRole =
+					currentSpec.lookupRoleDeclaration(
+						baseRoleDomain,
+						baseRoleName);
+				// get new parameters
+				NodeList paramNodes =
+					childEle.getElementsByTagName(PARAMETER);
+				OrderedMap newParameters =
+					transformParameters(paramNodes, currentSpec);
+				roleDeclaration =
+					RoleDeclaration.createRestrictionRole(
+						currentSpec,
+						roleName,
+						isIdentity,
+						baseRole,
+						newParameters);
+			}
+			else if (childName.equals(EXTENSION))
+			{
+				Element baseRoleEle =
+					getFirstChildElementByTagName(
+						childEle,
+						BASE_ROLE);
+				String baseRoleName = baseRoleEle.getAttribute(NAME);
+				if (baseRoleName.length() == 0)
+					throw new DomainSpecException(
+						missing_attr_value + "'name'");
+				String baseRoleDomain =
+					baseRoleEle.getAttribute(DOMAIN);
+				RoleDeclaration baseRole =
+					currentSpec.lookupRoleDeclaration(
+						baseRoleDomain,
+						baseRoleName);
+				NodeList paramNodes =
+					childEle.getElementsByTagName(PARAMETER);
+				OrderedMap newParameters =
+					transformParameters(paramNodes, currentSpec);
+				roleDeclaration =
+					RoleDeclaration.createExtensionRole(
+						currentSpec,
+						roleName,
+						isIdentity,
+						baseRole,
+						newParameters);
+			}
+			else if (childName.equals(PROJECTION))
+			{
+				Element baseRoleEle =
+					getFirstChildElementByTagName(
+						childEle,
+						BASE_ROLE);
+				String baseRoleName = baseRoleEle.getAttribute(NAME);
+				if (baseRoleName.length() == 0)
+					throw new DomainSpecException(
+						missing_attr_value + "'name'");
+				String baseRoleDomain =
+					baseRoleEle.getAttribute(DOMAIN);
+				RoleDeclaration baseRole =
+					currentSpec.lookupRoleDeclaration(
+						baseRoleDomain,
+						baseRoleName);
+				NodeList paramNodes =
+					childEle.getElementsByTagName(PARAMETER);
+				int num = paramNodes.getLength();
+				String[] newParamNames = new String[n];
+				for (int j = 0; j < num; j++)
+				{
+					Element e = (Element) paramNodes.item(j);
+					newParamNames[j] = e.getAttribute(NAME);
+				}
+
+				roleDeclaration =
+					RoleDeclaration.createProjectionRole(
+						currentSpec,
+						roleName,
+						isIdentity,
+						baseRole,
+						newParamNames);
+			}
+			else if (childName.equals(PLAIN))
+			{
+				String issuerTraces =
+					childEle.getAttribute(ISSUER_TRACES);
+				String subjectTraces =
+					childEle.getAttribute(SUBJECT_TRACES);
+				if (issuerTraces.length() != 0)
+				{
+					issuerT =
+						((Integer) (RoleDeclaration
+							.issuerTracesTypes
+							.get(issuerTraces.toLowerCase())))
+							.intValue();
+				}
+				if (subjectTraces.length() != 0)
+				{
+					subjectT =
+						((Integer) (RoleDeclaration
+							.subjectTracesTypes
+							.get(subjectTraces.toLowerCase())))
+							.intValue();
+				}
+				int dimension =
+					RTUtil.parseInt(
+						childEle.getAttribute(DIMENSION),
+						1);
+				Element identityRoleEle =
+					getFirstChildElementByTagName(childEle, IDENTITY);
+				/*  TODO
+				String idBaseRoleName = identityRoleEle.getAttribute(NAME);
+				if (idBaseRoleName.length() == 0)
+					throw new DomainSpecException(
+						missing_attr_value + "'name'");
+				String idBaseRoleDomain = identityRoleEle.getAttribute(DOMAIN);
+				RoleDeclaration idBaseRole =
+					currentSpec.lookupRoleDeclaration(
+						idBaseRoleDomain,
+						idBaseRoleName);
+				*/
+
+				NodeList paramNodes =
+					childEle.getElementsByTagName(PARAMETER);
+				OrderedMap newParameters =
+					transformParameters(paramNodes, currentSpec);
+				roleDeclaration =
+					RoleDeclaration.createPlainRole(
+						currentSpec,
+						roleName,
+						issuerT,
+						subjectT,
+						dimension,
+						isIdentity,
+						newParameters);
+			}
+
+		} // end of for loop
+		return roleDeclaration;
+	}
+	/**
+	 * Method transformParameters.<br>
+	 *  parses <code>Parameter</code> declarations in <code>RoleDeclaration</code> element.
+	 * @param nodes
+     *  the list of <code>Parameter</code> elements
+	 * @return OrderedMap
+     *  an OrderedMap of parameter declarations with parameter names as keys.
+	 */
+	private OrderedMap transformParameters(
+		NodeList nodes,
+		DomainSpecification currentSpec)
+		throws DomainSpecException
+	{
+		OrderedMap parameterDeclarations =
+			new OrderedMap(String.class, DataType.class);
+		int n = nodes.getLength();
+		for (int i = 0; i < n; i++)
+		{
+			Element childEle = (Element) nodes.item(i);
+			String paramName = childEle.getAttribute(NAME);
+			RTUtil.debugInfo("paramName = " + paramName);
+			Element typeRefEle =
+				getFirstChildElementByTagName(childEle, TYPE);
+			String domain = typeRefEle.getAttribute(DOMAIN);
+			//RTUtil.debugInfo("typeDomain = " + domain);
+			String name = typeRefEle.getAttribute(NAME);
+			//RTUtil.debugInfo("typeName = " + name);
+			DataType paramType = currentSpec.lookupType(domain, name);
+			parameterDeclarations.put(paramName, paramType);
+		}
+		return parameterDeclarations;
+	}
+
+	/*###########################################################
+	    #####
+	    ##### Parsing Credential or AccessRule
+	    #####
+	#############################################################*/
+	/**
+	 * Method transformCredential.<br>
+	 *   Returns a <code>CredentialDomain</code> object by parsing element:
+	 *   <pre>
+	 *       &lt;Credential&gt;
+	 *           ...
+	 *       &lt;/Credential&gt;
+	 *   </pre>
+	 * @param ele
+	 * @param rtContext
+	 * @return CredentialDomain
+	 * @throws DomainSpecException
+	 * @throws CredException
+	 */
+	public synchronized CredentialDomain transformCredential(
+		Element ele,
+		RTContext rtContext)
+		throws DomainSpecException, CredException
+	{
+		if (!ele.getTagName().equals(CREDENTIAL))
+			throw new DomainSpecException("Not a Credential element.");
+		String hashID = ele.getAttribute(ID);
+		if (hashID.length() == 0)
+		{
+			//compute hashID
+		}
+		RTUtil.debugInfo("HashID = " + hashID);
+		CredentialDomain credDomain =
+			new CredentialDomain(ele, rtContext);
+		HashID id = new HashID(HashID.CREDENTIAL_DOMAIN, hashID);
+		credDomain.setHashID(id);
+
+		Principal issuer = null;
+
+		Element[] elements = getChildElements(ele);
+		for (int i = 0; i < elements.length; i++)
+		{
+			Element child = elements[i];
+			String tagName = child.getTagName();
+			//RTUtil.debugInfo("***** tagName = " + tagName);
+			if (tagName.equals(PREAMBLE))
+			{
+				Element[] preambleElements = getChildElements(child);
+				for (int j = 0; j < preambleElements.length; j++)
+				{
+					Element preambleChild = preambleElements[j];
+					String preambleChildTag =
+						preambleChild.getTagName();
+					if (preambleChildTag.equals(IMPORT_DOMAIN))
+						// 0 or more
+					{
+						//short name for the imported domain in the scope of this credential.
+						String name =
+							preambleChild.getAttribute(NAME);
+						if (name.length() == 0)
+							throw new DomainSpecException(
+								missing_attr_value + "'name'");
+						RTUtil.debugInfo(
+							"ImportDomain's name = " + name);
+						String uri = preambleChild.getAttribute(URI);
+						RTUtil.debugInfo(
+							"ImportDomain's uri = " + uri);
+						String idref =
+							preambleChild.getAttribute(IDREF);
+						if (idref.length() == 0)
+							throw new DomainSpecException(
+								missing_attr_value + "'idref'");
+						ApplicationDomain importedDomain =
+							locateDomain(idref, uri, rtContext);
+						credDomain.importDomain(name, importedDomain);
+					}
+					else if (preambleChildTag.equals(PRINCIPAL))
+						// 0 or more
+					{
+						// To improve readability, the principal, which could be quite long,
+						// are included in the Preamble so that they can be referred to
+						// in a compact way elsewhere in the credential by using PrincipalRef.
+						RTUtil.debugInfo("parsing principle.....");
+						transformPrincipalValue(
+							preambleChild,
+							credDomain);
+					}
+				} // end for()..
+			}
+			else if (tagName.equals(ISSUER))
+			{
+				Element[] prinEle = getChildElements(child);
+				if (prinEle.length != 1)
+					throw new DomainSpecException(
+						improper_sub_element_for + "'Issuer'");
+				issuer =
+					transformPrincipalValue(prinEle[0], credDomain)
+						.getValue();
+				credDomain.setIssuer(issuer);
+			}
+			//			else if (tagName.equals(CREDENTIAL_IDENTIFIER))
+			//			{
+			//				// TODO
+			//				throw new UnsupportedOperationException(
+			//					no_support_for + "'CredentialIdentifier'");
+			//			}
+			else if (tagName.equals(VALIDITY_TIME))
+			{
+				//TODO
+				//ValidityTime validityTime = parseValidityTime(child);
+				//credDomain.setValidityTime(validityTime);
+			}
+			else if (tagName.equals(VALIDITY_RULE))
+			{
+				// TODO
+				throw new UnsupportedOperationException(
+					no_support_for + "'ValidityRule'");
+			}
+			else // ROLE_DEFINITION
+				{
+				RoleDefinition roleDef =
+					transformRoleDefinition(
+						issuer,
+						credDomain,
+						child);
+				credDomain.addRoleDefinition(roleDef);
+			}
+		} //===== End of for(int i=0; i<numOfchildren; i++)....
+		credDomain.setComplete();
+		return credDomain;
+	} //===== End of parseCredential()
+	/*
+	    Returns an AccessRule object by parsing element:
+	    <pre>
+	        &lt;AccessRule&gt;
+	            ...
+	        &lt;/AccessRule&gt;
+	    </pre>
+	*/
+	public synchronized CredentialDomain transformAccessRule(
+		Element ele,
+		RTContext rtContext)
+		throws DomainSpecException, CredException
+	{
+		if (!ele.getTagName().equals(ACCESS_RULE))
+			throw new DomainSpecException("Not an AccessRule element.");
+		String hashID = ele.getAttribute(ID);
+		if (hashID.length() == 0)
+		{
+			//compute hashID
+		}
+
+		CredentialDomain ruleDomain =
+			new CredentialDomain(ele, rtContext);
+		HashID id = new HashID(HashID.CREDENTIAL_DOMAIN, hashID);
+		ruleDomain.setHashID(id);
+
+		Principal issuer = null;
+		Element[] elements = getChildElements(ele);
+		for (int i = 0; i < elements.length; i++)
+		{
+			Element child = elements[i];
+			String tagName = child.getTagName();
+			if (tagName.equals(PREAMBLE))
+			{
+				Element[] preambleElements = getChildElements(child);
+				for (int j = 0; j < preambleElements.length; j++)
+				{
+					Element preambleChild = preambleElements[j];
+					String preambleChildTag =
+						preambleChild.getTagName();
+					if (preambleChildTag.equals(IMPORT_DOMAIN))
+						// 0 or more
+					{
+						String name =
+							preambleChild.getAttribute(NAME);
+						if (name.length() == 0)
+							throw new DomainSpecException(
+								missing_attr_value + "'name'");
+						String uri = preambleChild.getAttribute(URI);
+						String idref =
+							preambleChild.getAttribute(IDREF);
+						if (idref.length() == 0)
+							throw new DomainSpecException(
+								missing_attr_value + "'idref'");
+						ApplicationDomain importedDomain =
+							locateDomain(idref, uri, rtContext);
+						ruleDomain.importDomain(name, importedDomain);
+					}
+					else if (preambleChildTag.equals(PRINCIPAL))
+						// 0 or more
+					{
+						transformPrincipalValue(
+							preambleChild,
+							ruleDomain);
+					}
+				} // end for()..
+			}
+			else if (tagName.equals(RULE_IDENTIFIER))
+			{
+				// TODO
+				throw new UnsupportedOperationException(
+					no_support_for + "'RuleIdentifier'");
+			}
+			else if (tagName.equals(VALIDITY_TIME))
+			{
+				//                ValidityTime validityTime = parseValidityTime(child);
+				//                accessRule.setValidityTime(validityTime);
+			}
+			else
+			{
+				RoleDefinition roleDef =
+					transformRoleDefinition(
+						issuer,
+						ruleDomain,
+						child);
+				ruleDomain.addRoleDefinition(roleDef);
+			}
+		} // End of for(int i=0; i<numOfchildren; i++)....
+		ruleDomain.setComplete();
+		return ruleDomain;
+	} // End of parseAccessRule()
+
+	//	private parsePrincipalInfo()
+	//	{
+	//				java.security.PublicKey key = null;
+	//
+	//				Element[] principalElements = getChildElements(elements[0]);
+	//				if (principalElements.length != 1)
+	//					throw new DomainSpecException(
+	//						improper_sub_element_for + "'ds:KeyValue'");
+	//				String tagName = principalElements[0].getTagName();
+	//				if (tagName.equals(DSA_KEY_VALUE))
+	//				{
+	//					try
+	//					{
+	//						DSAKeyValue keyvalue =
+	//							new DSAKeyValue(principalElements[0], null);
+	//						key = keyvalue.getPublicKey();
+	//					}
+	//					catch (XMLSecurityException e)
+	//					{
+	//						e.printStackTrace();
+	//						throw new DomainSpecException(e.getMessage());
+	//					}
+	//
+	//					res =
+	//						new Principal(
+	//							new KeyValue(new KeyType(KeyType.DSA), key));
+	//				}
+	//				else if (tagName.equals(RSA_KEY_VALUE))
+	//				{
+	//					try
+	//					{
+	//						RSAKeyValue keyvalue =
+	//							new RSAKeyValue(principalElements[0], null);
+	//						key = keyvalue.getPublicKey();
+	//					}
+	//					catch (XMLSecurityException e)
+	//					{
+	//						e.printStackTrace();
+	//						throw new DomainSpecException(e.getMessage());
+	//					}
+	//					res =
+	//						new Principal(
+	//							new KeyValue(new KeyType(KeyType.RSA), key));
+	//				}
+	//				else // any ###other
+	//					{
+	//					// TODO 
+	//				}
+	//		
+	//	}
+	//	QQ: Currently CredentialDomain is credential-specific. The good part is that 
+	//	    the naming needs to be only unique in terms of one credential. However,
+	//	    it might be more efficient to have some sort of global environment to 
+	//	    keep the information commonly shared, such as principal keyvalue.
+	//	    For example, in the credential preambel, we could define principals 
+	//	    in advance for this credential. But different credentials are very 
+	//	    likely to use same principals. If we have a global env to keep it, then 
+	//	    we don't need to pass the credDomain around.
+	/**
+	 * Method transformPrincipalValue.<br>
+	 * @param ele
+	 * @param credDomain
+	 * @return PrincipalValue
+	 * @throws DomainSpecException
+	 */
+	private PrincipalValue transformPrincipalValue(
+		Element ele,
+		CredentialDomain credDomain)
+		throws DomainSpecException
+	{
+		String tag = ele.getTagName();
+		if (!tag.equals(PRINCIPAL) && !tag.equals(PRINCIPAL_REF))
+			throw new DomainSpecException("Not a Principal element");
+		Principal res = null;
+		PrincipalValue value = null;
+		String id = null;
+		SimpleType principalType = credDomain.getPrincipalType();
+		if (tag.equals(PRINCIPAL))
+		{
+			id = ele.getAttribute(SHORT_NAME);
+			Element[] elements = getChildElements(ele);
+			if (elements.length != 1)
+				throw new DomainSpecException(
+					improper_sub_element_for + "'Principal'");
+			String eleTag = elements[0].getTagName();
+			if (eleTag.equals(INTEGER_VALUE))
+			{
+				res =
+					new DataValuePrincipal(
+						transformIntegerValue(
+							(IntegerType) principalType,
+							elements[0]));
+			}
+			else if (eleTag.equals(STRING_VALUE))
+			{
+				res =
+					new DataValuePrincipal(
+						transformStringValue(
+							(StringType) principalType,
+							elements[0]));
+			}
+			else if (eleTag.equals(KEY_HASH))
+			{
+				Node textNode = elements[0].getFirstChild();
+				if (textNode.getNodeType()
+					!= org.w3c.dom.Node.TEXT_NODE)
+					throw new DomainSpecException("Wrong elements for StringValue");
+				String hashValue = textNode.getNodeValue();
+				res = new PublicKeyPrincipal(hashValue);
+			}
+			credDomain.addPrincipal(id, res);
+		}
+		else if (tag.equals(PRINCIPAL_REF))
+		{
+			id = ele.getAttribute(SHORT_NAME);
+			RTUtil.debugInfo("shortName = " + id);
+			res = credDomain.getPrincipal(id);
+			if (res == null)
+				throw new DomainSpecException("Principal not found");
+			value = new PrincipalValue(res);
+		}
+		return value;
+	}
+	/**
+	 * Method transformRoleDefinition.<br>
+     * Returns a role definition object.
+    
+        <p>
+        A role definition may be one the the following elements, i.e. 
+        <b>SimpleMember, SimpleContainment, LinkedContainment, IntersectionContainment,
+        ProductContainment, ExclusiveProductContainment, SimpleDelegation, or
+        AdvancedDelegation</b>.  Each role definition has a head and a body. The head 
+        part is defined by a HeadRoleTerm. The difference between the above 8 
+        elements lies in the body part. 
+        
+        <P>
+        The product role definition represented by <b>ProductContainment</b> and 
+        <b>ExclusiveProductContainment</b> has not been supported yet.
+	 * @param issuer
+	 * @param credDomain
+	 * @param ele
+	 * @return RoleDefinition
+	 * @throws CredException
+	 * @throws DomainSpecException
+	 */
+	private RoleDefinition transformRoleDefinition(
+		Principal issuer,
+		CredentialDomain credDomain,
+		Element ele)
+		throws CredException, DomainSpecException
+	{
+		RTUtil.debugInfo("parseRoleDefinition().... ");
+		String tag = ele.getTagName();
+		RTUtil.debugInfo("parseRoleDefinition()'s tag = " + tag);
+		if (!tag.equals(SIMPLE_MEMBER)
+			&& !tag.equals(SIMPLE_CONTAINMENT)
+			&& !tag.equals(LINKED_CONTAINMENT)
+			&& !tag.equals(INTERSECTION_CONTAINMENT)
+			&& !tag.equals(PRODUCT_CONTAINMENT)
+			&& !tag.equals(EXCLUSIVE_PRODUCT_CONTAINMENT)
+			&& !tag.equals(SIMPLE_DELEGATION)
+			&& !tag.equals(ADVANCED_DELEGATION))
+			throw new DomainSpecException("Not a proper role definition element");
+		RoleDefinition roleDefinition = null;
+		if (tag.equals(SIMPLE_DELEGATION)
+			|| tag.equals(ADVANCED_DELEGATION))
+		{
+			Element[] elements = getChildElements(ele);
+			if (elements.length < 2 || elements.length > 3)
+				throw new DomainSpecException(
+					improper_sub_element_for + "delegation role");
+			Element headElement = elements[0];
+			Element delegateToElement = elements[1];
+			Element controlElement = null; // optional
+			if (elements.length == 3)
+				controlElement = elements[2];
+			Role head =
+				new Role(
+					issuer,
+					transformRoleTerm(headElement, credDomain));
+			DelegationRole body =
+				transformDelegation(
+					issuer,
+					credDomain,
+					delegateToElement,
+					controlElement);
+			roleDefinition =
+				new RoleDefinition(credDomain, head, body);
+		}
+		else
+		{
+			Element[] elements = getChildElements(ele);
+			if (elements.length != 2)
+				throw new DomainSpecException(
+					improper_sub_element_for + "role definition");
+			Element headElement = elements[0];
+			Element bodyElement = elements[1];
+			Role head =
+				new Role(
+					issuer,
+					transformRoleTerm(headElement, credDomain));
+			PrincipalExpression body =
+				transformBody(issuer, credDomain, bodyElement);
+			roleDefinition =
+				new RoleDefinition(credDomain, head, body);
+		}
+		return roleDefinition;
+	}
+	/**
+	 * Method transformBody.<br>
+     * Returns a PrincipalExpression for the body of a role definition.
+        <P>
+        The body can be one of the following: PrincipalValue, RoleTerm, 
+        ExternalRole, LinkedRole, Intersection, Product, or a Delegation.
+    
+        The method handles all types of the role definition body except the 
+        Delegation role body.
+	 * @param issuer
+	 * @param credDomain
+	 * @param ele
+	 * @return PrincipalExpression
+	 * @throws CredException
+	 * @throws DomainSpecException
+	 */
+	private PrincipalExpression transformBody(
+		Principal issuer,
+		CredentialDomain credDomain,
+		Element ele)
+		throws CredException, DomainSpecException
+	{
+		String tag = ele.getTagName();
+		RTUtil.debugInfo("parseBody() tag = " + tag);
+		PrincipalExpression prinExp = null;
+		if (tag.startsWith(PRINCIPAL))
+		{
+			prinExp =
+				transformPrincipalValue(ele, credDomain).getValue();
+		}
+		else if (tag.equals(ROLE_TERM))
+		{
+			RoleTerm roleTerm = transformRoleTerm(ele, credDomain);
+			prinExp = new Role(issuer, roleTerm);
+		}
+		else if (tag.equals(EXTERNAL_ROLE))
+		{
+			prinExp = transformExternalRole(ele, credDomain);
+		}
+		else if (tag.equals(LINKED_ROLE))
+		{
+			NodeList nodes = ele.getElementsByTagName(ROLE_TERM);
+			if (nodes.getLength() != 2)
+				throw new DomainSpecException(
+					improper_sub_element_for + "'LinkedRole'");
+			Element roleTermEle1 = (Element) nodes.item(0);
+			Element roleTermEle2 = (Element) nodes.item(1);
+			prinExp =
+				new LinkedRole(
+					transformRoleTerm(roleTermEle1, credDomain),
+					transformRoleTerm(roleTermEle2, credDomain));
+		}
+		else if (tag.equals(INTERSECTION))
+		{
+			prinExp = transformRoleIntersection(ele, credDomain);
+		}
+		else if (tag.equals(PRODUCT))
+		{
+			// TODO
+			throw new UnsupportedOperationException(
+				no_support_for + "'Product'");
+		}
+		else if (tag.equals(EXCLUSIVE_PRODUCT))
+		{
+			// TODO
+			throw new UnsupportedOperationException(
+				no_support_for + "'ExclusiveProduct");
+		}
+		return prinExp;
+	}
+	/**
+	 * Method transformDelegation.<br>
+        Returns a DelegationRole object for the body of a role definition 
+        by parsing element: <br>
+        <pre>
+            &lt;SimpleDelegation&gt;
+                ...
+            &lt;/SimpleDelegation&gt;
+            
+            Or
+            
+            &lt;AdvancedDelegation&gt;
+                ...
+            &lt;/AdvancedDelegation&gt;
+        </pre>
+	 * @param issuer
+	 * @param credDomain
+	 * @param delegationElement
+	 * @param controlElement
+	 * @return DelegationRole
+	 * @throws DomainSpecException
+	 * @throws CredException
+	 */
+	private DelegationRole transformDelegation(
+		Principal issuer,
+		CredentialDomain credDomain,
+		Element delegationElement,
+		Element controlElement)
+		throws DomainSpecException, CredException
+	{
+		if (!delegationElement.getTagName().equals(DELEGATE_TO))
+			throw new DomainSpecException("Not a delegateTo element");
+		if (controlElement != null
+			&& !controlElement.getTagName().equals(CONTROL))
+			throw new DomainSpecException("Not a Control element");
+		PrincipalExpression delegateTo = null;
+		Role control = null;
+		// delegateTo
+		Element[] elements = getChildElements(delegationElement);
+		for (int i = 0; i < elements.length; i++)
+		{
+			Element child = elements[i];
+			String childName = child.getTagName();
+			if (childName.startsWith(PRINCIPAL))
+			{
+				delegateTo =
+					transformPrincipalValue(child, credDomain)
+						.getValue();
+			}
+			else if (childName.equals(ROLE_TERM))
+			{
+				RoleTerm roleTerm =
+					transformRoleTerm(child, credDomain);
+				delegateTo = new Role(issuer, roleTerm);
+			}
+			else
+			{
+				throw new DomainSpecException(
+					improper_sub_element_for + "'DelegatTo'");
+			}
+		}
+		// control
+		if (controlElement != null)
+		{
+			elements = getChildElements(controlElement);
+			for (int i = 0; i < elements.length; i++)
+			{
+				Element child = elements[i];
+				String childName = child.getTagName();
+				if (childName.equals(ROLE_TERM))
+				{
+					RoleTerm roleTerm =
+						transformRoleTerm(child, credDomain);
+					control = new Role(issuer, roleTerm);
+				}
+				else if (childName.equals(EXTERNAL_ROLE))
+				{
+					control =
+						transformExternalRole(child, credDomain);
+				}
+				else
+				{
+					throw new DomainSpecException(
+						improper_sub_element_for + "'Control'");
+				}
+			}
+		}
+		return new DelegationRole(delegateTo, control);
+	}
+	/**
+	 * Method transformExternalRole.<br>
+     * Returns an ExternalRole object by parsing element:
+        <pre>
+            &lt;ExternalRole&gt;
+                ...
+            &lt;/ExternalRole&gt;
+        </pre>
+	 * @param ele
+	 * @param credDomain
+	 * @return Role
+	 * @throws CredException
+	 * @throws DomainSpecException
+	 */
+	private Role transformExternalRole(
+		Element ele,
+		CredentialDomain credDomain)
+		throws CredException, DomainSpecException
+	{
+		if (!ele.getTagName().equals(EXTERNAL_ROLE))
+			throw new DomainSpecException("Not an ExternalRole element.");
+		Element[] elements = getChildElements(ele);
+		if (elements.length != 2)
+			throw new DomainSpecException(
+				improper_sub_element_for + "'ExternalRole'");
+		Element prinEle = elements[0];
+		Element roleTermEle = elements[1];
+		return new Role(
+			transformPrincipalValue(prinEle, credDomain).getValue(),
+			transformRoleTerm(roleTermEle, credDomain));
+	}
+	/**
+	 * Method transformRoleIntersection.<br>
+     * Returns an ExternalRole object by parsing element:
+        <pre>
+            &lt;Intersection&gt;
+                ...
+            &lt;/Intersection&gt;
+        </pre>
+	 * @param ele
+	 * @param credDomain
+	 * @return RoleIntersection
+	 * @throws CredException
+	 * @throws DomainSpecException
+	 */
+	private RoleIntersection transformRoleIntersection(
+		Element ele,
+		CredentialDomain credDomain)
+		throws CredException, DomainSpecException
+	{
+		if (!ele.getTagName().equals(INTERSECTION))
+			throw new DomainSpecException("Not an Intersection element.");
+		RoleIntersection ri = new RoleIntersection();
+		Element[] elements = getChildElements(ele);
+		int n = elements.length;
+		for (int i = 0; i < n; i++)
+		{
+			Element child = elements[i];
+			String childTag = child.getTagName();
+			if (childTag.equals(ROLE_TERM))
+			{
+				ri.and(transformRoleTerm(child, credDomain));
+			}
+			else if (childTag.equals(EXTERNAL_ROLE))
+			{
+				ri.and(transformExternalRole(child, credDomain));
+			}
+			else
+			{
+				throw new DomainSpecException(
+					improper_sub_element_for + "'Intersection'");
+			}
+		}
+		return ri;
+	}
+	/**
+	 * Method transformRoleTerm.<br>
+     * Returns a RoleTerm object by parsing element:
+        <pre>
+            &lt;RoleTerm&gt;
+                ...
+            &lt;/RoleTerm&gt; 
+        </pre>
+	 * @param ele
+	 * @param credDomain
+	 * @return RoleTerm
+	 * @throws CredException
+	 * @throws DomainSpecException
+	 */
+	private RoleTerm transformRoleTerm(
+		Element ele,
+		CredentialDomain credDomain)
+		throws CredException, DomainSpecException
+	{
+		if (!ele.getTagName().equals(HEAD_ROLE_TERM)
+			&& !ele.getTagName().equals(ROLE_TERM))
+			throw new DomainSpecException("Not a RoleTerm element.");
+		String roleName = ele.getAttribute(NAME);
+		if (roleName.length() == 0)
+			throw new DomainSpecException(
+				missing_attr_value + "'name'");
+		String domain = ele.getAttribute(DOMAIN);
+		RTUtil.debugInfo("**** roleName = " + roleName);
+		RTUtil.debugInfo("**** domain = " + domain);
+		RoleDeclaration roleDecl =
+			credDomain.lookupRoleDeclaration(domain, roleName);
+		RoleTerm roleTerm = new RoleTerm(roleDecl);
+		NodeList children = ele.getElementsByTagName(PARAMETER);
+		int n = children.getLength();
+		for (int i = 0; i < n; i++)
+		{
+			StringBuffer prefix = new StringBuffer(roleName);
+			Element paramEle = (Element) children.item(i);
+			String paramName = paramEle.getAttribute(NAME);
+			//prefix.append(COLON).append(paramName);
+			transformParameter(
+				paramEle,
+				prefix,
+				roleTerm,
+				credDomain);
+		}
+		return roleTerm;
+	}
+	/**
+	 * Method transformParameter.<br>
+        parses element:
+        <pre>
+            &lt;Parameter name="aa" id="s"&gt;
+                ...
+            &lt;/Parameter&gt;
+        </pre>
+	 * @param ele
+	 * @param prefix
+	 * @param roleTerm
+	 * @param credDomain
+	 * @throws DomainSpecException
+	 */
+	//ValueSet 
+	private void transformParameter(
+		Element ele,
+		StringBuffer prefix,
+		RoleTerm roleTerm,
+		CredentialDomain credDomain)
+		throws DomainSpecException
+	{
+		if (!ele.getTagName().equals(PARAMETER))
+			throw new DomainSpecException("Not a Parameter element.");
+		String parameterName = ele.getAttribute(NAME);
+		if (parameterName.length() == 0)
+			throw new DomainSpecException(
+				missing_attr_value + "'name'");
+		prefix.append(COLON).append(parameterName);
+		DataType paramType = roleTerm.getParameterType(parameterName);
+		String id = ele.getAttribute(ID);
+		RTUtil.debugInfo("transformParameter() id = " + id);
+		Element[] elements = getChildElements(ele);
+		if (elements.length > 1)
+			throw new DomainSpecException(
+				improper_sub_element_for + "'Parameter'");
+		if (elements.length == 0)
+		{
+			// TODO: Create a null parameter value in this case.
+			// It is related to Equals Element.
+			ValueSet nullParameterValue = new ValueSet(paramType);
+			roleTerm.putParameterValue(
+				prefix.toString(),
+				nullParameterValue);
+		}
+		else
+		{
+			Element valueEle = elements[0];
+			String tag = valueEle.getTagName();
+			if (tag.equals(EQUALS))
+			{
+				// TODO
+				throw new UnsupportedOperationException(
+					no_support_for + "'Equals'");
+			}
+			else if (tag.equals(SPECIAL_PRINCIPAL))
+			{
+				// TODO
+				throw new UnsupportedOperationException(
+					no_support_for + "'SpecialPrincipal'");
+			}
+			// the rest of the elements go to ValueSet
+			else
+			{
+				transformValueSetGroup(
+					paramType,
+					valueEle,
+					prefix,
+					roleTerm,
+					credDomain);
+			}
+		}
+	}
+	/**
+	 * Method transformValueSetGroup.<br>
+        Parses Parameter value elements and stores the prefix and value mapping
+        in the RoleTerm object.
+	 * @param type
+	 * @param ele
+	 * @param prefix
+	 * @param roleTerm
+	 * @param credDomain
+	 * @throws DomainSpecException
+	 */
+	//ValueSet 
+	private void transformValueSetGroup(
+		DataType type,
+		Element ele,
+		StringBuffer prefix,
+		RoleTerm roleTerm,
+		CredentialDomain credDomain)
+		throws DomainSpecException
+	{
+		ValueSet parameterValue = null;
+		String tag = ele.getTagName();
+        
+		if (tag.equals(TREE_VALUE)) // TreeValueSet
+		{
+			parameterValue = transformTreeValue((TreeType) type, ele);
+			roleTerm.putParameterValue(
+				prefix.toString(),
+				parameterValue);
+		}
+		else if (tag.equals(INTERVAL)) // IntervalValueSet
+		{
+			parameterValue =
+				transformIntervalValue((OrderedType) type, ele);
+			roleTerm.putParameterValue(
+				prefix.toString(),
+				parameterValue);
+		}
+		else if (tag.equals(SET)) // SetValueSet
+		{
+			Element[] elements = getChildElements(ele);
+			String memberTag = elements[0].getTagName();
+			if (memberTag.equals(INTEGER_VALUE))
+			{
+				SetValueSet set = new SetValueSet((IntegerType) type);
+				IntegerValue v = null;
+				for (int i = 0; i < elements.length; i++)
+				{
+					Element memberEle = elements[i];
+					v =
+						transformIntegerValue(
+							(IntegerType) type,
+							memberEle);
+					set.addValue(v);
+				}
+				parameterValue = set;
+			}
+			else if (memberTag.equals(DECIMAL_VALUE))
+			{
+				SetValueSet set = new SetValueSet((DecimalType) type);
+				DecimalValue v = null;
+				for (int i = 0; i < elements.length; i++)
+				{
+					Element memberEle = elements[i];
+					v =
+						transformDecimalValue(
+							(DecimalType) type,
+							memberEle);
+					set.addValue(v);
+				}
+				parameterValue = set;
+			}
+			else if (memberTag.equals(STRING_VALUE))
+			{
+				SetValueSet set = new SetValueSet((StringType) type);
+				StringValue v = null;
+				for (int i = 0; i < elements.length; i++)
+				{
+					Element memberEle = elements[i];
+					v =
+						transformStringValue(
+							(StringType) type,
+							memberEle);
+					set.addValue(v);
+				}
+				parameterValue = set;
+			}
+			else if (memberTag.equals(ENUM_VALUE))
+			{
+				SetValueSet set = new SetValueSet((EnumType) type);
+				EnumValue v = null;
+				for (int i = 0; i < elements.length; i++)
+				{
+					Element memberEle = elements[i];
+					v =
+						transformEnumValue(
+							(EnumType) type,
+							memberEle);
+					set.addValue(v);
+				}
+				parameterValue = set;
+			}
+			else if (memberTag.startsWith(PRINCIPAL))
+			{
+				SetValueSet set = new SetValueSet((KeyType) type);
+				PrincipalValue v = null;
+				for (int i = 0; i < elements.length; i++)
+				{
+					Element memberEle = elements[i];
+					v =
+						transformPrincipalValue(
+							memberEle,
+							credDomain);
+					set.addValue(v);
+				}
+				parameterValue = set;
+			}
+			roleTerm.putParameterValue(
+				prefix.toString(),
+				parameterValue);
+		}
+		else if (tag.equals(RECORD)) // Record
+		{
+			Element[] elements = getChildElements(ele);
+			// Fields
+			for (int i = 0; i < elements.length; i++)
+			{
+				StringBuffer newPrefix =
+					new StringBuffer(prefix.toString());
+				String fieldName = elements[i].getAttribute(NAME);
+				if (fieldName.length() == 0)
+					throw new DomainSpecException(
+						missing_attr_value + "'name'");
+				RTUtil.debugInfo(
+					"transformValueSetGroup.field name = "
+						+ fieldName);
+				newPrefix.append(COLON).append(fieldName);
+				DataType fieldType =
+					((RecordType) type).getFieldType(fieldName);
+				if (fieldType != null)
+					RTUtil.debugInfo(
+						"transformValueSetGroup.type name = "
+							+ fieldType.getName());
+				else
+					RTUtil.debugInfo(
+						"transformValueSetGroup.type  =  null");
+				Element valueEle = getChildElements(elements[i])[0];
+				// recurrsion
+				transformValueSetGroup(
+					fieldType,
+					valueEle,
+					newPrefix,
+					roleTerm,
+					credDomain);
+			}
+		}
+		else // SingletonValueSet
+			{
+			transformValueGroup(
+				(SimpleType) type,
+				ele,
+				prefix,
+				roleTerm,
+				credDomain);
+		}
+	} // end of transformValueSetGroup()
+	/**
+	 * Method transformValueGroup.<br>
+        Parses Value choice group, which can be one of the following:
+        IntegerValue, DecimalValue, StringValue, EnumValue, TimeValue, 
+        or PrincipalValue.
+	 * @param type
+	 * @param ele
+	 * @param prefix
+	 * @param roleTerm
+	 * @param credDomain
+	 * @throws DomainSpecException
+	 */
+	//SingletonValueSet 
+	private void transformValueGroup(
+		SimpleType type,
+		Element ele,
+		StringBuffer prefix,
+		RoleTerm roleTerm,
+		CredentialDomain credDomain)
+		throws DomainSpecException
+	{
+		SingletonValueSet value = null;
+		String tag = ele.getTagName();
+		if (tag.equals(INTEGER_VALUE))
+		{
+			value =
+				new SingletonValueSet(
+					(IntegerType) type,
+					transformIntegerValue((IntegerType) type, ele));
+			roleTerm.putParameterValue(prefix.toString(), value);
+		}
+		else if (tag.equals(DECIMAL_VALUE))
+		{
+			value =
+				new SingletonValueSet(
+					(DecimalType) type,
+					transformDecimalValue((DecimalType) type, ele));
+			roleTerm.putParameterValue(prefix.toString(), value);
+		}
+		else if (tag.equals(STRING_VALUE))
+		{
+			value =
+				new SingletonValueSet(
+					(StringType) type,
+					transformStringValue((StringType) type, ele));
+			roleTerm.putParameterValue(prefix.toString(), value);
+		}
+		else if (tag.equals(ENUM_VALUE))
+		{
+			value =
+				new SingletonValueSet(
+					(EnumType) type,
+					transformEnumValue((EnumType) type, ele));
+			roleTerm.putParameterValue(prefix.toString(), value);
+		}
+		else if (tag.equals(TIME_VALUE))
+		{
+			// TODO
+			//throw new UnsupportedOperationException(no_support_for+"'TimeValue'");
+			//roleTerm.putParameterValue(prefix.toString(), valu
+		}
+		else if (tag.startsWith(PRINCIPAL))
+		{
+			value =
+				new SingletonValueSet(
+					credDomain.getPrincipalType(),
+					transformPrincipalValue(ele, credDomain));
+			roleTerm.putParameterValue(prefix.toString(), value);
+		}
+	} // end of transformValueGroup()
+	/**
+	 * Method transformIntervalValue.<br>
+        Returns an IntervalValue object by parsing element:
+        <pre>
+            &lt;Interval includeMin="true" includeMax="true"&gt;
+                &lt;min&gt; ... &lt;/min&gt;
+                &lt;max&gt; ... &lt;/max&gt;
+            &lt;/Interval&gt;
+        </pre>
+	 * @param type
+	 * @param ele
+	 * @return IntervalValueSet
+	 * @throws DomainSpecException
+	 */
+	private IntervalValueSet transformIntervalValue(
+		OrderedType type,
+		Element ele)
+		throws DomainSpecException
+	{
+		if (!ele.getTagName().equals(INTERVAL))
+			throw new DomainSpecException("Not an Interval element");
+		Element fromEle = getFirstChildElementByTagName(ele, FROM);
+		Element toEle = getFirstChildElementByTagName(ele, TO);
+		Element e1 = null, e2 = null;
+		if (fromEle != null)
+			e1 = getFirstChildElement(fromEle);
+		if (toEle != null)
+			e2 = getFirstChildElement(toEle);
+		if (e1 != null && e2 != null)
+		{
+			if (!e1.getTagName().equals(e2.getTagName()))
+				throw new DomainSpecException(
+					improper_sub_element_for + "'Interval'");
+		}
+		DataValue min = null, max = null;
+		if (e1 != null)
+			min = transformOrderedValue(type, e1);
+		if (e2 != null)
+			max = transformOrderedValue(type, e2);
+		return new IntervalValueSet(type, min, max);
+	}
+	/**
+	 * Method transformOrderedValue.<br>
+        Returns DataValue by parsing elements:
+        <pre>
+            &lt;IntegerValue&gt; ... &lt;/IntegerValue&gt; or 
+    
+            &lt;DecimalValue&gt; ... &lt;/DecimalValue&gt; or
+    
+            &lt;StirngValue&gt; ... &lt;/StringValue&gt; or
+    
+            &lt;EnumValue&gt; ... &lt;/EnumValue&gt; or
+    
+            &lt;TimeValue&gt; ... &lt;/timeValue&gt;
+        </pre>
+	 * @param type
+	 * @param ele
+	 * @return DataValue
+	 * @throws DomainSpecException
+	 */
+	private DataValue transformOrderedValue(
+		OrderedType type,
+		Element ele)
+		throws DomainSpecException
+	{
+		DataValue value = null;
+		String tag = ele.getTagName();
+		if (tag.equals(INTEGER_VALUE))
+		{
+			value = transformIntegerValue((IntegerType) type, ele);
+		}
+		if (tag.equals(DECIMAL_VALUE))
+		{
+			value = transformDecimalValue((DecimalType) type, ele);
+		}
+		if (tag.equals(STRING_VALUE))
+		{
+			value = transformStringValue((StringType) type, ele);
+		}
+		if (tag.equals(ENUM_VALUE))
+		{
+			value = transformEnumValue((EnumType) type, ele);
+		}
+		if (tag.equals(TIME_VALUE))
+		{
+			//value = transformTimeValue((TimeType)type, ele);
+		}
+		return value;
+	}
+	/**
+	 * Method transformIntegerValue.<br>
+        Returns an IntegerValue object by parsing element:
+        <pre>
+            &lt;IntegerValue&gt;
+                123
+            &lt;/IntegerValue&gt;
+        </pre>
+	 * @param type
+	 * @param ele
+	 * @return IntegerValue
+	 * @throws DomainSpecException
+	 */
+	private IntegerValue transformIntegerValue(
+		IntegerType type,
+		Element ele)
+		throws DomainSpecException
+	{
+		if (!ele.getTagName().equals(INTEGER_VALUE))
+			throw new DomainSpecException("Not an IntegerValue element.");
+		Node textNode = ele.getFirstChild();
+		if (textNode.getNodeType() != org.w3c.dom.Node.TEXT_NODE)
+			throw new DomainSpecException("Wrong elements for StringValue");
+		IntegerValue value =
+			new IntegerValue(textNode.getNodeValue());
+		// Type checking.
+		if (type != null && !type.isValidValue(value))
+			throw new DomainSpecException(
+				illegal_value_for + "IntegerType :" + type.getName());
+		return value;
+	}
+	/**
+	 * Method transformDecimalValue.<br>
+        Returns a DecimalValue object by parsing element:
+        <pre>
+            &lt;DecimalValue&gt;
+                123
+            &lt;/DecimalValue&gt;
+        </pre>
+	 * @param type
+	 * @param ele
+	 * @return DecimalValue
+	 * @throws DomainSpecException
+	 */
+	private DecimalValue transformDecimalValue(
+		DecimalType type,
+		Element ele)
+		throws DomainSpecException
+	{
+		if (!ele.getTagName().equals(DECIMAL_VALUE))
+			throw new DomainSpecException("Wrong element");
+		Node textNode = ele.getFirstChild();
+		if (textNode.getNodeType() != org.w3c.dom.Node.TEXT_NODE)
+			throw new DomainSpecException("Wrong elements for StringValue");
+		DecimalValue value =
+			new DecimalValue(textNode.getNodeValue());
+		// Type checking.
+		if (type != null && !type.isValidValue(value))
+			throw new DomainSpecException(
+				illegal_value_for + "DecimalType :" + type.getName());
+		return value;
+	}
+	/**
+	 * Method transformStringValue.<br>
+        Returns a StringValue object by parsing element:
+        <pre>
+            &lt;StringValue&gt;
+                123
+            &lt;/StringValue&gt;
+        </pre>
+	 * @param type
+	 * @param ele
+	 * @return StringValue
+	 * @throws DomainSpecException
+	 */
+	private StringValue transformStringValue(
+		StringType type,
+		Element ele)
+		throws DomainSpecException
+	{
+		if (!ele.getTagName().equals(STRING_VALUE))
+			throw new DomainSpecException("Not a StringValue element");
+		Node textNode = ele.getFirstChild();
+		if (textNode.getNodeType() != org.w3c.dom.Node.TEXT_NODE)
+			throw new DomainSpecException(
+				improper_sub_element_for + "'StringValue'");
+		StringValue value = new StringValue(textNode.getNodeValue());
+		// Type checking.
+		if (type != null && !type.isValidValue(value))
+			throw new DomainSpecException(
+				illegal_value_for + "StringType :" + type.getName());
+		return value;
+	}
+	/**
+	 * Method transformEnumValue.<br>
+        Returns an EnumValue object by parsing element:
+        <pre>
+            &lt;EnumValue&gt;
+                123
+            &lt;/EnumValue&gt;
+        </pre>
+	 * @param type
+	 * @param ele
+	 * @return EnumValue
+	 * @throws DomainSpecException
+	 */
+	private EnumValue transformEnumValue(EnumType type, Element ele)
+		throws DomainSpecException
+	{
+		if (!ele.getTagName().equals(ENUM_VALUE))
+			throw new DomainSpecException("Not an EnumValue element");
+		Node textNode = ele.getFirstChild();
+		if (textNode.getNodeType() != org.w3c.dom.Node.TEXT_NODE)
+			throw new DomainSpecException(
+				improper_sub_element_for + "'EnumValue'");
+		EnumValue value =
+			new EnumValue(textNode.getNodeValue());
+		// Type checking.
+		if (type != null && !type.isValidValue(value))
+		{
+			RTUtil.debugInfo(
+				"transformEnumValue() type name = " + type.getName());
+			RTUtil.debugInfo(
+				"transformEnumValue() value = " + value.toString());
+			throw new DomainSpecException(
+				illegal_value_for + "EnumType :" + type.getName());
+		}
+		return value;
+	}
+	/**
+	 * Method transformTreeValue.<br>
+        Returns a TreeValueSet object by parsing element:
+        <pre>
+            &lt;TreeValue includeCurrent="true" 
+                       includeChildren="true" 
+                       includeDescendents="false"&gt;    
+                cs.stanford.edu
+            &lt;/TreeValue&gt;
+        </pre>
+	 * @param type
+	 * @param ele
+	 * @return TreeValueSet
+	 * @throws DomainSpecException
+	 */
+	private TreeValueSet transformTreeValue(
+		TreeType type,
+		Element ele)
+		throws DomainSpecException
+	{
+		if (!ele.getTagName().equals(TREE_VALUE))
+			throw new DomainSpecException("Not a TreeValue element");
+		Node textNode = ele.getFirstChild();
+		if (textNode.getNodeType() != org.w3c.dom.Node.TEXT_NODE)
+			throw new DomainSpecException(
+				improper_sub_element_for + "'TreeValue'");
+		boolean includeCurrent =
+			RTUtil.parseBoolean(
+				ele.getAttribute(INCLUDE_CURRENT),
+				true);
+		boolean includeChildren =
+			RTUtil.parseBoolean(
+				ele.getAttribute(INCLUDE_CHILDREN),
+				false);
+		boolean includeDescendents =
+			RTUtil.parseBoolean(
+				ele.getAttribute(INCLUDE_DESCENDENTS),
+				false);
+		String value = textNode.getNodeValue();
+		String separator = type.getSeparator();
+		StringTokenizer st = new StringTokenizer(value, separator);
+		int size = st.countTokens();
+		ArrayList values = new ArrayList(size);
+		while (st.hasMoreTokens())
+		{
+			values.add((String) st.nextToken());
+		}
+		TreeValue res = new TreeValue(type, values);
+		// Type checking.
+		if (type != null && !type.isValidValue(res))
+			throw new DomainSpecException(
+				illegal_value_for + "TreeType :" + type.getName());
+		return new TreeValueSet(
+			(TreeType) type,
+			res,
+			includeCurrent,
+			includeChildren,
+			includeDescendents);
+	}
+	/**
+	 * Method transformTimeValue.<br>
+        Returns a TimeValue object by parsing element:
+        <pre>
+            &lt;TimeValue&gt;
+                2002-08-29T09:31:32
+            &lt;/TimeValue&gt;
+        </pre>
+	 * @param type
+	 * @param ele
+	 * @return TimeValue
+	 * @throws DomainSpecException
+	 */
+	private TimeValue transformTimeValue(TimeType type, Element ele)
+		throws DomainSpecException
+	{
+		if (!ele.getTagName().equals(TIME_VALUE))
+			throw new DomainSpecException("Not a TimeValue element");
+		Node textNode = ele.getFirstChild();
+		if (textNode.getNodeType() != org.w3c.dom.Node.TEXT_NODE)
+			throw new DomainSpecException(
+				improper_sub_element_for + "'TimeValue'");
+		String dateString = textNode.getNodeValue();
+		String typeName = type.getName();
+		TimeValue value =
+			new TimeValue(
+				typeName,
+				transformDateTime(typeName, dateString));
+		return value;
+	}
+	/**
+	 * Method transformDateTime.<br>
+        Returns a java.uti.Date object from the given XML Schema datetype name
+        and the dateTime stirng.
+        
+        By using Sun XML Datetype Library, we validate dateTime against 
+        the corresonding datetype specified by typeName. DomainSpecExeption is
+        thrown when validation fails.
+	 * @param typeName
+	 * @param dateTime
+	 * @return Date
+	 * @throws DomainSpecException
+	 */
+	private Date transformDateTime(String typeName, String dateTime)
+		throws DomainSpecException
+	{
+		com.sun.msv.datatype.xsd.XSDatatype type = null;
+		try
+		{
+			com.sun.msv.datatype.xsd.DatatypeFactory.getTypeByName(
+				typeName);
+		}
+		catch (org.relaxng.datatype.DatatypeException e)
+		{
+			throw new DomainSpecException(
+				"Cannot recognize type " + typeName);
+		}
+		if (!type.isValid(dateTime, null))
+			throw new DomainSpecException(
+				illegal_value_for + type.getName());
+		// for datetype, the corresponding Java object is Calendar.
+		Calendar dtObject =
+			(Calendar) type.createJavaObject(dateTime, null);
+		Class dtClass = type.getJavaObjectType();
+		RTUtil.debugInfo(
+			"paseDateTime()> dtClass = " + dtClass.getName());
+		return dtObject.getTime();
+	}
+	/*
+	TreeValue parseDateTimeOld(String typeName, String dateTime)
+	    throws DomainSpecException
+	{
+	
+	        XSDatatype = DatatypeFactory.getTypeByName(tu   
+	
+	    string regExp;
+	    String s = dateTime.trim();
+	
+	    if(typeName.equals("dateTime"))
+	    {
+	        regExp = "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}";
+	        int tIndex = s.indexOf('T');
+	        
+	    }
+	    else if (typeName.equals("date"))
+	    {
+	    }
+	    else if (typeName.equals("time"))
+	    {
+	    }
+	    else if(typeName.equals("gYear"))
+	    {
+	    }
+	    else if(typeName.equals("gYearMonth"))
+	    {
+	    }
+	    else if(typeName.equals("gMonth"))
+	    {
+	    }
+	    else if(typeName.equals("gMonthDay"))
+	    {
+	    }
+	    else if(typeName.equals("gDay"))
+	    {
+	    }
+	    
+	// Issue: Not sure how to handle the optional time zone part, so ignore it for now.
+	// The following is an attempt to match the time zone.
+	// "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(Z|((+|\\0x2D)[0-2][0-9]:[0-2][0-9]))?
+	
+	    if(! s.matches(regExp))
+	        throw new DomainSpecException("'"+dateTime+
+	            "' is no in the format of 'CCYY-MM-DDThh:mm:ss'");           
+	    String year = s.substring(0, 4);
+	    if(! RTUtil.validYear(year))
+	        throw new DomainSecException("Invalid year '" + year + "'");
+	    String month = s.substring(5, 8);
+	    if(! RTUtil.validMonth(month))
+	        throw new DomainSpecException("Invalid month '" + month+"'");
+	    String day = s.substring(9, 11);
+	    if(! RTUtil.validDay(year, month, day))
+	        throw new DomainSpecException("Invalid day '" + day + 
+	            "' in month '"+month+"'");
+	    String hour = s.substring(12, 14);
+	    if(! RTUtil.validHour(hour))
+	        throw new DomainSpecException("Invalid hour '"+hour+"'");
+	    String minute = s.substring(15, 17);
+	    if(! RTUtil.validMinSec(minute))
+	        throw new DomainSpecException("Invalid minute '"+minute+"'");
+	    String second = s.substring(18, 20);
+	    if(! RTUtil.validMinSec(second))
+	        throw new DomainSpecException("Invalid second '"+second+"'");
+	    //String timeZone = s.substring(22);
+	    
+	
+	    Date date = null;
+	    try
+	    {
+	        Calendar calendar = Calendar.getInstance();
+	        calendar.set(Integer.parseInt(year), Integer.parseInt(month), 
+	                     Integer.parseInt(day), Integer.parseInt(hour), 
+	                     Integer.parseInt(minute), Integer.parseInt(second));
+	        date = calendar.getTime();
+	    } 
+	    catch(NumberFormatException e)
+	    {
+	        // Because month, day, hour, minute, second has been validated
+	        // it should never reach here. 
+	    }
+	    
+	    return ;
+	}
+	*/
+	//        DatatypeValidator validator = getDatatypeValidator("dateTime");
+	//        try
+	//        {
+	//            validator.validate(dateTime, null);
+	//        } 
+	//        catch(InvalidDatatypeValueException e)
+	//        {
+	//            
+	//        }
+	//        
+	//        
+	//        int year = date[0], month = date[1], day = date[2], 
+	//            hour = date[3], minute = date[4], second = date[5]; 
+	//        // Issue: what to do with the time zone?
+	//        
+	//        Calendar calendar = Calendar.getInstance();
+	//        calendar.set(year, month, day, hour, minute, second);
+	//        return calendar.getTime();
+
+	//    private ValidityTime parseValidityTime(Element ele)
+	//        throws DomainSpecException
+	//    {
+	//        if(! ele.getTagName().equals(VALIDITY_TIME))
+	//            throw new DomainSpecException("Not a ValidityTime element");
+	//        
+	//        Element[] elements = getChildElements(ele);
+	//        if(elements.length != 3)
+	//            throw new DomainSpecException(
+	//                improper_sub_element_for + "'ValidityTime'");
+	//                
+	//        String issueAt = getFirstChildElementByTagName(ele, ISSUE_AT).getNodeValue();
+	//        String validFrom = getFirstChildElementByTagName(ele, VALID_FROM).getNodeValue();
+	//        String validTo = getFirstChildElementByTagName(ele, VALID_TO).getNodeValue();
+	//        
+	//        return new ValidityTime(RTUtil.parseDateTime(issueAt),
+	//                                RTUtil.parseDateTime(validFrom),
+	//                                RTUtil.parseDateTime(validTo));
+	//    }
+
+} // End of Class RTParser.
