/*
 * (c) Copyright IBM Corp 2001, 2005 
 */

package edu.uga.cs.lsdis.meteors.wadls.xml;

import java.io.*;
import java.net.*;
import java.util.*;

import javax.xml.namespace.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.*;

import javax.wadls.*;
import javax.wadls.extensions.*;
import javax.wadls.extensions.schema.Schema;
import javax.wadls.extensions.schema.SchemaReference;
import javax.wadls.factory.*;
import javax.wadls.xml.*;
import javax.wadls.Effect;
import javax.wadls.PreCondition;
import javax.wadls.extensions.ExtensionRegistry;



import javax.wadls.extensions.ExtensibilityElement;
import javax.wadls.extensions.ExtensionDeserializer;
import javax.wadls.factory.WADLFactory;

import edu.uga.cs.lsdis.meteors.wadls.*;
import edu.uga.cs.lsdis.meteors.wadls.extensions.schema.SchemaConstants;
import edu.uga.cs.lsdis.meteors.wadls.extensions.schema.SchemaSerializer;
import edu.uga.cs.lsdis.meteors.wadls.util.*;
import edu.uga.cs.lsdis.meteors.wadls.util.xml.*;
import edu.uga.cs.lsdis.meteors.wadls.Constants;
import edu.uga.cs.lsdis.meteors.wadls.util.xml.QNameUtils;
import edu.uga.cs.lsdis.meteors.wadls.util.StringUtils;
import edu.uga.cs.lsdis.meteors.wadls.util.xml.XPathUtils;
import edu.uga.cs.lsdis.meteors.wadls.extensions.schema.SchemaDeserializer;


/**
 * This class describes a collection of methods
 * that enable conversion of a WSDL-S document (in XML,
 * following the WSDL schema described in the WSDL
 * specification) into a WSDL-S model.
 *
 * @author Zixin Wu (wuzixin@uga.edu)
 * @author Matthew J. Duftler
 * @author Nirmal Mukhi
 */
public class WADLReaderImpl implements WADLReader
{
	
	static {
		Constants.setSemanticExtensionURI(Constants.SemanticExtensionType.SAWADL);
	}
	// Used for determining the style of operations.
	private static final List STYLE_ONE_WAY =
		Arrays.asList(new String[]{Constants.ELEM_INPUT});
	private static final List STYLE_REQUEST_RESPONSE =
		Arrays.asList(new String[]{Constants.ELEM_INPUT, Constants.ELEM_OUTPUT});
	private static final List STYLE_SOLICIT_RESPONSE =
		Arrays.asList(new String[]{Constants.ELEM_OUTPUT, Constants.ELEM_INPUT});
	private static final List STYLE_NOTIFICATION =
		Arrays.asList(new String[]{Constants.ELEM_OUTPUT});
	
	protected boolean verbose = true;
	protected ExtensionRegistry extReg = null;
	protected boolean importDocuments = true;
	protected boolean parseSAWSDL = false;
	protected String factoryImplName = null;
	protected WADLLocator loc = null;
	
	//Contains all schemas used by this wsdl, either in-line or nested 
	//via wsdl imports or schema imports, includes or redefines
	protected Map allSchemas = new Hashtable();
	
	private String WORKING_SEMANTIC_NAMESPACE = Constants.NS_URI_SAWADL;
	
	
	/**
	 * Sets the specified feature to the specified value.
	 * <p>
	 * The supported features are:
	 * <p>
	 * <table border=1>
	 *   <tr>
	 *     <th>Name</th>
	 *     <th>Description</th>
	 *     <th>Default Value</th>
	 *   </tr>
	 *   <tr>
	 *     <td><center>javax.wsdls.verbose</center></td>
	 *     <td>If set to true, status messages will be displayed.</td>
	 *     <td><center>true</center></td>
	 *   </tr>
	 *   <tr>
	 *     <td><center>javax.wsdls.importDocuments</center></td>
	 *     <td>If set to true, imported WSDL documents will be
	 *         retrieved and processed.</td>
	 *     <td><center>true</center></td>
	 *   </tr>
	 * </table>
	 * <p>
	 * All feature names must be fully-qualified, Java package style. All
	 * names starting with javax.wsdls. are reserved for features defined
	 * by the JWSDL specification. It is recommended that implementation-
	 * specific features be fully-qualified to match the package name
	 * of that implementation. For example: com.abc.featureName
	 *
	 * @param name the name of the feature to be set.
	 * @param value the value to set the feature to.
	 * @throws IllegalArgumentException if the feature name is not recognized.
	 * @see #getFeature(String)
	 */
	public void setFeature(String name, boolean value)
	throws IllegalArgumentException
	{
		if (name == null)
		{
			throw new IllegalArgumentException("Feature name must not be null.");
		}
		
		if (name.equals(Constants.FEATURE_VERBOSE))
		{
			verbose = value;
		}
		else if (name.equals(Constants.FEATURE_IMPORT_DOCUMENTS))
		{
			importDocuments = value;
		} else if(name.equals(Constants.FEATURE_PARSE_SAWADL)) {
			if(value) {
				WORKING_SEMANTIC_NAMESPACE = Constants.NS_URI_SAWADL;
				Constants.setSemanticExtensionURI(Constants.SemanticExtensionType.SAWADL);
			} else {
				WORKING_SEMANTIC_NAMESPACE = Constants.NS_URI_WADLS;
				Constants.setSemanticExtensionURI(Constants.SemanticExtensionType.WADLS);
			}
			parseSAWSDL = value;
		}
		else
		{
			throw new IllegalArgumentException("Feature name '" + name +
			"' not recognized.");
		}
	}
	
	/**
	 * Gets the value of the specified feature.
	 *
	 * @param name the name of the feature to get the value of.
	 * @throws IllegalArgumentException if the feature name is not recognized.
	 * @see #setFeature(String, boolean)
	 */
	public boolean getFeature(String name) throws IllegalArgumentException
	{
		if (name == null)
		{
			throw new IllegalArgumentException("Feature name must not be null.");
		}
		
		if (name.equals(Constants.FEATURE_VERBOSE))
		{
			return verbose;
		}
		else if (name.equals(Constants.FEATURE_IMPORT_DOCUMENTS))
		{
			return importDocuments;
		}
		else
		{
			throw new IllegalArgumentException("Feature name '" + name +
			"' not recognized.");
		}
	}
	
	public void setExtensionRegistry(ExtensionRegistry extReg)
	{
		this.extReg = extReg;
	}
	
	/**
	 * Get the extension registry, if one was set. Default is
	 * null.
	 */
	public ExtensionRegistry getExtensionRegistry()
	{
		return extReg;
	}
	
