Index: fedd/abac-src/rtml/src/edu/stanford/rt/credential/DomainSpecification.java
===================================================================
--- fedd/abac-src/rtml/src/edu/stanford/rt/credential/DomainSpecification.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
+++ fedd/abac-src/rtml/src/edu/stanford/rt/credential/DomainSpecification.java	(revision 8780cbecc6db2bdc2b9ef31eec6e5209ad3bff15)
@@ -0,0 +1,458 @@
+package edu.stanford.rt.credential;
+
+import java.util.*;
+
+import edu.stanford.rt.datatype.*;
+import edu.stanford.rt.credential.*;
+import edu.stanford.rt.util.*;
+
+/**
+ * @author Ninghui Li, Sandra Qiu<br>
+ *
+ * This class stores the common information about an <code>ApplicationDomain</code> or
+ * a <code>CredentialDomain</code>. The info includes the following:
+ * principal type, imported application domains, type declarations, 
+ * role declarations, hash id, RTML context, and the parsing status.
+ * 
+ */
+public class DomainSpecification
+{
+    /**
+     * Principal type
+     */
+	private SimpleType principalType;
+
+	/**
+	 * Stores all imported domains in this domain, 
+	 * mapping string (domain name) to ApplicationDomain object.
+	 */
+	private OrderedMap importedDomains;
+
+	/**
+	 * Stores all type decalarations in this domain, 
+	 * mapping string(type name) to type declaration object.
+	 */
+	private OrderedMap typeDeclarations;
+
+	/**
+	 * Stores all role declarations in this domain,
+	 * mapping string(role name) to role declaration object.
+	 */
+	private OrderedMap roleDeclarations;
+
+	/**
+	 *  A flag indicates the parsing status of the domain.
+	 */
+	private boolean completeState;
+
+	/** The hash value of the domain. */
+	private HashID hashID;
+
+    /**
+     * RTML Context
+     */
+	private RTContext context;
+
+	/**
+	 * Constuctor for DomainSpecification.
+	    Contructs a DomainSpecification object with the specific uri. 
+	    Include System DomainSpecification for non-system DomainSpecification
+		object.
+	 * @param uri
+	 * @param isSystemDomain
+	 * @param context
+	 * @throws DomainSpecException
+	 */
+	DomainSpecification(RTContext context) throws DomainSpecException
+	{
+		this.completeState = false;
+		this.importedDomains =
+			new OrderedMap(String.class, DomainSpecification.class);
+		this.typeDeclarations =
+			new OrderedMap(String.class, DataType.class);
+		this.roleDeclarations =
+			new OrderedMap(String.class, RoleDeclaration.class);
+		this.context = context;
+	}
+
+	//	/**
+	//	    Copies over the type declarations and role declarations from the 
+	//	    included domain specification objects.
+	//	*/
+	//	private void includeDomain(DomainSpecification ds)
+	//		throws DomainSpecException
+	//	{
+	//		SimpleType prinType = ds.getPrincipalType();
+	//		if (prinType != null)
+	//		{
+	//			if (this.principalType == null)
+	//			{
+	//				this.principalType = prinType;
+	//			}
+	//			else if (!prinType.equals(this.principalType))
+	//			{
+	//				throw new DomainSpecException("Pincipal Type Conflict!");
+	//			}
+	//		}
+	//		typeDeclarations.putAll(ds.getTypeDeclarations());
+	//		roleDeclarations.putAll(ds.getRoleDeclarations());
+	//	}
+
+	/**
+	 * Method importDomain.
+	 * 		Add a newly imported domain map.
+	 * @param name
+     *      the short name to refer to spec with the domain.
+	 * @param spec
+	 * @throws DomainSpecException
+	 */
+	public synchronized void importDomain(
+		String name,
+		ApplicationDomain spec)
+		throws DomainSpecException
+	{
+		importedDomains.put(name, spec);
+	}
+
+	/**
+	 * Method addType.
+	 * 		Add a new type declaration to the domain.<br>
+	 * @param type
+	 * @throws DomainSpecException
+	 * 		DomainSpecException when a duplicated type declaration, 
+	 *      i.e. a type declaration with the same name and same data 
+	 *      type, is added.
+	 */
+	public synchronized void addType(DataType type)
+		throws DomainSpecException
+	{
+		String typeName = type.getName();
+		if (typeExistsInSystemDomain(typeName))
+			throw new DomainSpecException(
+				"Type '"
+					+ typeName
+					+ "' already declared in system domain");
+		typeDeclarations.put(typeName, type);
+	}
+
+	/**
+	 * Method addType.
+	 * 		Add XML built-in type.
+	 * @param typeName
+	 * @throws DomainSpecException
+	 */
+	public synchronized void addType(String typeName)
+		throws DomainSpecException
+	{
+		if (typeExistsInSystemDomain(typeName))
+			throw new DomainSpecException(
+				"Type '"
+					+ typeName
+					+ "' already declared in system domain");
+		typeDeclarations.put(typeName, null);
+	}
+
+	/**
+	 * Method addRole.
+	 * 		Add a new role declaration to the domain.
+	 * @param role
+	 * @throws DomainSpecException
+	 */
+	public synchronized void addRole(RoleDeclaration role)
+		throws DomainSpecException
+	{
+		RTUtil.debugInfo(
+			"DomainSpecification(id="
+				+ getHashID().toString()
+				+ ") adding role '"
+				+ role.getName()
+				+ "'");
+
+		String roleName = role.getName();
+		if (roleExistsInSystemDomain(roleName))
+			throw new DomainSpecException(
+				"Role '"
+					+ roleName
+					+ "' already declared in system domain");
+		roleDeclarations.put(roleName, role);
+	}
+
+	/**
+	 * Method setPrincipalType.
+	 * @param prinType
+	 * @throws DomainSpecException
+	 */
+	public synchronized void setPrincipalType(SimpleType prinType)
+		throws DomainSpecException
+	{
+		if (this.principalType == null)
+			this.principalType = prinType;
+		else if (!prinType.equals(this.principalType))
+			throw new DomainSpecException("Pincipal Type Conflict!");
+	}
+
+	/**
+	 * Method isComplete.
+     *  checks whether the parsing is completed.
+	 * @return boolean
+	 */
+	public boolean isComplete()
+	{
+		return completeState;
+	}
+
+	/**
+	 * Method setComplete.
+     *      marks the parsing status as complete, so no modification 
+     *      is allowed for imported domains, type declarations , and 
+     *      role declarations maps.
+	 */
+	public synchronized void setComplete()
+	{
+		completeState = true;
+		importedDomains.setUneditable();
+		typeDeclarations.setUneditable();
+		roleDeclarations.setUneditable();
+	}
+
+	/**
+	 * Method lookupImportedDomain.
+	 * 		Lookup an imported domain by the given domainRef 
+     *      in the currnt domain.
+	 * @param domainRef
+	 * @return DomainSpecification
+	 * @throws DomainSpecException
+     *      if cannot find one
+	 */
+	public DomainSpecification lookupImportedDomain(String domainRef)
+		throws DomainSpecException
+	{
+		DomainSpecification spec =
+			(DomainSpecification) importedDomains.get(domainRef);
+		if (spec == null)
+		{
+			throw new DomainSpecException(
+				"Domain '" + domainRef + "' not found.");
+		}
+
+		return spec;
+	}
+
+	/**
+	 * Method lookupType.
+	 * 		Look up the DataType declaration by given typeName 
+     *      in the current domain.
+	 * @param typeName
+	 * @return DataType
+     *  returns null if cannot find one.
+	 * @throws DomainSpecException
+	 * 		if cannot find a DataType declaration by the given name.
+	 */
+	public DataType lookupType(String typeName)
+		throws DomainSpecException
+    {
+        return (DataType) typeDeclarations.get(typeName);
+    }
+
+	/**
+	 * Method lookupType.
+	 * 		Look up the DataType declaration by given typeName in the given domain.
+	 * @param domainRef
+	 * 		specifies which domain to look up in. If domainRef is null or an
+	 * 		empty string, then look up in the current domain.
+	 * @param typeName
+	 * @return DataType
+	 * @throws DomainSpecException
+	 * 		if cannot find a DataType with given name.
+	 */
+	public DataType lookupType(String domainRef, String typeName)
+		throws DomainSpecException
+	{
+		DataType type;
+
+		if (domainRef == null || domainRef.length() == 0)
+		{
+			type = this.lookupType(typeName);
+		}
+		else
+		{
+			DomainSpecification importedSpec =
+				this.lookupImportedDomain(domainRef);
+			type = importedSpec.lookupType(typeName);
+		}
+		return type;
+	}
+
+	/**
+	 * Method lookupRoleDeclaration.
+	 * 		Look up the role declaration by given roleName in the current domain.
+	 * @param roleName
+	 * @return RoleDeclaration
+     *  returns null if cannot find one.
+	 * @throws DomainSpecException
+	 * 		if cannot find one.
+	 */
+	public RoleDeclaration lookupRoleDeclaration(String roleName)
+		throws DomainSpecException
+    {
+        return (RoleDeclaration) roleDeclarations.get(roleName);
+    }
+
+	/**
+	 * Method lookupRoleDeclaration.
+	 * 		looks up a role declaration by given roleName in the given domain.
+	 * @param domainRef
+	 * 		specifies which domain to look up in.  If domainRef is null or an
+	 * 		empty string, then look up in the current domain.
+	 * @param roleName
+	 * @return RoleDeclaration
+	 * @throws DomainSpecException
+	 * 		if cannot find a one.
+	 */
+	public RoleDeclaration lookupRoleDeclaration(
+		String domainRef,
+		String roleName)
+		throws DomainSpecException
+	{
+		RoleDeclaration role;
+
+		if (domainRef == null || domainRef.length() == 0)
+		{
+			role = this.lookupRoleDeclaration(roleName);
+		}
+		else
+		{
+			DomainSpecification importedSpec =
+				this.lookupImportedDomain(domainRef);
+			role = importedSpec.lookupRoleDeclaration(roleName);
+		}
+		return role;
+	}
+
+	/**
+	 * Method getContext.
+	 * @return RTContext
+	 */
+	public RTContext getContext()
+	{
+		return context;
+	}
+	/**
+	 * Method getTypeDeclarations.
+	 * @return OrderedMap
+	 * @throws DomainSpecException
+     *  when parsing is not completed.
+	 */
+	public OrderedMap getTypeDeclarations()
+		throws DomainSpecException
+	{
+		if (!isComplete())
+			throw new DomainSpecException("Still parsing current domain specification");
+		return typeDeclarations;
+	}
+
+	/**
+	 * Method getRoleDeclarations.
+	 * @return OrderedMap
+	 * @throws DomainSpecException
+     *  when parsing is not completed.
+	 */
+	public OrderedMap getRoleDeclarations()
+		throws DomainSpecException
+	{
+		if (!isComplete())
+			throw new DomainSpecException("Still parsing current domain specification");
+		return roleDeclarations;
+	}
+
+	/**
+	 * Method getImportedDomains.
+	 * @return OrderedMap
+	 * @throws DomainSpecException
+     *  when parsing is not completed.
+	 */
+	public OrderedMap getImportedDomains() throws DomainSpecException
+	{
+		if (!isComplete())
+			throw new DomainSpecException("Still parsing current domain specification");
+		return importedDomains;
+
+	}
+
+	/**
+	 * Method getPrincipalType.
+	 * @return SimpleType
+	 */
+	public SimpleType getPrincipalType()
+	{
+		return this.principalType;
+	}
+
+	/**
+	 * Returns the hashID.
+	 * @return ApplicationDomainHashID
+	 */
+	public HashID getHashID()
+	{
+		return this.hashID;
+	}
+
+	/**
+	 * Sets the hashID.
+	 * @param hashID The hashID to set
+	 */
+	public synchronized void setHashID(HashID hashID)
+		throws DomainSpecException
+	{
+		this.hashID = hashID;
+	}
+
+	/**
+	 * Method typeExistsInSystemDomain.
+     *  checks whether a DataType with given typeName is already 
+     *  declcared in system domain.
+	 * @param typeName
+	 * @return boolean
+	 */
+	private boolean typeExistsInSystemDomain(String typeName)
+	{
+		if (context == null)
+			return false;
+
+		try
+		{
+			DataType t =
+				context.getSystemDomain().lookupType(typeName);
+			return true;
+		}
+		catch (DomainSpecException e)
+		{
+			return false;
+		}
+	}
+
+	/**
+	 * Method roleExistsInSystemDomain.
+     *  checks whether a RoleDeclaration with given roleName is already 
+     *  declcared in system domain.
+	 * @param roleName
+	 * @return boolean
+	 */
+	private boolean roleExistsInSystemDomain(String roleName)
+	{
+		if (context == null)
+			return false;
+
+		try
+		{
+			RoleDeclaration r =
+				context.getSystemDomain().lookupRoleDeclaration(
+					roleName);
+			return true;
+		}
+		catch (DomainSpecException e)
+		{
+			return false;
+		}
+	}
+}
