blob: 13eb50751b6507ef791d41408e63d8611971685b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.wsdl.validation.internal.wsdl11;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.wsdl.Definition;
import javax.wsdl.Import;
import javax.wsdl.WSDLException;
import org.apache.xerces.xs.XSModel;
import org.eclipse.wst.wsdl.validation.internal.IValidationMessage;
import org.eclipse.wst.wsdl.validation.internal.util.ErrorMessage;
import org.eclipse.wst.wsdl.validation.internal.util.MessageGenerator;
import org.eclipse.wst.wsdl.validation.internal.wsdl11.xsd.XSDValidator;
import org.eclipse.wst.wsdl.validation.internal.xml.AbstractXMLConformanceFactory;
import org.eclipse.wst.wsdl.validation.internal.xml.IXMLValidator;
import org.eclipse.wst.wsdl.validation.internal.xml.XMLCatalogResolver;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import com.ibm.wsdl.Constants;
import com.ibm.wsdl.util.StringUtils;
import com.ibm.wsdl.util.xml.DOMUtils;
import com.ibm.wsdl.util.xml.QNameUtils;
/**
* A class to hold and parse an import element.
*/
public class ImportHolder implements Comparable
{
private MessageGenerator messagegenerator;
private WSDLDocument importingWSDLDoc = null;
private WSDLDocument wsdlDocument = null;
private Definition importingDef = null;
private Element importingDocImportElement = null;
private String namespace = null;
private String location = null;
private String contextURI = null;
private int depth;
private Element element = null;
private List schemas = new ArrayList();
private boolean isWSDLFileImport = true;
private boolean importInvalid = false;
private Import importDef = null;
private IWSDL11ValidationInfo valinfo;
/**
* Constructor.
*
* @param namespace The namespace of the import.
* @param location The location of the import.
* @param contextURI The context URI for resolving the import location.
* @param wsdlDoc The WSDLDocument that contains the import.
* @param depth The depth of the import.
* @param importingDocImportElement The element representing the import in the encapsulating WSDLDocument.
* @param messagegenerator A messagegenerator for obtaining strings.
* @param valinfo The WSDL11ValidationInfo for reporting messages.
*/
public ImportHolder(String namespace, String location, String contextURI, WSDLDocument importingWSDLDoc, int depth, Element importingDocImportElement, MessageGenerator messagegenerator, IWSDL11ValidationInfo valinfo)
{
this.messagegenerator = messagegenerator;
this.valinfo = valinfo;
this.importingWSDLDoc = importingWSDLDoc;
if(importingWSDLDoc != null)
{
this.importingDef = importingWSDLDoc.getDefinition();
}
this.importingDocImportElement = importingDocImportElement;
this.depth = depth;
this.namespace = namespace;
this.location = location;
// Allow WSDL imports to have no location attribute even though it is required.
// Schema will normally catch the problem but this allows users to override the
// schema and have the validator run.
if (this.location == null)
{
this.location = namespace;
}
this.contextURI = contextURI;
this.location = this.location.replace('\\','/');
String classpathURI = valinfo.getURIResolver().resolve(this.contextURI, this.namespace, this.location);
if(classpathURI != null)
{
this.location = classpathURI;
this.contextURI = null;
}
}
public void initialize()
{
Element documentElement = null;
try
{
documentElement = getElement();
}
catch(WSDLException e)
{
}
if(documentElement != null)
{
// Handle WSDL imports.
if (QNameUtils.matches(Constants.Q_ELEM_DEFINITIONS, documentElement))
{
if(isXMLValid(this.location))
{
try
{
wsdlDocument = new WSDLDocument(this.location, documentElement, this.depth, this.messagegenerator, this.valinfo);
createWSDLImport(wsdlDocument);
}
catch(WSDLException e)
{
valinfo.addError(messagegenerator.getString("_UNABLE_TO_IMPORT_BAD_LOCATION", "'" + importDef.getLocationURI() + "'"), importingDocImportElement);
}
}
}
// Handle schema imports.
else if (QNameUtils.matches(Constants.Q_ELEM_XSD_2001, documentElement))
{
createXSDImport();
}
}
}
protected boolean isXMLValid(String uri)
{
IXMLValidator xmlValidator = AbstractXMLConformanceFactory.getInstance().getXMLValidator();
xmlValidator.setFile(uri);
//xmlValidator.setValidationInfo(valInfo);
xmlValidator.run();
// if there are no xml conformance problems go on to check the wsdl stuff
if (xmlValidator.hasErrors())
{
// temp handling of XML errors until validator is updated.
List errors = xmlValidator.getErrors();
Iterator errorsIter = errors.iterator();
while (errorsIter.hasNext())
{
IValidationMessage valMes = (IValidationMessage)errorsIter.next();
valinfo.addError(valMes.getMessage(), valMes.getLine(), valMes.getColumn(), valMes.getURI());
}
importInvalid = true;
return false;
}
return true;
}
/**
* Get the importing WSDLDocument.
*
* @return The importing WSDLDocument.
*/
public WSDLDocument getImportingDocument()
{
return importingWSDLDoc;
}
/**
* Get the WSDL document this import represents.
*
* @return The WSDL document this import represents.
*/
public WSDLDocument getWSDLDocument()
{
return wsdlDocument;
}
/**
* Get the namespace.
*
* @return The namespace.
*/
public String getNamespace()
{
return namespace;
}
/**
* Get the location.
*
* @return The location.
*/
public String getLocation()
{
return location;
}
/**
* Get the context URI.
*
* @return The context URI.
*/
public String getContextURI()
{
return contextURI;
}
/**
* Get the depth in the WSDL tree.
*
* @return The depth in the WSDL tree.
*/
public int getDepth()
{
return depth;
}
/**
* Get the containing defintions element.
*
* @return The containing definitions element.
*/
public Definition getImportingDefinition()
{
return importingDef;
}
/**
* Get the element for this import.
*
* @return The element for this import.
* @throws WSDLException
*/
public Element getElement() throws WSDLException
{
if(element != null)
{
return element;
}
String locationURI = location;
String namespaceURI = namespace;
//Import importDef = importingDef.createImport();
// Allow locating WSDL documents using any registered URI resolver.
//String classpathURI = URIResolver.getInstance().resolve(contextURI, namespaceURI, locationURI);
// if (!classpathURI.equals(locationURI))
// {
// locationURI = classpathURI;
// contextURI = null;
// }
Reader reader = null;
if (locationURI != null)
{
try
{
//String contextURI = def.getDocumentBaseURI();
//Definition importedDef = null;
InputSource inputSource = null;
URL url = null;
URL contextURL = (contextURI != null) ? StringUtils.getURL(null, contextURI) : null;
url = StringUtils.getURL(contextURL, locationURI);
// Handle file:// urls. The correct format should be file:/// or file:/.
String urlAuthority = url.getAuthority();
String urlProtocol = url.getProtocol();
if(urlAuthority !=null && urlProtocol.equalsIgnoreCase("file") && !urlAuthority.equals(""))
{
url = new URL(urlProtocol,"","/" + urlAuthority + url.getFile());
}
String urlString = url.toString();
// Test for case sensitivity on local files.
if(urlString.startsWith("file:"))
{
File testfile = new File(url.getFile());
String testfileString = testfile.getAbsolutePath();
File canonicalfile = testfile.getCanonicalFile();
String canonicalfileString = canonicalfile.getAbsolutePath();
if (!testfileString.equals(canonicalfileString))
{
if (!String.valueOf(testfileString.charAt(0)).equalsIgnoreCase
(String.valueOf(canonicalfileString.charAt(0)))
|| !testfileString.substring(1,testfileString.length()).equals
(canonicalfileString.substring(1,canonicalfileString.length())))
{
urlString = "";
url = null;
}
}
}
if(url != null)
{
try
{
reader = StringUtils.getContentAsReader(url);
}
catch(IOException e)
{
// No need to do anything here. The error will be handled below.
}
}
if (reader != null)
{
inputSource = new InputSource(reader);
}
if (inputSource == null)
{
// Get the actual location from the element.
String actualLocation = DOMUtils.getAttribute(importingDocImportElement, Constants.ATTR_LOCATION);
if(actualLocation == null)
{
actualLocation = DOMUtils.getAttribute(importingDocImportElement, "schemaLocation");
}
if(actualLocation == null)
{
actualLocation = namespace;
}
importingWSDLDoc.addReaderWarning(
importingDef,
importingDocImportElement,
messagegenerator.getString("_UNABLE_TO_IMPORT_BAD_LOCATION", "'" + actualLocation + "'"));
importInvalid = true;
// TODO: modify the reader error to show in all the correct locations.
throw new WSDLException(
WSDLException.OTHER_ERROR,
"Unable to locate imported document "
+ "at '"
+ locationURI
+ "'"
+ (contextURI == null ? "." : ", relative to '" + contextURI + "'."));
}
Document doc = null;
try
{
doc = WSDLReaderImpl.getDocument(inputSource, locationURI);
}
catch(WSDLException e)
{
// The File is invalid and cannot be read.
// Perform XML validation.
isXMLValid(locationURI);
// importingWSDLDoc.addReaderError(
// importingDef,
// importingDocImportElement,
// messagegenerator.getString("_UNABLE_TO_IMPORT_INVALID", "'" + location + "'"));
throw e;
}
element = doc.getDocumentElement();
if(!QNameUtils.matches(Constants.Q_ELEM_DEFINITIONS, element))
{
isWSDLFileImport = false;
}
// Ensure that the imported document has the same namespace as the import element states.
String importTargetNS = element.getAttribute(Constants.ATTR_TARGET_NAMESPACE);
if(!importTargetNS.equals(namespace))
{
importingWSDLDoc.addReaderWarning(
importingDef,
importingDocImportElement,
messagegenerator.getString("_WARN_WRONG_NS_ON_IMPORT", "'" + namespace + "'", "'" + importTargetNS + "'"));
element = null;
importInvalid = true;
}
}
catch(Exception e)
{
}
finally
{
if(reader != null)
{
try
{
reader.close();
}
catch(IOException e)
{}
}
}
}
return element;
}
/**
* Create an import element for a WSDL import of a WSDL document.
*
* @param wsdlDocument The document of the import.
* @return The newly created import element.
*/
public Import createWSDLImport(WSDLDocument wsdlDocument)
{
if(importDef != null)
{
return importDef;
}
importDef = getNewImport();
if (importDef != null)
{
importDef.setDefinition(wsdlDocument.getDefinition());
schemas.addAll(wsdlDocument.getSchemas());
importingWSDLDoc.addSchemas(schemas);
}
return importDef;
}
/**
* Create an import element for a WSDL import of a schema import of a schema document.
*
* @return The newly created import element.
*/
public Import createXSDImport()
{
if(importDef != null)
{
return importDef;
}
importDef = getNewImport();
XSDValidator xsdvalidator = new XSDValidator();
xsdvalidator.validate(location, XMLCatalogResolver.getInstance());
if (xsdvalidator.isValid())
{
XSModel schema = xsdvalidator.getXSModel();
if (schema != null)
{
schemas.add(schema);
}
}
else
{
// addReaderWarning(
// def,
// importDef,
// messagegenerator.getString("_UNABLE_TO_IMPORT_INVALID", "'" + importDef.getLocationURI() + "'"));
Iterator errors = xsdvalidator.getErrors().iterator();
while (errors.hasNext())
{
ErrorMessage err = (ErrorMessage) errors.next();
String uri = err.getURI();
int line = err.getErrorLine();
String errmess = err.getErrorMessage();
valinfo.addError(errmess, line, err.getErrorColumn(), uri);
}
}
importingWSDLDoc.addSchemas(schemas);
return importDef;
}
/**
* Get the import element if it has been created.
*
* @return The import element if it has been created or null.
*/
public Import getImport()
{
return importDef;
}
/**
* Get a new import element.
*
* @return A new import element.
*/
private Import getNewImport()
{
if(importInvalid)
{
return null;
}
Import importDef = importingDef.createImport();
if (namespace != null)
{
importDef.setNamespaceURI(namespace);
}
if (location != null)
{
importDef.setLocationURI(location);
}
if(element != null)
{
Element tempEl = DOMUtils.getFirstChildElement(element);
while (tempEl != null)
{
if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl))
{
importDef.setDocumentationElement(tempEl);
}
tempEl = DOMUtils.getNextSiblingElement(tempEl);
}
}
return importDef;
}
/**
* Get the schemas corresponding to this import.
*
* @return The schemas corresponding to this import.
*/
public List getSchemas()
{
return schemas;
}
/**
* Returns true if this import imports a WSDL document, false otherwise.
*
* @return True if this import imports a WSDL document, false otherwise.
*/
public boolean isWSDLFileImport()
{
return isWSDLFileImport;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object obj)
{
if(obj.getClass() == ImportHolder.class)
{
ImportHolder otherImport = (ImportHolder)obj;
if(getNamespace().equals(otherImport.getNamespace()) && getLocation().equals(otherImport.getLocation()))
{
return true;
}
}
return false;
}
/* (non-Javadoc)
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
public int compareTo(Object obj)
{
if(obj == null)
{
throw new NullPointerException();
}
ImportHolder otherImport = (ImportHolder)obj;
return (getNamespace()+getLocation()).compareTo((otherImport.getNamespace()+otherImport.getLocation()));
}
/**
* Set the messagegenerator for the import holder.
*
* @param mg The message generator to set.
*/
public void setMessageGenerator(MessageGenerator mg)
{
messagegenerator = mg;
}
/**
* Return true if the import is invalid, false otherwise.
*
* @return True if the import is invalid, false otherwise.
*/
public boolean isImportInvalid()
{
return importInvalid;
}
}