	/**
	 * Set the extension registry to be used when reading
	 * WSDL documents into a WSDL definition. If an
	 * extension registry is set, that is the extension
	 * registry that will be set as the extensionRegistry
	 * property of the definitions resulting from invoking
	 * readWSDL(...). Default is null.
	 *
	 * @param extReg the extension registry to use for new
	 * definitions
	 */
	
	
	
	
	/**
	 * Set a different factory implementation to use for
	 * creating definitions when reading WSDL documents.
	 * As some WSDLReader implementations may only be
	 * capable of creating definitions using the same
	 * factory implementation from which the reader was
	 * obtained, this method is optional. Default is null.
	 *
	 * @param factoryImplName the fully-qualified class name of the
	 * class which provides a concrete implementation of the abstract
	 * class WSDLFactory.
	 * @throws UnsupportedOperationException if this method
	 * is invoked on an implementation which does not
	 * support it.
	 */
	public void setFactoryImplName(String factoryImplName)
	throws UnsupportedOperationException
	{
		this.factoryImplName = factoryImplName;
	}
	
	/**
	 * Get the factoryImplName, if one was set. Default is null.
	 */
	public String getFactoryImplName()
	{
		return factoryImplName;
	}
	
	protected Application parseApplications(String documentBaseURI,
			Element defEl,
			Map importedDefs)
	throws WADLSException, URISyntaxException
	{
		checkElementName(defEl, Constants.Q_ELEM_DEFINITIONS);
		
		WADLFactory factory = (factoryImplName != null)
		? WADLFactory.newInstance(factoryImplName)
				: WADLFactory.newInstance();
		Application def = factory.newApplication();
		
		
		
		String name = DOMUtils.getAttribute(defEl, Constants.ATTR_NAME);
		String targetNamespace = DOMUtils.getAttribute(defEl,
				Constants.ATTR_TARGET_NAMESPACE);
		System.out.println("Target Name Space:"+targetNamespace);
		NamedNodeMap attrs = defEl.getAttributes();
		
		if (documentBaseURI != null)
		{
			def.setDocumentBaseURI(documentBaseURI);
		}
		
		if (name != null)
		{
			def.setQName(new QName(targetNamespace, name));
		}
		
		if (targetNamespace != null)
		{
			def.setTargetNamespace(targetNamespace);
		}
		
		int size = attrs.getLength();
		
		for (int i = 0; i < size; i++)
		{
			Attr attr = (Attr)attrs.item(i);
			String namespaceURI = attr.getNamespaceURI();
			String localPart = attr.getLocalName();
			String value = attr.getValue();
					
			
			if (namespaceURI != null && namespaceURI.equals(Constants.NS_URI_XMLNS))
			{
				if (localPart != null && !localPart.equals(Constants.ATTR_XMLNS))
				{
					System.out.println("LocalPart is set to "+localPart+" and it's value is "+value);
					def.addNamespace(localPart, value);
				}
				else
				{
					System.out.println("LocalPart is set to null and it's value is "+value);
					def.addNamespace(null, value);
				}
			}
		}
		
		Element tempEl = DOMUtils.getFirstChildElement(defEl);
		System.out.println("%%%% ");
		System.out.println("%%%% First Child: "+tempEl.getNodeName());
		
		while (tempEl != null)
		{
			if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl))
			{
				System.out.println("%%%% Documentation Element:"+tempEl.getTextContent());
				def.setDocumentationElement(tempEl);
			}
			else if (QNameUtils.matches(Constants.Q_ELEM_GRAMMARS, tempEl))
			{
				System.out.println("%%%% Grammars element is parsed.");
				def.setGrammars(parseGrammars(tempEl, def));
			}
		    else if (QNameUtils.matches(Constants.Q_ELEM_RESOURCES, tempEl)){
				
		      System.out.println("%%%% Resources Element is parsed.");
		      String path = DOMUtils.getAttribute(tempEl, Constants.ATTR_BASE);
		      def.setResourcesPath(path);
		      System.out.println("Resources path is:"+path);
			  Element tempEl1 = DOMUtils.getFirstChildElement(tempEl);
			  for (; tempEl1 != null; tempEl1 = DOMUtils.getNextSiblingElement(tempEl1)){
			  if (QNameUtils.matches(Constants.Q_ELEM_RESOURCE, tempEl1))
				{
					def.addResource(parseResource(tempEl1, def));
				}
			  }
			
			}
		    else{
		    	
		    }
		
			tempEl = DOMUtils.getNextSiblingElement(tempEl);
		}
		
		return def;
	}
	
	protected Include parseInclude(Element importEl,
			Application def,
			Map importedDefs)
	throws WADLSException
	{
		Include importDef = def.createInclude();
		
		try
		{
			String namespaceURI = DOMUtils.getAttribute(importEl,
					Constants.ATTR_NAMESPACE);
			String locationURI = DOMUtils.getAttribute(importEl,
					Constants.ATTR_LOCATION);
			String contextURI = null;
			
			if (namespaceURI != null)
			{
				importDef.setNamespaceURI(namespaceURI);
			}
			
			if (locationURI != null)
			{
				importDef.setLocationURI(locationURI);
				
				if (importDocuments)
				{
					try
					{
						contextURI = def.getDocumentBaseURI();
						Application importedDef = null;
						InputStream inputStream = null;
						InputSource inputSource = null;
						URL url = null;
						
						if (loc != null)
						{
							inputSource = loc.getImportInputSource(contextURI, locationURI);
							
							/*
							 We now have available the latest import URI. This might
							 differ from the locationURI so check the importedDefs for it
							 since it is this that we pass as the documentBaseURI later.
							 */
							String liu = loc.getLatestImportURI();
							
							importedDef = (Application)importedDefs.get(liu);
						}
						else
						{
							URL contextURL = (contextURI != null)
							? StringUtils.getURL(null, contextURI)
									: null;
							
							url = StringUtils.getURL(contextURL, locationURI);
							importedDef = (Application)importedDefs.get(url.toString());
							
							if (importedDef == null)
							{
								inputStream = StringUtils.getContentAsInputStream(url);
								
								if (inputStream != null)
								{
									inputSource = new InputSource(inputStream);
								}
							}
						}
						
						if (importedDef == null)
						{
							if (inputSource == null)
							{
								throw new WADLSException(WADLSException.OTHER_ERROR,
										"Unable to locate imported document " +
										"at '" + locationURI + "'" +
										(contextURI == null
												? "."
														: ", relative to '" + contextURI +
										"'."));
							}
							
							inputSource.setSystemId(url.toString());
							Document doc = getDocument(inputSource, url.toString());
							
							if (inputStream != null)
							{
								inputStream.close();
							}
							
							Element documentElement = doc.getDocumentElement();
							
							/*
							 Check if it's a wsdl document.
							 If it's not, don't retrieve and process it.
							 This should later be extended to allow other types of
							 documents to be retrieved and processed, such as schema
							 documents (".xsd"), etc...
							 */
							if (QNameUtils.matches(Constants.Q_ELEM_DEFINITIONS,
									documentElement))
							{
								if (verbose)
								{
									System.out.println("Retrieving document at '" + locationURI +
											"'" +
											(contextURI == null
													? "."
															: ", relative to '" + contextURI + "'."));
								}
								
								String urlString =
									(loc != null)
									? loc.getLatestImportURI()
											: (url != null)
											? url.toString()
													: locationURI;
											
											importedDef = readWADL(urlString,
													documentElement,
													importedDefs);
							}
							else
							{
								QName docElementQName = QNameUtils.newQName(documentElement);
								
								if (SchemaConstants.XSD_QNAME_LIST.contains(docElementQName))
								{
									WADLFactory factory =
										(factoryImplName != null)
										? WADLFactory.newInstance(factoryImplName)
												: WADLFactory.newInstance();
										
										importedDef = factory.newApplication();
										
									
										String urlString =
											(loc != null)
											? loc.getLatestImportURI()
													: (url != null)
													? url.toString()
															: locationURI;
													
													importedDef.setDocumentBaseURI(urlString);
													
													Params types = importedDef.createParams();
													importedDef.setParams(types);
								}
							}
						}
						
						if (importedDef != null)
						{
							importDef.setApplication(importedDef);
						}
					}
					catch (WADLSException e)
					{
						throw e;
					}
					catch (Throwable t)
					{
						throw new WADLSException(WADLSException.OTHER_ERROR,
								"Unable to resolve imported document at '" +
								locationURI + 
								(contextURI == null 
										? "'." : "', relative to '" + contextURI + "'")
										, t);
					}
				} //end importDocs
			} //end locationURI
			
		}
		catch (WADLSException e)
		{
			if (e.getLocation() == null)
			{
				e.setLocation(XPathUtils.getXPathExprFromNode(importEl));
			}
			else
			{
				//If definitions are being parsed recursively for nested imports
				//the exception location must be built up recursively too so
				//prepend this element's xpath to exception location.
				String loc = XPathUtils.getXPathExprFromNode(importEl) + e.getLocation();
				e.setLocation(loc);
			}
			
			throw e; 
		}
		
		Element tempEl = DOMUtils.getFirstChildElement(importEl);
		
		while (tempEl != null)
		{
			if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl))
			{
				importDef.setDocumentationElement(tempEl);
			}
			else
			{
				DOMUtils.throwWADLException(tempEl);
			}
			
			tempEl = DOMUtils.getNextSiblingElement(tempEl);
		}
		
		
		return importDef; 
		
	}
	

	
	protected Grammars parseGrammars(Element typesEl, Application def)
	throws WADLSException
	{
		Grammars grammars = def.createGrammars();
		List<String> schemaList =new Vector();
		List<Schema> docElement =new Vector();
		List<String> targetNS =new Vector();	
		Element tempEl = DOMUtils.getFirstChildElement(typesEl);
		QName tempElType;
			
		while (tempEl != null)
		{
			tempElType = QNameUtils.newQName(tempEl);
			
			if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl))
			{
				grammars.setDocumentationElement(tempEl);
			}
			else if (QNameUtils.matches(Constants.Q_ELEM_INCLUDE, tempEl))
			{
				String xsd = DOMUtils.getAttribute(tempEl, Constants.ELEM_HREF);
				schemaList.add(xsd);
				System.out.println("Xsd element in Grammars tag:"+xsd);
				
				docElement.add(parseSchema(tempEl,def));
				//targetNS.add(parseSchemaNS(tempEl,def));
				List remainingAttrs = DOMUtils.getAttributes(tempEl);
				//the element qname indicates it is a schema.
				String modelReference = DOMUtils.getAttributeNS(tempEl,
						WORKING_SEMANTIC_NAMESPACE, 
						Constants.ATTR_MODELREF,
						remainingAttrs);
				System.out.println("XSD Element's model reference is:"+modelReference);
				if (modelReference != null)
				{
					try {
						parseModelReference(modelReference, def, grammars);
					} catch (URISyntaxException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					 /*ModelReference mr = def.createModelReference();
					 mr.valueOf(modelReference, def);
					 mr.setParent(preCondition);
					 preCondition.addModelReference(mr);*/
				}
				
		  }
					
			tempEl = DOMUtils.getNextSiblingElement(tempEl);
		}
		grammars.setSchemas(this.allSchemas);
		Map temp = grammars.getSchemas();
		System.out.println("Schemas added to grammars class:"+temp.size());
		return grammars;
	}
	
	
protected Schema parseSchema(Element el,Application def)
	throws WADLSException
	{
		/*
		 * This method returns ExtensibilityElement rather than Schema because we
		 * do not insist that a suitable XSD schema deserializer is registered.
		 * PopulatedExtensionRegistry registers SchemaDeserializer by default, but 
		 * if the user chooses not to register a suitable deserializer then the
		 * UnknownDeserializer will be used, returning an UnknownExtensibilityElement. 
		 */

	
		Schema schema = null;
		SchemaReference schemaRef = null;
		try
		{
			
			QName elementType = QNameUtils.newQName(el);
	
			edu.uga.cs.lsdis.meteors.wadls.extensions.schema.SchemaDeserializer scDS = new edu.uga.cs.lsdis.meteors.wadls.extensions.schema.SchemaDeserializer();
			
			//Now unmarshall the DOM element.
			Schema ee =  
				scDS.unmarshall(elementType, el, def);
			
			if (ee instanceof Schema)
			{
				
				schema = (Schema) ee;
			}
			String location = null;
				
			//Keep track of parsed schemas to avoid duplicating Schema objects
			//through duplicate or circular references (eg: A imports B imports A).
			if (schema.getDocumentBaseURI() != null) 
			{		
			
				
				this.allSchemas.put(schema.getDocumentBaseURI(), schema);
			}

			ArrayList allSchemaRefs = new ArrayList();
			
			Collection ic = schema.getImports().values();
			
	
			Iterator importsIterator = ic.iterator();
			while(importsIterator.hasNext())
			{
				allSchemaRefs.addAll( (Collection) importsIterator.next() );
			}
			
			allSchemaRefs.addAll(schema.getIncludes());
			allSchemaRefs.addAll(schema.getRedefines());
			
			//Then, retrieve the schema referred to by each schema reference. If the 
			//schema has been read in previously, use the existing schema object. 
			//Otherwise unmarshall the DOM element into a new schema object.
			
			ListIterator schemaRefIterator = allSchemaRefs.listIterator();
			
			
			while(schemaRefIterator.hasNext()){
	
				try
				{
					schemaRef = (SchemaReference) schemaRefIterator.next();
					
					if (schemaRef.getSchemaLocationURI() == null)
					{
						
						//cannot get the referenced schema, so ignore this schema reference
						continue;
					}
					
					if (verbose)
					{
						System.out.println("change: Retrieving schema at '" + 
								schemaRef.getSchemaLocationURI() +
								(schema.getDocumentBaseURI() == null
										? "'."
												: "', relative to '" + 
												schema.getDocumentBaseURI() + "'."));
					}
					
					
					InputStream inputStream = null;
					InputSource inputSource = null;
					
					
					
					//This is the child schema referred to by the schemaReference
					Schema referencedSchema = null;
					
					//This is the child schema's location obtained from the WSDLLocator or the URL
				
					
					if (loc != null)
					{
						
						//Try to get the referenced schema using the wsdl locator
						inputSource = loc.getImportInputSource(
								schema.getDocumentBaseURI(), schemaRef.getSchemaLocationURI());
						
						if (inputSource == null)
						{
							throw new WADLSException(WADLSException.OTHER_ERROR,
									"Unable to locate with a locator "
									+ "the schema referenced at '"
									+ schemaRef.getSchemaLocationURI() 
									+ "' relative to document base '"
									+ schema.getDocumentBaseURI() + "'");
						}
						location = loc.getLatestImportURI();
						
						
						//if a schema from this location has been read previously, use it.
						referencedSchema = (Schema) this.allSchemas.get(location);
					}
					else
					{
						// We don't have a wsdl locator, so try to retrieve the schema by its URL
						
						String contextURI = schema.getDocumentBaseURI();
						URL contextURL = (contextURI != null) ? StringUtils.getURL(null, contextURI) : null;
						//System.out.println("%%%% Context URL OF SCHEMA:"+contextURL);
						URL url = StringUtils.getURL(contextURL, schemaRef.getSchemaLocationURI());
						//System.out.println("%%%%URL :"+url);
						location = url.toExternalForm();
						//System.out.println("%%%% schema location:"+location);
						//if a schema from this location has been retrieved previously, use it.
						referencedSchema = (Schema) this.allSchemas.get(location);
						
						if (referencedSchema == null)
						{
							//System.out.println("%%%% Referenced Schema is equal to null");
							// We haven't read this schema in before so do it now
							inputStream = url.openStream();
							
							if (inputStream != null)
							{
								inputSource = new InputSource(inputStream);
							}
							
							if (inputSource == null)
							{
								throw new WADLSException(WADLSException.OTHER_ERROR,
										"Unable to locate with a url "
										+ "the document referenced at '"
										+ schemaRef.getSchemaLocationURI()
										+ "'"
										+ (contextURI == null ? "." : ", relative to '"
											+ contextURI + "'."));
							}
						}  
						
					} //end if loc
					
					// If we have not previously read the schema, get its DOM element now.
					if (referencedSchema == null)
					{
						//System.out.println("%%%% Referenced Schema is equal to null 2");
						inputSource.setSystemId(location);
						Document doc = getDocument(inputSource, location);
						
						if (inputStream != null)
						{
							inputStream.close();
						}
						
						Element documentElement = doc.getDocumentElement();
						NodeList nodeList = documentElement.getChildNodes();
			
						/*for(int i=0; i<nodeList.getLength(); i++){
							  Node childNode = nodeList.item(i);
							  System.out.println("Children$$$$ : "+childNode.getTextContent());
							  // Do something with childNode...
							}*/
						//System.out.println("#####Child Nodes:"+documentElement.getChildNodes());
						//System.out.println("%%%% documentElement:"+ documentElement.getNodeName());						
						// If it's a schema doc process it, otherwise the schema reference remains null
						
						QName docElementQName = QNameUtils.newQName(documentElement);
						
						if (SchemaConstants.XSD_QNAME_LIST.contains(docElementQName))
						{
							//We now need to call parseSchema recursively to parse the referenced
							//schema. The document base URI of the referenced schema will be set to 
							//the document base URI of the current schema plus the schemaLocation in 
							//the schemaRef. We cannot explicitly pass in a new document base URI
							//to the schema deserializer, so instead we will create a dummy 
							//Definition and set its documentBaseURI to the new document base URI. 
							//We can leave the other definition fields empty because we know
							//that the SchemaDeserializer.unmarshall method uses the definition 
							//parameter only to get its documentBaseURI. If the unmarshall method
							//implementation changes (ie: its use of definition changes) we may need 
							//to rethink this approach.
							//System.out.println("%%%%%SchemaConstants.XSD_QNAME_LIST.contains(docElementQName)"+docElementQName.getLocalPart());
							
							WADLFactory factory = (factoryImplName != null)
							? WADLFactory.newInstance(factoryImplName)
									: WADLFactory.newInstance();
							Application dummyDef = factory.newApplication();
							
							dummyDef.setDocumentBaseURI(location);
							//System.out.println("%%%% End of Parse Schema");
							//By this point, we know we have a SchemaDeserializer registered
							//so we can safely cast the ExtensibilityElement to a Schema.
							referencedSchema = (Schema) parseSchema( documentElement, 
									dummyDef);
						}
						
					} //end if referencedSchema
					
					schemaRef.setReferencedSchema(referencedSchema);  	
				}
				catch (WADLSException e)
				{
					throw e;
				}
				catch (Throwable t)
				{
					throw new WADLSException(WADLSException.OTHER_ERROR,
							"An error occurred trying to resolve schema referenced at '" 
							+ schemaRef.getSchemaLocationURI() 
							+ "'"
							+ (schema.getDocumentBaseURI() == null ? "." : ", relative to '"
								+ schema.getDocumentBaseURI() + "'."),
								t);
				}
				
			} //end while loop
			
			return schema;
			
		}
		catch (WADLSException e)
		{
			if (e.getLocation() == null)
			{
				e.setLocation(XPathUtils.getXPathExprFromNode(el));
			}
			else
			{
				//If this method has been called recursively for nested schemas
				//the exception location must be built up recursively too so
				//prepend this element's xpath to exception location.
				String loc = XPathUtils.getXPathExprFromNode(el) + e.getLocation();
				e.setLocation(loc);
			}
			
			throw e; 
		}
		
	}
	
	
	

	protected Resource parseResource(Element portTypeEl, Application def)
	throws WADLSException, URISyntaxException
	{
		Resource portType = null;
		String path = DOMUtils.getAttribute(portTypeEl, Constants.RESOURCE_ATTR_NAME);
		List remainingAttrs = DOMUtils.getAttributes(portTypeEl);
		//read modelReference
		//String modelReference= null;
		if (path != null)
		{
			QName resourceName = new QName(def.getTargetNamespace(), path);
			System.out.println("Resource Path:"+path);
			System.out.println("ResourceName:"+resourceName.toString());
			
			portType = def.getResource(resourceName);
			
			if (portType == null)
			{
				portType = def.createResource();
				portType.setQName(resourceName);
			}
		}
		else
		{
			portType = def.createResource();
		}
		
		// Whether it was retrieved or created, the definition has been found.
		portType.setUndefined(false);
		String modelReference = DOMUtils.getAttributeNS(portTypeEl,
				WORKING_SEMANTIC_NAMESPACE, 
				Constants.ATTR_MODELREF,
				remainingAttrs);
		System.out.println("Resource modelreference:"+modelReference);
		if (modelReference != null)
		{
			parseModelReference(modelReference, def, portType);
			 /*ModelReference mr = def.createModelReference();
			 mr.valueOf(modelReference, def);
			 mr.setParent(preCondition);
			 preCondition.addModelReference(mr);*/
		}
		
		Element tempEl = DOMUtils.getFirstChildElement(portTypeEl);
				
		while (tempEl != null)
		{
			if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl))
			{
				portType.setDocumentationElement(tempEl);
			}
			else if (QNameUtils.matches(Constants.Q_ELEM_OPERATION, tempEl))
			{
				Method op = parseMethod(tempEl, portType, def);
				
				if (op != null)
				{
					portType.addMethod(op);
				}
			}
			else
			{
				DOMUtils.throwWADLException(tempEl);
			}
			
			tempEl = DOMUtils.getNextSiblingElement(tempEl);
		}
		
		return portType;
	}
	
	/**
	 * This is for Ajith and Kats. Just make sure we handle the SAWSDL and WSDLS namespaces properly. 
	 * The point being that we still might have to support wsdls and hence we want to see if we can use this operation with an internal
	 * flag indicating if the parser is being used in the context of WSDLS or SAWSDL.
	 * @param opEl
	 * @param portType
	 * @param def
	 * @return
	 * @throws WADLSException
	 * @throws URISyntaxException
	 */
	protected Method parseMethod(Element opEl,
			Resource portType,
			Application def)
	throws WADLSException, URISyntaxException
	{
		Method op = null;
		List remainingAttrs = DOMUtils.getAttributes(opEl);
		String name = DOMUtils.getAttribute(opEl, Constants.ID_NAME, remainingAttrs);
		//read modelReference
		//String modelReference= null;
		
		String parameterOrderStr = DOMUtils.getAttribute(opEl,
				Constants.ATTR_PARAMETER_ORDER,
				remainingAttrs);
		
		
		Element tempEl = DOMUtils.getFirstChildElement(opEl);
		List messageOrder = new Vector();
		Element docEl = null;
		Request input = null;
		Response output = null;
		PreCondition preCondition = null;
		Effect effect = null;
		List extElements = new Vector();
		boolean retrieved = true;
		
		while (tempEl != null)
		{
			if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl))
			{
				docEl = tempEl;
			}
			else if (QNameUtils.matches(Constants.Q_ELEM_INPUT, tempEl))
			{
				input = parseRequest(tempEl, def);
				
			}
			else if (QNameUtils.matches(Constants.Q_ELEM_PRECON, tempEl))
			{
				preCondition = parsePreCondition(tempEl, def);
			}
			else if (QNameUtils.matches(Constants.Q_ELEM_EFFECT, tempEl))
			{
				effect = parseEffect(tempEl, def);
				
			}
			else if (QNameUtils.matches(Constants.Q_ELEM_OUTPUT, tempEl))
			{
				output = parseResponse(tempEl, def);
			}
			tempEl = DOMUtils.getNextSiblingElement(tempEl);
		}
		
		if (name != null)
		{
			String inputName = (input != null ? input.getName() : null);
			String outputName = (output != null ? output.getName() : null);
			
			op = portType.getMethod(name, inputName, outputName);
			
			if (op != null && !op.isUndefined())
			{
				op = null;
			}
			
			if (op != null)
			{
				if (inputName == null)
				{
					Request tempIn = op.getRequest();
					
					if (tempIn != null)
					{
						if (tempIn.getName() != null)
						{
							op = null;
						}
					}
				}
			}
			
			if (op != null)
			{
				if (outputName == null)
				{
					Response tempOut = op.getResponse();
					
					if (tempOut != null)
					{
						if (tempOut.getName() != null)
						{
							op = null;
						}
					}
				}
			}
			
			if (op == null)
			{
				op = def.createMethod();
				op.setName(name);
				retrieved = false;
			}
		}
		else
		{
			op = def.createMethod();
			retrieved = false;
		}
		
		// Whether it was retrieved or created, the definition has been found.
		op.setUndefined(false);
		
		if (parameterOrderStr != null)
		{
			op.setParameterOrdering(StringUtils.parseNMTokens(parameterOrderStr));
		}
		
		if (docEl != null)
		{
			op.setDocumentationElement(docEl);
		}
		
		if (input != null)
		{
			op.setRequest(input);
		}
		
		if (output != null)
		{
			op.setResponse(output);
		}
		
	   if (preCondition != null)
		{
			op.setPreCondition(preCondition);
		}
	   String modelReference = DOMUtils.getAttributeNS(opEl,
				WORKING_SEMANTIC_NAMESPACE, 
				Constants.ATTR_MODELREF,
				remainingAttrs);
        System.out.println("Model Reference of method:"+modelReference);
		if (modelReference != null)
		{
			parseModelReference(modelReference, def, op);
			 /*ModelReference mr = def.createModelReference();
			 mr.valueOf(modelReference, def);
			 mr.setParent(preCondition);
			 preCondition.addModelReference(mr);*/
		}
		if (effect != null)
		{
			op.setEffect(effect);
		}
		
		
		if (retrieved)
		{
			op = null;
		}
		
		return op;
	}
	
	
	
	
	protected Request parseRequest(Element inputEl, Application def)
	throws WADLSException
	{
		Request input = def.createRequest();
		List<String> inputXSDList = new ArrayList<String>(10);
		List<Param> paramList = new ArrayList<Param>(20);
		Element tempEl = DOMUtils.getFirstChildElement(inputEl);
		List remainingAttrs = DOMUtils.getAttributes(inputEl);
		String modelReference = DOMUtils.getAttributeNS(inputEl,
				WORKING_SEMANTIC_NAMESPACE, 
				Constants.ATTR_MODELREF,
				remainingAttrs);
        System.out.println("Model reference for request:"+modelReference);
		if (modelReference != null)
		{
			try {
				parseModelReference(modelReference, def, input);
			} catch (URISyntaxException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			 /*ModelReference mr = def.createModelReference();
			 mr.valueOf(modelReference, def);
			 mr.setParent(preCondition);
			 preCondition.addModelReference(mr);*/
		}
		while (tempEl != null)
		{
			if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl))
			{
				input.setDocumentationElement(tempEl);
			}
			else if (QNameUtils.matches(Constants.Q_ELEM_REPRESENTATION, tempEl))
			{
				String inputXSD = DOMUtils.getAttribute(tempEl, Constants.REQUEST_ELEMENT_NAME);
				//input.setName(inputXSD);
				inputXSDList.add(inputXSD);
				System.out.println("InPut XSD : "+inputXSD);
			}
			else if (QNameUtils.matches(Constants.Q_ELEM_PARAM, tempEl))
			{
				System.out.println("New paramter is added to request");
				Param param = new ParamImpl();
				List remainingParamAttrs = DOMUtils.getAttributes(tempEl);
				String parammodelReference = DOMUtils.getAttributeNS(tempEl,
						WORKING_SEMANTIC_NAMESPACE, 
						Constants.ATTR_MODELREF,
						remainingAttrs);
				String liftingschema = DOMUtils.getAttributeNS(tempEl,
						WORKING_SEMANTIC_NAMESPACE, 
						Constants.ATTR_LIFTINGSCHEMAMAPPING,
						remainingAttrs);
				String loweringschema = DOMUtils.getAttributeNS(tempEl,
						WORKING_SEMANTIC_NAMESPACE, 
						Constants.ATTR_LOWERINGSCHEMAMAPPING,
						remainingAttrs);
				
				param.setModelreference(parammodelReference);
				param.setLiftingschemamapping(liftingschema);
				param.setLoweringschemamapping(loweringschema);
				//param.setModelreference(liftingschema);
				//param.setModelreference(loweringschema);
				
				String style = DOMUtils.getAttribute(tempEl, Constants.PARAM_STYLE);
				System.out.println("Param Style:"+style);
				String type = DOMUtils.getAttribute(tempEl, Constants.PARAM_TYPE);
				System.out.println("Param Type:"+type);
				
				param.setName(DOMUtils.getAttribute(tempEl, Constants.PARAM_NAME));
				param.setDefault1(DOMUtils.getAttribute(tempEl, Constants.PARAM_DEFAULT));
				param.setRequired(DOMUtils.getAttribute(tempEl, Constants.PARAM_REQUIRED));
				
				
				if(type!=null){					
					param.setType(type);
				}
				
					List<String> optionValue = new ArrayList<String>(30);
					Element paramoption = DOMUtils.getFirstChildElement(tempEl);


					for (; paramoption != null; paramoption = DOMUtils.getNextSiblingElement(paramoption))
					{
						if(paramoption.getLocalName().toString().equals("option")){
						optionValue.add(DOMUtils.getAttribute(paramoption, Constants.OPTION_VALUE));
						System.out.println("Param Option Value:"+DOMUtils.getAttribute(paramoption, Constants.OPTION_VALUE));
						}
					}
					
					param.setOptionvalue(optionValue);
				
				
				paramList.add(param);
			
			}
			else
			{
				DOMUtils.throwWADLException(tempEl);
			}
			tempEl = DOMUtils.getNextSiblingElement(tempEl);
		}
		
		input.setInputXSDList(inputXSDList);
		input.setParamList(paramList);
		return input;
	}
	
	protected Response parseResponse(Element outputEl, Application def)
	throws WADLSException
	{
		Response output = def.createResponse();
		List<String> outputXSDList = new ArrayList<String>(10);
		List<Param> paramList = new ArrayList<Param>(20);
		String name = DOMUtils.getAttribute(outputEl, Constants.ATTR_NAME);
		QName messageName = getQualifiedAttributeValue(outputEl,
				Constants.ATTR_MESSAGE,
				Constants.ELEM_OUTPUT,
				def);
		
		if (name != null)
		{
			output.setName(name);
		}
		List remainingAttrs = DOMUtils.getAttributes(outputEl);
		String modelReference = DOMUtils.getAttributeNS(outputEl,
				WORKING_SEMANTIC_NAMESPACE, 
				Constants.ATTR_MODELREF,
				remainingAttrs);
		System.out.println("Model reference for response:"+modelReference);
		if (modelReference != null)
		{
			try {
				parseModelReference(modelReference, def, output);
			} catch (URISyntaxException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			 /*ModelReference mr = def.createModelReference();
			 mr.valueOf(modelReference, def);
			 mr.setParent(preCondition);
			 preCondition.addModelReference(mr);*/
		}
		Element tempEl = DOMUtils.getFirstChildElement(outputEl);
		
		while (tempEl != null)
		{
			if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl))
			{
				output.setDocumentationElement(tempEl);
			}
			else if (QNameUtils.matches(Constants.Q_ELEM_REPRESENTATION, tempEl))
			{
				String outputXSD = DOMUtils.getAttribute(tempEl, Constants.REQUEST_ELEMENT_NAME);
				//output.setName(outputXSD);
				outputXSDList.add(outputXSD);
				System.out.println("OutPut XSD:"+outputXSD);
				
			}
			else if (QNameUtils.matches(Constants.Q_ELEM_PARAM, tempEl))
			{
				Param param = new ParamImpl();
				List remainingParamAttrs = DOMUtils.getAttributes(tempEl);
				String parammodelReference = DOMUtils.getAttributeNS(tempEl,
						WORKING_SEMANTIC_NAMESPACE, 
						Constants.ATTR_MODELREF,
						remainingAttrs);
				String liftingschema = DOMUtils.getAttributeNS(tempEl,
						WORKING_SEMANTIC_NAMESPACE, 
						Constants.ATTR_LIFTINGSCHEMAMAPPING,
						remainingAttrs);
				String loweringschema = DOMUtils.getAttributeNS(tempEl,
						WORKING_SEMANTIC_NAMESPACE, 
						Constants.ATTR_LOWERINGSCHEMAMAPPING,
						remainingAttrs);
				
				param.setModelreference(parammodelReference);
				param.setModelreference(liftingschema);
				param.setModelreference(loweringschema);
				
				String style = DOMUtils.getAttribute(tempEl, Constants.PARAM_STYLE);
				String type = DOMUtils.getAttribute(tempEl, Constants.PARAM_TYPE);
				
				param.setName(DOMUtils.getAttribute(tempEl, Constants.PARAM_NAME));
				param.setDefault1(DOMUtils.getAttribute(tempEl, Constants.PARAM_DEFAULT));
				param.setRequired(DOMUtils.getAttribute(tempEl, Constants.PARAM_REQUIRED));
				
				if(style.equalsIgnoreCase("query") && type!=null){					
					param.setType(type);
				}
				else{
					List<String> optionValue = new ArrayList<String>(30);
					Element paramoption = DOMUtils.getFirstChildElement(tempEl);


					for (; paramoption != null; paramoption = DOMUtils.getNextSiblingElement(paramoption))
					{
						optionValue.add(DOMUtils.getAttribute(paramoption, Constants.OPTION_VALUE));
					}
					
					param.setOptionvalue(optionValue);
				 }
				
				paramList.add(param);
			
			}
			
			else
			{
				DOMUtils.throwWADLException(tempEl);
			}
			
			tempEl = DOMUtils.getNextSiblingElement(tempEl);
		}
		
		output.setInputXSDList(outputXSDList);
		output.setParamList(paramList);
		
		return output;
	}
	
	protected PreCondition parsePreCondition(Element preConEl, Application def)
	throws WADLSException, URISyntaxException
	{
		PreCondition preCondition = def.createPreCondition();
		
		//String name = DOMUtils.getAttribute(preConEl, Constants.ATTR_NAME);
		String attrModelReference = DOMUtils.getQualifiedValue(WORKING_SEMANTIC_NAMESPACE, Constants.ATTR_MODELREF, def);
		String modelReference = DOMUtils.getAttribute(preConEl, attrModelReference);
		String expression = DOMUtils.getAttribute(preConEl, Constants.ATTR_EXPRESSION);
		System.out.println("Pre Condition:"+expression);
		

		if (modelReference != null)
		{
			parseModelReference(modelReference, def, preCondition);
			 /*ModelReference mr = def.createModelReference();
			 mr.valueOf(modelReference, def);
			 mr.setParent(preCondition);
			 preCondition.addModelReference(mr);*/
		}
		
		if (expression != null)
		{
			preCondition.setExpression(expression);
		}
		
		
//		parseExtensibilityAttributes(preConEl, PreCondition.class, preCondition, def);
		
		return preCondition;
	}
	
	protected Effect parseEffect(Element effectEl, Application def)
	throws WADLSException, URISyntaxException
	{
		Effect effect = def.createEffect();
		//String name = DOMUtils.getAttribute(effectEl, Constants.ATTR_NAME);
		String attrModelReference = DOMUtils.getQualifiedValue(WORKING_SEMANTIC_NAMESPACE, Constants.ATTR_MODELREF, def);
		String modelReference = DOMUtils.getAttribute(effectEl, attrModelReference);
		String expression = DOMUtils.getAttribute(effectEl, Constants.ATTR_EXPRESSION);
		System.out.println("EFFECT:"+expression);
		
		/*if (name != null)
		{
			effect.setName(name);
		}*/
		
		if (modelReference != null)
		{
			parseModelReference(modelReference, def, effect);
			/*ModelReference mr = def.createModelReference();
			mr.valueOf(modelReference, def);
			mr.setParent(effect);
			effect.addModelReference(mr);*/
		}
		
		if (expression != null)
		{
			effect.setExpression(expression);
		}
		
				
//		parseExtensibilityAttributes(effectEl, Effect.class, effect, def);
		
		return effect;
	}
	
	/**
	 * This method should be used for elements that support extension
	 * attributes because it does not track unexpected remaining attributes.
	 */
	private static QName getQualifiedAttributeValue(Element el,
			String attrName,
			String elDesc,
			Application def)
	throws WADLSException
	{
		try
		{
			return DOMUtils.getQualifiedAttributeValue(el,
					attrName,
					elDesc,
					false,
					def);
		}
		catch (WADLSException e)
		{
			if (e.getFaultCode().equals(WADLSException.NO_PREFIX_SPECIFIED))
			{
				String attrValue = DOMUtils.getAttribute(el, attrName);
				
				return new QName(attrValue);
			}
			else
			{
				throw e;
			}
		}
	}
	
	/**
	 * This method should be used for elements that do not support extension
	 * attributes because it tracks unexpected remaining attributes.
	 */
	private static QName getQualifiedAttributeValue(Element el,
			String attrName,
			String elDesc,
			Application def,
			List remainingAttrs)
	throws WADLSException
	{
		try
		{
			return DOMUtils.getQualifiedAttributeValue(el,
					attrName,
					elDesc,
					false,
					def,
					remainingAttrs);
		}
		catch (WADLSException e)
		{
			if (e.getFaultCode().equals(WADLSException.NO_PREFIX_SPECIFIED))
			{
				String attrValue = DOMUtils.getAttribute(el, attrName, remainingAttrs);
				
				return new QName(attrValue);
			}
			else
			{
				throw e;
			}
		}
	}
	
	private static void checkElementName(Element el, QName qname)
	throws WADLSException
	{
		System.out.println("Element Name:"+el);
		System.out.println("Q Name:"+qname.toString());
		if (!QNameUtils.matches(qname, el))
		{
			WADLSException wsdlExc = new WADLSException(WADLSException.INVALID_WADL,
					"Expected element '" +
					qname + "'.");
			
			wsdlExc.setLocation(XPathUtils.getXPathExprFromNode(el));
			
			throw wsdlExc;
		}
	}
	
	private static Document getDocument(InputSource inputSource,
			String desc) throws WADLSException
			{
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		
		factory.setNamespaceAware(true);
		factory.setValidating(false);
		
		try
		{
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document doc = builder.parse(inputSource);
			
			return doc;
		}
		catch (Throwable t)
		{
			throw new WADLSException(WADLSException.XSDPARSER_ERROR,
					"Problem parsing '" + desc + "'.",
					t);
		}
			}
	
	  /**
	   * Read the WSDL document accessible via the given input stream
	   * @param wsdlIS a InputStream for a WSDL XML definition
	   * @return the definition.
	   * @throws WADLSException
	   */
	  public Application readWADL(InputStream wsdlIS)
	  	throws WADLSException
	  {
		    try
		    {
		      InputSource inputSource = new InputSource(wsdlIS);
		      Document doc = getDocument(inputSource, "");

		      wsdlIS.close();

		      //note that documentBaseURI will be null
		      //importing wsdl or schema should use absolution path/URL
		      Application def = readWADL(null, doc);

		      return def;
		    }
		    catch (WADLSException e)
		    {
		      throw e;
		    }
		    catch (Throwable t)
		    {
		      throw new WADLSException(WADLSException.OTHER_ERROR,
		                              "Unable to resolve imported document at '", t);
		    }
	  }
	  
	/**
	 * Read the WSDL document accessible via the specified
	 * URI into a WSDL definition.
	 *
	 * @param wsdlURI a URI (can be a filename or URL) pointing to a
	 * WSDL XML definition.
	 * @return the definition.
	 */
	public Application readWADL(String wsdlURI) throws WADLSException
	{
		return readWADL(null, wsdlURI);
	}
	
	/**
	 * Read the WSDL document accessible via the specified
	 * URI into a WSDL definition.
	 *
	 * @param contextURI the context in which to resolve the
	 * wsdlURI, if the wsdlURI is relative. Can be null, in which
	 * case it will be ignored.
	 * @param wsdlURI a URI (can be a filename or URL) pointing to a
	 * WSDL XML definition.
	 * @return the definition.
	 */
	public Application readWADL(String contextURI, String wsdlURI)
	throws WADLSException
	{
		try
		{
			if (verbose)
			{
				System.out.println("Retrieving document at '" + wsdlURI + "'" +
						(contextURI == null
								? "."
										: ", relative to '" + contextURI + "'."));
			}
			
			URL contextURL = (contextURI != null)
			? StringUtils.getURL(null, contextURI)
					: null;
			URL url = StringUtils.getURL(contextURL, wsdlURI);
			InputStream inputStream = url.openStream();
			InputSource inputSource = new InputSource(inputStream);
			inputSource.setSystemId(url.toString());
			Document doc = getDocument(inputSource, url.toString());
			
			inputStream.close();
			
			Application def = readWADL(url.toString(), doc);
			
			return def;
		}
		catch (WADLSException e)
		{
			throw e;
		}
		catch (Throwable t)
		{
			throw new WADLSException(WADLSException.OTHER_ERROR,
					"Unable to resolve imported document at '" +
					wsdlURI +
					(contextURI == null
							? "'."
									: "', relative to '" + contextURI + "'.")
									, t);
		}
	}
	
	/**
	 * Read the specified &lt;wsdl:definitions&gt; element into a WSDL
	 * definition.
	 *
	 * @param documentBaseURI the document base URI of the WSDL definition
	 * described by the element. Will be set as the documentBaseURI
	 * of the returned Definition. Can be null, in which case it
	 * will be ignored.
	 * @param definitionsElement the &lt;wsdl:definitions&gt; element
	 * @return the definition described by the element.
	 * @throws URISyntaxException 
	 */
	public Application readWADL(String documentBaseURI,
			Element definitionsElement)
	throws WADLSException, URISyntaxException
	{
		return readWADL(documentBaseURI, definitionsElement, null);
	}
	
	protected Application readWADL(String documentBaseURI,
			Element definitionsElement,
			Map importedDefs)
	throws WADLSException, URISyntaxException
	{
		return parseApplications(documentBaseURI, definitionsElement, importedDefs);
	}
	
	/**
	 * Read the specified WSDL document into a WSDL definition.
	 *
	 * @param documentBaseURI the document base URI of the WSDL definition
	 * described by the document. Will be set as the documentBaseURI
	 * of the returned Definition. Can be null, in which case it
	 * will be ignored.
	 * @param wsdlDocument the WSDL document, an XML
	 * document obeying the WSDL schema.
	 * @return the definition described in the document.
	 * @throws URISyntaxException 
	 */
	public Application readWADL(String documentBaseURI, Document wsdlDocument)
	throws WADLSException, URISyntaxException
	{
		return readWADL(documentBaseURI, wsdlDocument.getDocumentElement());
	}
	
	/**
	 * Read a WSDL document into a WSDL definition.
	 *
	 * @param documentBaseURI the document base URI of the WSDL definition
	 * described by the document. Will be set as the documentBaseURI
	 * of the returned Definition. Can be null, in which case it
	 * will be ignored.
	 * @param inputSource an InputSource pointing to the
	 * WSDL document, an XML document obeying the WSDL schema.
	 * @return the definition described in the document pointed to
	 * by the InputSource.
	 * @throws URISyntaxException 
	 */
	public Application readWADL(String documentBaseURI, InputSource inputSource)
	throws WADLSException, URISyntaxException
	{
		return readWADL(documentBaseURI,
				getDocument(inputSource, "- WSDL Document -"));
	}
	
	/**
	 * Read a WSDL document into a WSDL definition.
	 *
	 * @param locator A WSDLLocator object used to provide InputSources
	 * pointing to the wsdl file.
	 * @return the definition described in the document
	 * @throws URISyntaxException 
	 */
	public Application readWADL(WADLLocator locator) throws WADLSException, URISyntaxException
	{
		InputSource is = locator.getBaseInputSource();
		String base = locator.getBaseURI();
		
		if (is == null)
		{
			throw new WADLSException(WADLSException.OTHER_ERROR,
					"Unable to locate document at '" + base + "'.");
		}
		
		this.loc = locator;
		
		if (verbose)
		{
			System.out.println("Retrieving document at '" + base + "'.");
		}
		
		return readWADL(base, is);
	}
	
	protected List<ModelReference> parseModelReference (String modelReference, Application def, ModelReferenceExtensible op) throws URISyntaxException,WADLSException{
		List <ModelReference> modelReferenceList= new ArrayList<ModelReference>();
		String [] modelRefs= modelReference.split("\\s");
		ModelReference currentModelReference;
		for(int modelRefsIT= 0;modelRefsIT<modelRefs.length;modelRefsIT++){
			currentModelReference= def.createModelReference();
			currentModelReference.valueOf(modelRefs[modelRefsIT], def);
			currentModelReference.setParent(op);
			modelReferenceList.add(currentModelReference);	
			op.addModelReference(currentModelReference);  
			}// end for modelRefsIT
		
		return modelReferenceList;
		
		
	}// end method parseModelref
	
	protected List<ModelReference> parseModelReference(String modelReferences, Application def) throws URISyntaxException, WADLSException {
		return ModelReferenceImpl.getModelReferences(modelReferences, def);
	}
}
