diff options
author | lmandel | 2005-11-07 07:29:37 +0000 |
---|---|---|
committer | lmandel | 2005-11-07 07:29:37 +0000 |
commit | d702c81d0ff6daf1bd3ccfb9760a83331106008e (patch) | |
tree | d09e5ca6da53b201ca75ca3b1cc8e9d1210cfd00 /bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst | |
parent | 451e5d5e7454e9c4befcd395dace52aae74d46cc (diff) | |
download | webtools.webservices-d702c81d0ff6daf1bd3ccfb9760a83331106008e.tar.gz webtools.webservices-d702c81d0ff6daf1bd3ccfb9760a83331106008e.tar.xz webtools.webservices-d702c81d0ff6daf1bd3ccfb9760a83331106008e.zip |
[99731] Separated WSDL validation core and ui.
Diffstat (limited to 'bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst')
70 files changed, 14165 insertions, 0 deletions
diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/Constants.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/Constants.java new file mode 100644 index 000000000..0c2ca7ec6 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/Constants.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * 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; + +/** + * Set constants that the validator makes use of. + */ +public interface Constants +{ + /** + * The name of the validator properties file. + */ + public final static String WSDL_VALIDATOR_PROPERTIES_FILE = "validatewsdl"; + + /** + * The SOAP 1.1 namespace. + */ + public final static String NS_SOAP11 = "http://schemas.xmlsoap.org/wsdl/soap/"; + + /** + * The HTTP namespace. + */ + public final static String NS_HTTP = "http://schemas.xmlsoap.org/wsdl/http/"; + + /** + * The MIME namespace. + */ + public final static String NS_MIME = "http://schemas.xmlsoap.org/wsdl/mime/"; +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ControllerValidationInfo.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ControllerValidationInfo.java new file mode 100644 index 000000000..34f4d51cf --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ControllerValidationInfo.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * 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; + + +/** + * An interface for the validation info that allows for starting and + * completing WSDL and WS-I validation. + */ +public interface ControllerValidationInfo extends IValidationInfo +{ + + /** + * Perform the necessary steps to complete WSDL validation. + */ + public void completeWSDLValidation(); + +// /** +// * Perform the necessary steps to complete WS-I WSDL validation. +// */ +// public void completeWSIValidation(); + +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/IValidationInfo.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/IValidationInfo.java new file mode 100644 index 000000000..34e1581a0 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/IValidationInfo.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * 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; + +import org.eclipse.wst.wsdl.validation.internal.resolver.URIResolver; + + +/** + * An interface representing the current validation information. + * This interface is not meant to be implemented by clients. + */ +public interface IValidationInfo extends IValidationReport +{ + + /** + * Add an error message for this file. (Uses the URI from this validation info object.) + * + * @param message The message for the error. + * @param line The line location of the error in the file. + * @param column The column location of the error in the file. + * @deprecated + */ + public void addError(String message, int line, int column); + + /** + * Add an error message. + * + * @param message The message for the error. + * @param line The line location of the error in the file. + * @param column The column location of the error in the file. + * @param uri The URI of the file that contains the error. + */ + public void addError(String message, int line, int column, String uri); + + /** + * Add a warning message for this file. (Uses the URI from this validation info object.) + * + * @param message The message for the warning. + * @param line The line location of the warning in the file. + * @param column The column location of the warning in the file. + * @deprecated + */ + public void addWarning(String message, int line, int column); + + /** + * Add a warning message. + * + * @param message The message for the warning. + * @param line The line location of the warning in the file. + * @param column The column location of the warning in the file. + * @param uri The URI of the file that contains the error. + */ + public void addWarning(String message, int line, int column, String uri); + + /** + * Get the URI resolver in use for this validation. The URI resolver + * returned is actually a URI resolver handler that will + * iterate through all of the registered URI resolvers. + * + * @return The URI resolver handler. + */ + public URIResolver getURIResolver(); + + /** + * Get the attribute with the given name. If the attribute + * has not been registered, return null. + * + * @param name The name of the attribute being requested. + * @return The attribute value if the attribute has been registered, null otherwise. + */ + public Object getAttribute(String name); +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/IValidationMessage.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/IValidationMessage.java new file mode 100644 index 000000000..3f5a9af27 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/IValidationMessage.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * 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; + +import java.util.List; + +import org.eclipse.core.runtime.QualifiedName; + +/** + * An interface for a validation message. A validation message contains information + * for the message, its severity and where it's located. + */ +public interface IValidationMessage +{ + public static final QualifiedName ERROR_MESSAGE_MAP_QUALIFIED_NAME = new QualifiedName("org.eclipse.wsdl.validate", "errorMessageMap"); + /** + * Severity error. + */ + public static final int SEV_ERROR = 0; + /** + * Severity warning. + */ + public static final int SEV_WARNING = 1; + + /** + * Returns the URI for the file that contains the validation message. + * + * @return The URI for the file that contains the validation message. + */ + public String getURI(); + + /** + * Return the message for this validation message. + * + * @return The message for this validation message. + */ + public String getMessage(); + + /** + * Return the severity of this validation message. + * + * @return The severity of this validation message. + */ + public int getSeverity(); + + /** + * Return the line where this validation message is located. + * + * @return The line where this validation message is located. + */ + public int getLine(); + + /** + * Return the column where this validation message is located. + * + * @return The column where this validation message is located. + */ + public int getColumn(); + + /** + * Get the list of nested validation messages. + * + * @return The list of nested validation messages. + */ + public List getNestedMessages(); +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/IValidationReport.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/IValidationReport.java new file mode 100644 index 000000000..ced4bd8cc --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/IValidationReport.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * 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; + +import java.util.HashMap; + +/** + * An interface for a WSDL validation report. + */ +public interface IValidationReport +{ + /** + * Returns the URI for the file the report refers to. + * + * @return The URI for the file the report refers to. + */ + public String getFileURI(); + + /** + * Returns whether the file is valid according to the WSDL specification. + * + * @return True if the file is WSDL valid, false otherwise. + */ + public boolean isWSDLValid(); + + /** + * Returns an array of validation messages. + * + * @return An array of validation messages. + */ + public IValidationMessage[] getValidationMessages(); + + /** + * Returns true if there are errors, false otherwise. + * + * @return True if there are errors, false otherwise. + */ + public boolean hasErrors(); + + public HashMap getNestedMessages(); + +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/IWSDLValidator.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/IWSDLValidator.java new file mode 100644 index 000000000..3278e9d0e --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/IWSDLValidator.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * 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; + +import java.util.ResourceBundle; + +import org.eclipse.wst.wsdl.validation.internal.exception.ValidateWSDLException; +import org.w3c.dom.Document; + +/** + * An interface for a WSDL validator. This is the interface for a top level validator + * component such as a WSDL 1.1 validator, WSDL 1.2 validator or WS-I Basic Profile validator. + */ +public interface IWSDLValidator +{ + /** + * Validate the file with the given name. + * + * @param domModel A DOM model of the file to be validated. + * @param valInfo The information for the validation that is being performed. + * @throws ValidateWSDLException + */ + public void validate(Document domModel, IValidationInfo valInfo) throws ValidateWSDLException; + + /** + * setResourceBundle + * Set the ResourceBundle for this validator. Allows the use of difference + * ResourceBundles for different validators. + * + * @param rb The resource bundle to set. + */ + public void setResourceBundle(ResourceBundle rb); + +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ValidationController.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ValidationController.java new file mode 100644 index 000000000..ddba6aa8e --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ValidationController.java @@ -0,0 +1,398 @@ +/******************************************************************************* + * 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; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.ResourceBundle; + +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.parsers.DOMParser; +import org.apache.xerces.parsers.StandardParserConfiguration; +import org.apache.xerces.xni.XNIException; +import org.eclipse.wst.wsdl.validation.internal.exception.ValidateWSDLException; +import org.eclipse.wst.wsdl.validation.internal.resolver.URIResolver; +import org.eclipse.wst.wsdl.validation.internal.util.MessageGenerator; +import org.eclipse.wst.wsdl.validation.internal.xml.AbstractXMLConformanceFactory; +import org.eclipse.wst.wsdl.validation.internal.xml.DefaultXMLValidator; +import org.eclipse.wst.wsdl.validation.internal.xml.IXMLValidator; +import org.eclipse.wst.wsdl.validation.internal.xml.LineNumberDOMParser; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.InputSource; + +/** + * This is the main entrypoint to the WSDL Validator. The controller is + * responsible for calling the reader, the XML conformance check, the WSDL + * validation and the WS-I validation if selected. The controller contains any + * errors and warnings generated as well. + */ +public class ValidationController +{ + protected final String _ERROR_PROBLEM_WSDL_VALIDATOR = "_ERROR_PROBLEM_WSDL_VALIDATOR"; + protected final String _ERROR_NO_WSDL_VALIDATOR = "_ERROR_NO_WSDL_VALIDATOR"; + protected final String _ERROR_PROBLEM_EXT_VALIDATOR = "_ERROR_PROBLEM_EXT_VALIDATOR"; + + protected ValidatorRegistry ver; + protected ResourceBundle resourcebundle; + protected MessageGenerator messagegenerator; + protected URIResolver uriResolver; + protected Hashtable attributes = new Hashtable(); + + //protected String wsdlNamespace = null; + + /** + * The ResourceBundle needs to be set so it can be passed to the reader. + * + * @param rb + * The resource bundle for this validator. + */ + public ValidationController(ResourceBundle rb, URIResolver uriResolver) + { + resourcebundle = rb; + messagegenerator = new MessageGenerator(resourcebundle); + this.uriResolver = uriResolver; + + ver = ValidatorRegistry.getInstance(); + } + + /** + * Add the attributes specified to the validation. + * + * @param attributes The attributes to add to the validation. + */ + public void setAttributes(Hashtable attributes) + { + this.attributes.putAll(attributes); + } + + /** + * Validate the WSDL file. Check the file for XML conformance. If it is XML + * conformant, read the file and check it for WSDL conformance. If it is WSDL + * conformant and WS-I conformance is set to suggest or require, check the + * file for WS-I conformance. + * + * @param uri + * The uri where the WSDL document is located. + * @param wsiLevel + * The level of WS-I conformance to use for validation. + * @return A validation report with the validation info for the file. + */ +// public IValidationReport validate(String uri) +// { return validate(uri, null); +// } + + /** + * Validate the WSDL file with the stream. This method will run the check of the + * WSDL document. The validation is broken up into three stages: XML conformance, + * WSDL semantic, and post validation. + * + * @param uri The URI of the WSDL document to be validated. + * @param inputStream The contents of the WSDL document to be validated. + * @return A validation report with the validation info for the file. + */ + public IValidationReport validate(String uri, InputStream inputStream) + { + + InputStream xmlValidateStream = null; + InputStream wsdlValidateStream = null; + if (inputStream != null) + { //copy the inputStream so we can use it more than once + String contents = createStringForInputStream(inputStream); + xmlValidateStream = new ByteArrayInputStream(contents.getBytes()); + wsdlValidateStream = new ByteArrayInputStream(contents.getBytes()); + } + + ControllerValidationInfo valInfo = new ValidationInfoImpl(uri, messagegenerator); + ((ValidationInfoImpl)valInfo).setURIResolver(uriResolver); + ((ValidationInfoImpl)valInfo).setAttributes(attributes); + + if (validateXML(valInfo, xmlValidateStream)) + { + Document wsdldoc = getDocument(uri, wsdlValidateStream); + String wsdlns = getWSDLNamespace(wsdldoc); + if (validateWSDL(wsdldoc, valInfo, wsdlns)) + { + validateExtensionValidators(wsdldoc, valInfo, wsdlns); + } + } + return (IValidationReport)valInfo; + } + + /** + * Validate the file for XML conformance. + * @param valInfo information about the validation + * @param inputStream the inputStream to validate + * @return True if the file is conformant, false otherwise. + */ + protected boolean validateXML(ControllerValidationInfo valInfo, InputStream inputStream) + { + IXMLValidator xmlValidator = AbstractXMLConformanceFactory.getInstance().getXMLValidator(); + xmlValidator.setURIResolver(uriResolver); + xmlValidator.setFile(valInfo.getFileURI()); + if (xmlValidator instanceof DefaultXMLValidator) + { + ((DefaultXMLValidator)xmlValidator).setInputStream(inputStream); + } + //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(); + + if (valMes instanceof ValidationMessageImpl && valInfo instanceof ValidationInfoImpl) + { String errorKey = ((ValidationMessageImpl)valMes).getErrorKey(); + Object[] messageArgs = ((ValidationMessageImpl)valMes).getMessageArguments(); + ((ValidationInfoImpl)valInfo).addError(valMes.getMessage(), valMes.getLine(), valMes.getColumn(), valMes.getURI(), errorKey, messageArgs); + } + else + { + valInfo.addError(valMes.getMessage(), valMes.getLine(), valMes.getColumn(), valMes.getURI()); + } + } + return false; + } + //wsdlNamespace = xmlValidator.getWSDLNamespace(); + return true; + } + + /** + * Validate the file for XML conformance. + * @param valInfo information about the validation + * @return True if the file is conformant, false otherwise. + */ + protected boolean validateXML(ControllerValidationInfo valInfo) + { return validateXML(valInfo, null); + } + + /** + * Validate the WSDL file. Set the errors and warning appropriately. + * + * @param wsdldoc A W3C document representation of the WSDL document. + * @param valInfo The current validation information. + * @param wsdlNamespace The WSDL namespace to validate. + * @return True if the file is valid, false otherwise. + */ + protected boolean validateWSDL(Document wsdldoc, ControllerValidationInfo valInfo, String wsdlNamespace) + { + WSDLValidatorDelegate[] wsdlVals = ver.queryValidatorRegistry(wsdlNamespace, ValidatorRegistry.WSDL_VALIDATOR); + if (wsdlVals != null) + { + for (int i = 0; i < wsdlVals.length; i++) + { + WSDLValidatorDelegate wsdlvaldel = wsdlVals[i]; + IWSDLValidator wsdlVal = wsdlvaldel.getValidator(); + + // If the wsdl validator isn't null, validate. + if (wsdlVal != null) + { + try + { + wsdlVal.validate(wsdldoc, valInfo); + } + catch (ValidateWSDLException e) + { + valInfo.addError(messagegenerator.getString(_ERROR_PROBLEM_WSDL_VALIDATOR, wsdlNamespace), 1, 1, valInfo.getFileURI()); + } + } + // If the validator is null and the namespace isn't create an error. + // If the namespace is null the file is empty (and the XML validator + // has let it go) + // so it is valid but does not need to be validated. + else + { + valInfo.addError( + messagegenerator.getString(_ERROR_NO_WSDL_VALIDATOR, wsdlNamespace), + 1, + 1, + valInfo.getFileURI()); + } + } + } + // No validators registered. + else + { + valInfo.addError(messagegenerator.getString(_ERROR_NO_WSDL_VALIDATOR, wsdlNamespace), 1, 1, valInfo.getFileURI()); + } + valInfo.completeWSDLValidation(); + + return valInfo.isWSDLValid(); + } + + /** + * Validate the WSDL file with the extension validator. Set the errors and warning appropriately. + * + * @param wsdldoc A W3C document representation of the WSDL document. + * @param valInfo The current validation information. + * @param wsdlNamespace The WSDL namespace to validate. + * @return True if the file is valid, false otherwise. + */ + protected void validateExtensionValidators(Document wsdldoc, ControllerValidationInfo valInfo, String wsdlNamespace) + { + WSDLValidatorDelegate[] extVals = ver.queryValidatorRegistry(wsdlNamespace, ValidatorRegistry.EXT_VALIDATOR); + if(extVals != null) + { + int numvals = extVals.length; + for(int i = 0; i < numvals; i++) + { + WSDLValidatorDelegate extvaldel = extVals[i]; + IWSDLValidator extval = extvaldel.getValidator(); + if(extval != null) + { + try + { + extval.validate(wsdldoc, valInfo); + } + catch(Throwable t) + { + valInfo.addWarning(messagegenerator.getString(_ERROR_PROBLEM_EXT_VALIDATOR, extvaldel.getValidatorClassName(), wsdlNamespace), 1, 1, valInfo.getFileURI()); + // This error should be logged and not displayed to the user. + } + } + } + } + } + + /** + * Set the ResourceBundle for this ValidatorManager. + * + * @param rb + * The resource bundle to set. + * @see #getResourceBundle + */ + public void setResourceBundle(ResourceBundle rb) + { + resourcebundle = rb; + } + + /** + * Get the ResourceBundle for this ValidationController. + * + * @return The resource bundle set for this ValidationController. + * @see #setResourceBundle + */ + public ResourceBundle getResourceBundle() + { + return resourcebundle; + } + + /** + * Get a DOM document representation of the WSDL document. + * + * @param uri The uri of the file to read + * @return The DOM model of the WSDL document or null if the document can't be read. + */ + private Document getDocument(String uri, InputStream inputStream) + { + try + { + // Catch a premature EOF error to allow empty WSDL files to be considered valid. + StandardParserConfiguration configuration = new StandardParserConfiguration() + { + protected XMLErrorReporter createErrorReporter() + { + return new XMLErrorReporter() + { + public void reportError(String domain, String key, Object[] arguments, short severity) throws XNIException + { + boolean reportError = true; + if (key.equals("PrematureEOF")) + { + reportError = false; + } + + if (reportError) + { + super.reportError(domain, key, arguments, severity); + } + } + }; + } + }; + + InputSource inputSource = null; + if (inputStream != null) + { //then we want to create a DOM from the inputstream + inputSource = new InputSource(inputStream); + } + else + { inputSource = new InputSource(uri); + } + + DOMParser builder = new LineNumberDOMParser(configuration); + builder.parse(inputSource); + Document doc = builder.getDocument(); + + return doc; + } + catch (Throwable t) + { + // TODO: Log error if the parser fails to read the WSDL document. + // In this case the validator will fail with an unexplained error message + // about a null WSDL namespace. This error should be addressed as well. + System.out.println(t); + } + return null; + } + + private String getWSDLNamespace(Document doc) + { + String wsdlns = null; + if(doc != null) + { + Element definitions = doc.getDocumentElement(); + if(definitions.getLocalName().equals("definitions")) + { + wsdlns = definitions.getNamespaceURI(); + } + } + return wsdlns; + } + + + + private final String createStringForInputStream(InputStream inputStream) + { + // Here we are reading the file and storing to a stringbuffer. + StringBuffer fileString = new StringBuffer(); + try + { + InputStreamReader inputReader = new InputStreamReader(inputStream); + BufferedReader reader = new BufferedReader(inputReader); + char[] chars = new char[1024]; + int numberRead = reader.read(chars); + while (numberRead != -1) + { + fileString.append(chars, 0, numberRead); + numberRead = reader.read(chars); + } + } + catch (Exception e) + { + //TODO: log error message + //e.printStackTrace(); + } + return fileString.toString(); + } + +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ValidationInfoImpl.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ValidationInfoImpl.java new file mode 100644 index 000000000..f21587598 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ValidationInfoImpl.java @@ -0,0 +1,300 @@ +/******************************************************************************* + * 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; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.Vector; + +import org.eclipse.wst.wsdl.validation.internal.resolver.IExtensibleURIResolver; +import org.eclipse.wst.wsdl.validation.internal.resolver.URIResolver; +import org.eclipse.wst.wsdl.validation.internal.util.MessageGenerator; + +/** + * An implementation of the validation info interface. + */ +public class ValidationInfoImpl implements IValidationReport, ControllerValidationInfo +{ + private boolean WRAPPER_ERROR_SUPPORT_ENABLED = true; + private final String _WARN_NO_VALDIATOR = "_WARN_NO_VALDIATOR"; + private final String _REF_FILE_ERROR_MESSAGE = "_REF_FILE_ERROR_MESSAGE"; + private String validating_file_uri = null; + private URL validating_file_url = null; + private boolean wsdlValid = false; + private List messages = new Vector(); + private List schemas = new Vector(); + private List nsNoVals = new Vector(); + private MessageGenerator messagegenerator = null; + private boolean haserrors = false; + private HashMap nestedMessages = new HashMap(); + private URIResolver uriResolver = null; + private Hashtable attributes = new Hashtable(); + + /** + * Constructor. + * + * @param uri + * The URI of the file for the validation. + */ + public ValidationInfoImpl(String uri, MessageGenerator messagegenerator) + { + this.validating_file_uri = uri; + if(uri != null) + { + uri = uri.replaceAll("%20"," "); + this.validating_file_uri = uri; + try + { + this.validating_file_url = new URL(uri); + } catch (MalformedURLException e) + { + } + } + this.messagegenerator = messagegenerator; + } + /** + * @see org.eclipse.wst.wsdl.validation.internal.IValidationReport#getFileURI() + */ + public String getFileURI() + { + return validating_file_uri; + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.IValidationReport#isWSDLValid() + */ + public boolean isWSDLValid() + { + return wsdlValid; + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.IValidationInfo#addError(java.lang.String, + * int, int) + */ + public void addError(String message, int line, int column) + { + addError(message, line, column, validating_file_uri); + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.IValidationInfo#addError(java.lang.String, + * int, int) + */ + public void addError(String message, int line, int column, String uri) + { + if(addMessage(message, line, column, uri, ValidationMessageImpl.SEV_ERROR)) + { + haserrors = true; + } + } + + public void addError(String message, int line, int column, String uri, String errorKey, Object[] messageArguments) + { + if(addMessage(message, line, column, uri, ValidationMessageImpl.SEV_ERROR, errorKey, messageArguments)) + { + haserrors = true; + } + } + + + /** + * @see org.eclipse.wst.wsdl.validation.internal.IValidationInfo#addWarning(java.lang.String, + * int, int) + */ + public void addWarning(String message, int line, int column) + { + addWarning(message, line, column, validating_file_uri); + } + /** + * @see org.eclipse.wst.wsdl.validation.internal.IValidationInfo#addWarning(java.lang.String, + * int, int) + */ + public void addWarning(String message, int line, int column, String uri) + { + addMessage(message, line, column, uri, ValidationMessageImpl.SEV_WARNING); + } + + /** + * Add a message to the list. A message may not be added to the list in + * certain circumstances such as when the URI is invalid or the message + * is null. + * + * @param message The message to add. + * @param line The line location of the message. + * @param column The column location of the message. + * @param uri The URI of the file that contains the message. + * @param severity The severity of the message. + * @return True if the message was able to be added, false otherwise. + */ + private boolean addMessage(String message, int line, int column, String uri, int severity) + { + return this.addMessage(message, line, column, uri, severity, null, null); + } + + /** + * Add a message to the list. A message may not be added to the list in + * certain circumstances such as when the URI is invalid or the message + * is null. + * + * @param message The message to add. + * @param line The line location of the message. + * @param column The column location of the message. + * @param uri The URI of the file that contains the message. + * @param severity The severity of the message. + * @param errorKey The Xerces Error Key + * @param messageArguments The Xerces arguments used to create the error message + * @return True if the message was able to be added, false otherwise. + */ + private boolean addMessage(String message, int line, int column, String uri, int severity, String errorKey, Object[] messageArguments) + { + boolean successfullyAdded = false; + // If the message is null there is nothing to report. + if(message == null) + { + return successfullyAdded; + } + String errorURI = uri; + URL errorURL = null; + if (errorURI != null) + { + try + { + errorURI = errorURI.replaceAll("%20", " "); + errorURL = new URL(errorURI); + } catch (MalformedURLException e) + { + } + //errorURI = normalizeURI(errorURI); + } +// else +// { +// errorURI = validating_file_uri; +// errorURL = validating_file_url; +// } + //boolean doDialog = true; + if (errorURL != null) + { + successfullyAdded = true; + // Add to the appropriate list if nested error support is off or + // this message is for the current file. + if (!WRAPPER_ERROR_SUPPORT_ENABLED || validating_file_url.sameFile(errorURL)) + { + + ValidationMessageImpl valmes = new ValidationMessageImpl(message, line, + column, severity, uri, errorKey, messageArguments); + messages.add(valmes); + } + // If nested error support is enabled create a nested error. + else if (WRAPPER_ERROR_SUPPORT_ENABLED) + { + String nesteduri = errorURL.toExternalForm(); + ValidationMessageImpl nestedmess = new ValidationMessageImpl(message, line, + column, severity, nesteduri); + + ValidationMessageImpl container = (ValidationMessageImpl) nestedMessages.get(nesteduri); + if(container == null) + { + // Initially set the nested error to a warning. This will automatically be changed + // to an error if a nested message has a severity of error. + container = new ValidationMessageImpl(messagegenerator.getString(_REF_FILE_ERROR_MESSAGE, nesteduri), 1, 0, IValidationMessage.SEV_WARNING, nesteduri); + nestedMessages.put(nesteduri, container); + messages.add(container); + } + container.addNestedMessage(nestedmess); + } + } + + return successfullyAdded; + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.IValidationReport#getValidationMessages() + */ + public IValidationMessage[] getValidationMessages() + { + return (IValidationMessage[])messages.toArray(new IValidationMessage[messages.size()]); + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.IValidationInfo#addNamespaceWithNoValidator(java.lang.String) + */ + public void addNamespaceWithNoValidator(String namespace) + { + // If the list doesn't already contain this namespace, add it to the list + // and create a warning message. + if (!nsNoVals.contains(namespace)) + { + nsNoVals.add(namespace); + addWarning(messagegenerator.getString(_WARN_NO_VALDIATOR, namespace), 1, 0); + + } + + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.ControllerValidationInfo#completeWSDLValidation() + */ + public void completeWSDLValidation() + { + if (haserrors) + { + wsdlValid = false; + } + else + { + wsdlValid = true; + } + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.IValidationReport#hasErrors() + */ + public boolean hasErrors() + { + return haserrors; + } + + /* (non-Javadoc) + * @see org.eclipse.wsdl.validate.ValidationReport#getNestedMessages() + */ + public HashMap getNestedMessages() + { + return nestedMessages; + } + + public void setURIResolver(URIResolver uriResolver) + { + this.uriResolver = uriResolver; + } + + public URIResolver getURIResolver() + { + return uriResolver; + } + + /* (non-Javadoc) + * @see org.eclipse.wsdl.validate.ValidationInfo#getAttribute(java.lang.String) + */ + public Object getAttribute(String name) + { + return attributes.get(name); + } + + public void setAttributes(Hashtable attributes) + { + this.attributes.putAll(attributes); + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ValidationMessageImpl.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ValidationMessageImpl.java new file mode 100644 index 000000000..aa7fc1ae2 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ValidationMessageImpl.java @@ -0,0 +1,193 @@ +/******************************************************************************* + * 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; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + + +/** + * A validation message is created when there is information to report from + * validating a WSDL document. + */ +public class ValidationMessageImpl implements IValidationMessage +{ + protected String message; + protected int lineNumber; + protected int columnNumber; + protected String uri; + protected int severity = SEV_ERROR; + protected List nestedErrors; + protected String errorKey = null; + protected Object[] messageArguments = null; + + /** + * Constructor. + * + * @param message The validation message. + * @param lineNumber The line where the message should be displayed. + * @param columnNumber The column where the message should be displayed. + * @deprecated Use contructor with URI parameter. + */ + public ValidationMessageImpl(String message, int lineNumber, int columnNumber, int severity) + { + this(message, lineNumber, columnNumber, severity, null); + } + + /** + * Constructor. + * Allows specifying a uri for the reference that the message refers to. + * + * @param message The validation message. + * @param lineNumber The line where the message should be displayed. + * @param columnNumber The column where the message should be displayed. + * @param uri The uri of the reference file for the message. + */ + public ValidationMessageImpl(String message, int lineNumber, int columnNumber, int severity, String uri) + { + this(message, lineNumber, columnNumber, severity, uri, null, null); + } + + /** + * Constructor. + * Allows specifying a uri for the reference that the message refers to. + * + * @param message The validation message. + * @param lineNumber The line where the message should be displayed. + * @param columnNumber The column where the message should be displayed. + * @param uri The uri of the reference file for the message. + * @param errorKey The Xerces Error key + * @param messageArguments The values used to "fill in the blanks" of a Xerces error Message + */ + public ValidationMessageImpl(String message, int lineNumber, int columnNumber, int severity, String uri, String errorKey, Object[] messageArguments) + { + this.message = message; + this.lineNumber = lineNumber; + this.columnNumber = columnNumber; + this.severity = severity; + this.uri = uri; + this.errorKey = errorKey; + this.messageArguments = messageArguments; + } + + /** + * Returns the validation message. + * + * @return The validation message. + */ + public String getMessage() + { + return message; + } + + /** + * Returns the column number. + * + * @return The column number where the message is located. + */ + public int getColumn() + { + return columnNumber; + } + + /** + * Returns the line number. + * + * @return The line number where the message is located. + */ + public int getLine() + { + return lineNumber; + } + + /** + * returns the uri of the reference file for the validation message. + * + * @return The uri of the resource that the message refers to. + */ + public String getURI() + { + return uri; + } + /** + * @see org.eclipse.wst.wsdl.validation.internal.IValidationMessage#getSeverity() + */ + public int getSeverity() + { + return severity; + } + + /** + * Set the severity of the message. + * + * @param severity The severity of the message. + */ + public void setSeverity(int severity) + { + if(severity == SEV_ERROR || severity == SEV_WARNING) + { + this.severity = severity; + } + } + + /** + * Add a nested validation message to this validation message. + * + * @param validationMessage The validation message to add as a nested message. + */ + public void addNestedMessage(IValidationMessage validationMessage) + { + if (nestedErrors == null) + { + nestedErrors = new ArrayList(); + } + nestedErrors.add(validationMessage); + int validaitonmessageSeverity = validationMessage.getSeverity(); + if(validaitonmessageSeverity == SEV_ERROR) + { + setSeverity(SEV_ERROR); + } + } + + /** + * Get the list of nested validation messages. + * + * @return The list of nested validation messages. + */ + public List getNestedMessages() + { + return nestedErrors != null ? nestedErrors : Collections.EMPTY_LIST; + } + /** + * @return the error key + */ + public String getErrorKey() + { + return errorKey; + } + + /** + * @param errorKey the error key to set + */ + public void setErrorKey(String errorKey) + { + this.errorKey = errorKey; + } + /** + * @return the Xerces message arguments used to "fill in the blanks" of the messages + */ + public Object[] getMessageArguments() + { + return messageArguments; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ValidatorRegistry.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ValidatorRegistry.java new file mode 100644 index 000000000..e82ca77fb --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ValidatorRegistry.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * 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; + +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Vector; + + +/** + * A registry of IWSDLValidator validators. This holds the top level WSDL and WS-I validators. + * Validators are registered by the namespace they validate. + */ +public class ValidatorRegistry +{ + /** + * The WSDL validator type. + */ + public final static Integer WSDL_VALIDATOR = new Integer(0); + /** + * The WS-I validator type. + */ + public final static Integer EXT_VALIDATOR = new Integer(1); + protected static ValidatorRegistry verInstance; + /* + This is a Map of Maps. The top-level Map is keyed by (Class)parentType, + and the inner Maps are keyed by (QName)elementType. + This idea is the same as is done in WSDL4J + */ + protected Map validatorReg = new Hashtable(); + + protected Iterator defaultValidatorIterator; + + /** + * Constructor. + */ + protected ValidatorRegistry() + { + } + + /** + * Returns the instance of the registry. + * + * @return The instance of the registry. + */ + public static ValidatorRegistry getInstance() + { + if (verInstance == null) + { + verInstance = new ValidatorRegistry(); + } + return verInstance; + } + /** + * Register this validator of the given type with the given namespace. + * + * @param namespace The namespace the validator validates. + * @param valDelegate The validator delegate to register. + * @param type The type of validator. + */ + public void registerValidator(String namespace, WSDLValidatorDelegate valDelegate, Integer type) + { + // allow the null namespace but make it the empty string + if (namespace == null) + { + namespace = ""; + } + + // get the hastable for the type of validator we want + Hashtable typeValidatorReg = (Hashtable)validatorReg.get(type); + // if it's null if means we haven't defined this type of validator yet + if (typeValidatorReg == null) + { + typeValidatorReg = new Hashtable(); + validatorReg.put(type, typeValidatorReg); + } + + List namespacevals = (List)typeValidatorReg.get(namespace); + if(namespacevals == null) + { + namespacevals = new Vector(); + typeValidatorReg.put(namespace, namespacevals); + } + namespacevals.add(valDelegate); + + } + /** + * Ask for the validator associated with this namespace. If none is found + * return null. + * + * @param namespace The namespace for the validator that is being requested. + * @param type The type of validator that is being requested. + * @return An array of validator delegates if at least one is registered, null otherwise. + */ + public WSDLValidatorDelegate[] queryValidatorRegistry(String namespace, Integer type) + { + IWSDLValidator wsdlval = null; + // if the namespace is null allow it and treat it as the empty string + if (namespace == null) + { + namespace = ""; + } + Hashtable typeValidatorReg = (Hashtable)validatorReg.get(type); + if (typeValidatorReg == null) + { + return null; + + } + + List valdels = (List)typeValidatorReg.get(namespace); + if(valdels != null) + { + return (WSDLValidatorDelegate[])valdels.toArray(new WSDLValidatorDelegate[valdels.size()]); + } + + return null; + } + + /** + * Returns true if there is a validator registered of the given type with the given namespace. + * + * @param namespace The namespace of the validator. + * @param type The type of the validator. + * @return True if there is a validator registered for the namespace, false otherwise. + */ + public boolean hasRegisteredValidator(String namespace, Integer type) + { + if (queryValidatorRegistry(namespace, type) != null) + { + return true; + } + return false; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/WSDLValidator.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/WSDLValidator.java new file mode 100644 index 000000000..b3dbf4d6c --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/WSDLValidator.java @@ -0,0 +1,146 @@ +/******************************************************************************* + * 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; + +import java.io.InputStream; +import java.util.Hashtable; +import java.util.ResourceBundle; + +import org.eclipse.wst.wsdl.validation.internal.resolver.IExtensibleURIResolver; +import org.eclipse.wst.wsdl.validation.internal.resolver.URIResolver; +import org.eclipse.wst.wsdl.validation.internal.wsdl11.WSDL11BasicValidator; +import org.eclipse.wst.wsdl.validation.internal.wsdl11.WSDL11ValidatorController; +import org.eclipse.wst.wsdl.validation.internal.wsdl11.WSDL11ValidatorDelegate; +import org.eclipse.wst.wsdl.validation.internal.wsdl11.http.HTTPValidator; +import org.eclipse.wst.wsdl.validation.internal.wsdl11.mime.MIMEValidator; +import org.eclipse.wst.wsdl.validation.internal.wsdl11.soap.SOAPValidator; +import org.eclipse.wst.wsdl.validation.internal.wsdl11.xsd.InlineSchemaValidator; + +import com.ibm.wsdl.Constants; + +/** + * An main WSDL validator class. The WSDL validator validates WSDL documents. + */ +public class WSDLValidator +{ + private static String VALIDATOR_RESOURCE_BUNDLE = "validatewsdl"; + private static String VALIDATOR_HTTP_RESOURCE_BUNDLE = "validatewsdlhttp"; + private static String VALIDATOR_SOAP_RESOURCE_BUNDLE = "validatewsdlsoap"; + private static String VALIDATOR_MIME_RESOURCE_BUNDLE = "validatewsdlmime"; + private ValidationController validationController; + private URIResolver uriResolver; + private Hashtable attributes = new Hashtable(); + + /** + * Constructor. + */ + public WSDLValidator() + { + ResourceBundle rb = ResourceBundle.getBundle(VALIDATOR_RESOURCE_BUNDLE); + uriResolver = new URIResolver(); + validationController = new ValidationController(rb, uriResolver); + + //Register the default validators. + ValidatorRegistry registry = ValidatorRegistry.getInstance(); + // Register the WSDL 1.1 validator controller and validators. + WSDLValidatorDelegate delegate = new WSDLValidatorDelegate(WSDL11ValidatorController.class.getName(), VALIDATOR_RESOURCE_BUNDLE, getClass().getClassLoader()); + registry.registerValidator(Constants.NS_URI_WSDL, delegate, ValidatorRegistry.WSDL_VALIDATOR); + WSDL11ValidatorDelegate delegate1 = new WSDL11ValidatorDelegate(WSDL11BasicValidator.class.getName(), VALIDATOR_RESOURCE_BUNDLE, getClass().getClassLoader()); + registerWSDL11Validator(Constants.NS_URI_WSDL, delegate1); + delegate1 = new WSDL11ValidatorDelegate(HTTPValidator.class.getName(), VALIDATOR_HTTP_RESOURCE_BUNDLE, getClass().getClassLoader()); + registerWSDL11Validator(org.eclipse.wst.wsdl.validation.internal.Constants.NS_HTTP, delegate1); + delegate1 = new WSDL11ValidatorDelegate(SOAPValidator.class.getName(), VALIDATOR_SOAP_RESOURCE_BUNDLE, getClass().getClassLoader()); + registerWSDL11Validator(org.eclipse.wst.wsdl.validation.internal.Constants.NS_SOAP11, delegate1); + delegate1 = new WSDL11ValidatorDelegate(MIMEValidator.class.getName(), VALIDATOR_MIME_RESOURCE_BUNDLE, getClass().getClassLoader()); + registerWSDL11Validator(org.eclipse.wst.wsdl.validation.internal.Constants.NS_MIME, delegate1); + + // The WSDL 1.1 schema validator is a special case as it is registered for three namespaces. + delegate1 = new WSDL11ValidatorDelegate(InlineSchemaValidator.class.getName(), VALIDATOR_RESOURCE_BUNDLE, getClass().getClassLoader()); + registerWSDL11Validator(Constants.NS_URI_XSD_1999, delegate1); + registerWSDL11Validator(Constants.NS_URI_XSD_2000, delegate1); + registerWSDL11Validator(Constants.NS_URI_XSD_2001, delegate1); + } + + /** + * Validate the WSDL file at the given location. + * + * @param uri The location of the WSDL file to validate. + * @return A validation report summarizing the results of the validation. + */ + public IValidationReport validate(String uri) + { + return validate(uri, null); + } + + /** + * + * Validate the inputStream + * @param uri The location of the WSDL file being validated + * @param inputStream The stream to validate + * @return A Validation report summarizing the results of the validation + */ + public IValidationReport validate(String uri, InputStream inputStream) + { + if(uri == null) + return null; + validationController.setAttributes(attributes); + return validationController.validate(uri, inputStream); + } + + /** + * Add a URI resolver to the WSDL validator. + * + * @param uriResolver The URI resolver to add to the WSDL validator. + */ + public void addURIResolver(IExtensibleURIResolver uriResolver) + { + this.uriResolver.addURIResolver(uriResolver); + } + + /** + * Set an attribute on the validator. An attribute is + * defined by a name and a value pair. An attribute may + * be defined for any validator, built in or an extension. + * Extension validators can probe the attributes set on + * the WSDL validator to customize the way in which they + * validate. + * + * @param name The attribute identifier. + * @param value The attribute itself. + */ + public void setAttribute(String name, Object value) + { + attributes.put(name, value); + } + + /** + * Register an extension WSDL validator delegate with this validator. + * + * @param namespace The namespace the validator validates for. This is the WSDL namespace. + * @param delegate The delegate that holds the validator. + */ + public void registerWSDLExtensionValidator(String namespace, WSDLValidatorDelegate delegate) + { + ValidatorRegistry.getInstance().registerValidator(namespace, delegate, ValidatorRegistry.EXT_VALIDATOR); + } + + /** + * Register a WSDL 1.1 validator delegate with this validator. + * + * @param namespace The namespace the validator validates for. + * @param delegate The delegate that holds the validator. + */ + public void registerWSDL11Validator(String namespace, WSDL11ValidatorDelegate delegate) + { + org.eclipse.wst.wsdl.validation.internal.wsdl11.ValidatorRegistry.getInstance().registerValidator(namespace, delegate); + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/WSDLValidatorDelegate.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/WSDLValidatorDelegate.java new file mode 100644 index 000000000..ab4075f2c --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/WSDLValidatorDelegate.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * 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; + +import java.util.Locale; +import java.util.ResourceBundle; + + +/** + * A delegate holds a validator's information and can instantiate it + * when requested to. + */ +public class WSDLValidatorDelegate +{ + private String validatorClassname = null; + private String resourceBundle = null; + private ClassLoader classLoader = null; + private IWSDLValidator validator = null; + + /** + * Create a delegate for a validator by its class name and resource bundle name. + * + * @param validatorClassname The name of the validator class. + * @param resourceBundle The name of the validator base resource bundle. + */ + public WSDLValidatorDelegate(String validatorClassname, String resourceBundle) + { + this.validatorClassname = validatorClassname; + this.resourceBundle = resourceBundle; + } + + /** + * Create a delegate for a validator by its class name, resource bundle name and + * a class loader to load the validator and bundle. + * + * @param validatorClassname The name of the validator class. + * @param resourceBundle The name of the validator base resource bundle. + * @param classLoader The class loader to use to load the validator and bundle. + */ + public WSDLValidatorDelegate(String validatorClassname, String resourceBundle, ClassLoader classLoader) + { + this(validatorClassname, resourceBundle); + this.classLoader = classLoader; + } + + /** + * Get the validator specified in this delegate. + * + * @return The WSDL validator specified by this delegate. + */ + public IWSDLValidator getValidator() + { + if (validator == null) + { + if(classLoader == null) + { + classLoader = getClass().getClassLoader(); + } + try + { + Class validatorClass = + classLoader != null ? classLoader.loadClass(validatorClassname) : Class.forName(validatorClassname); + + validator = (IWSDLValidator)validatorClass.newInstance(); + + if (resourceBundle != null) + { + ResourceBundle validatorBundle = ResourceBundle.getBundle(resourceBundle, Locale.getDefault(), classLoader); + validator.setResourceBundle(validatorBundle); + } + } + catch (Exception e) + { + // TODO: add logging + System.err.println(e); + } + catch(Throwable t) + { + System.err.println(t); + } + } + return validator; + } + + /** + * Return the validator class name. + * @return The validator class name. + */ + public String getValidatorClassName() + { + return validatorClassname; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/eclipse/URIResolverRegistryReader.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/eclipse/URIResolverRegistryReader.java new file mode 100644 index 000000000..65c0ba7b2 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/eclipse/URIResolverRegistryReader.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * 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.eclipse; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.Platform; +import org.eclipse.wst.wsdl.validation.internal.resolver.IExtensibleURIResolver; +import org.eclipse.wst.wsdl.validation.internal.resolver.URIResolverDelegate; + +/** + * Read extension URI resolvers. + * + * <extension + * point="org.eclipse.wst.wsdl.validation.uriresolver"> + * <uriresolver + * class="org.eclipse.wst.wsdl.validation.someclass"/> + * </extension> + * + */ +class URIResolverRegistryReader +{ + protected static final String PLUGIN_ID = "org.eclipse.wst.wsdl.validation"; + protected static final String EXTENSION_POINT_ID = "uriresolver"; + protected static final String ATT_CLASS = "class"; + protected String tagName; + + /** + * Constructor. + */ + public URIResolverRegistryReader() + { + } + + /** + * Read from plugin registry and handle the configuration elements that match + * the spedified elements. + */ + public List readRegistry() + { + List resolverList = new ArrayList(); + IExtensionRegistry pluginRegistry = Platform.getExtensionRegistry(); + IExtensionPoint point = pluginRegistry.getExtensionPoint(PLUGIN_ID, EXTENSION_POINT_ID); + if (point != null) + { + IConfigurationElement[] elements = point.getConfigurationElements(); + for (int i = 0; i < elements.length; i++) + { + IExtensibleURIResolver resolver = readElement(elements[i]); + if(resolver != null) + { + resolverList.add(resolver); + } + } + } + return resolverList; + } + + /** + * Parse and deal with the extension points. + * + * @param element The extension point element. + */ + protected IExtensibleURIResolver readElement(IConfigurationElement element) + { + if (element.getName().equals(EXTENSION_POINT_ID)) + { + String resolverClass = element.getAttribute(ATT_CLASS); + + if (resolverClass != null) + { + try + { + ClassLoader pluginLoader = + element.getDeclaringExtension().getDeclaringPluginDescriptor().getPluginClassLoader(); + + return new URIResolverDelegate(resolverClass, pluginLoader).getURIResolver(); + } + catch (Exception e) + { + } + } + } + return null; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/eclipse/URIResolverWrapper.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/eclipse/URIResolverWrapper.java new file mode 100644 index 000000000..c6b4830b6 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/eclipse/URIResolverWrapper.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * 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.eclipse; + +import org.eclipse.wst.common.uriresolver.internal.provisional.URIResolver; +import org.eclipse.wst.common.uriresolver.internal.provisional.URIResolverPlugin; +import org.eclipse.wst.wsdl.validation.internal.resolver.IExtensibleURIResolver; +import org.eclipse.wst.wsdl.validation.internal.resolver.IURIResolutionResult; + +/** + * An wrapper URI resolver that wraps the Web Standard Tools URI resolver + * in a WSDL validator URI resolver. + */ +public class URIResolverWrapper implements IExtensibleURIResolver +{ + /** + * Constructor. + */ + public URIResolverWrapper() + { + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.resolver.IExtensibleURIResolver#resolve(java.lang.String, java.lang.String, java.lang.String, org.eclipse.wst.wsdl.validation.internal.resolver.IURIResolutionResult) + */ + public void resolve(String baseLocation, String publicId, String systemId, IURIResolutionResult result) + { + URIResolver resolver = URIResolverPlugin.createResolver(); + String location = null; + if (publicId != null || systemId != null) + { + location = resolver.resolve(baseLocation, publicId, systemId); + } + + if (location != null) + { + result.setLogicalLocation(location); + String physical = resolver.resolvePhysicalLocation(baseLocation, publicId, location); + if(physical != null) + { + result.setPhysicalLocation(physical); + } + else + { + result.setPhysicalLocation(location); + } + } + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/eclipse/ValidateWSDLPlugin.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/eclipse/ValidateWSDLPlugin.java new file mode 100644 index 000000000..5cecbe897 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/eclipse/ValidateWSDLPlugin.java @@ -0,0 +1,511 @@ +/******************************************************************************* + * 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.eclipse; + +import java.io.IOException; +import java.net.URL; +import java.util.ResourceBundle; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Plugin; +import org.eclipse.wst.wsdl.validation.internal.Constants; +import org.eclipse.wst.wsdl.validation.internal.WSDLValidatorDelegate; +import org.eclipse.wst.wsdl.validation.internal.wsdl11.WSDL11ValidatorDelegate; +import org.eclipse.wst.wsdl.validation.internal.xml.XMLCatalog; +import org.eclipse.wst.wsdl.validation.internal.xml.XMLCatalogEntityHolder; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; + +/** + * The main plugin class required for eclipse. + */ +public class ValidateWSDLPlugin extends Plugin +{ + protected final String PROPERTIES_FILE = "validatewsdlui"; + protected static ValidateWSDLPlugin instance; + protected ResourceBundle resourcebundle = null; + protected ResourceBundle wsdlValidatorResourceBundle = null; + + /** + * Constructor. + */ + public ValidateWSDLPlugin() + { + super(); + } + + /* (non-Javadoc) + * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception + { + super.start(context); + instance = this; + wsdlValidatorResourceBundle = ResourceBundle.getBundle(Constants.WSDL_VALIDATOR_PROPERTIES_FILE); + resourcebundle = ResourceBundle.getBundle(PROPERTIES_FILE); + + // Configure the XML catalog. + new ExtXMLCatalogPluginRegistryReader().readRegistry(); + new WSDLValidatorPluginRegistryReader( + "extvalidator", + "extvalidator", + WSDLValidatorPluginRegistryReader.EXT_VALIDATOR) + .readRegistry(); + + // register any WSDL 1.1 validators defined + new WSDL11ValidatorPluginRegistryReader("wsdl11validator", "validator").readRegistry(); + } + /* (non-Javadoc) + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception + { + super.stop(context); + XMLCatalog.reset(); + } + + /** + * Return the instance of this plugin object. + * + * @return the instance of this plugin object + */ + public static ValidateWSDLPlugin getInstance() + { + return instance; + } + + /** + * Get the install URL of this plugin. + * + * @return the install url of this plugin + */ + public String getInstallURL() + { + try + { + return Platform.resolve(getBundle().getEntry("/")).getFile(); + } + catch (IOException e) + { + return null; + } + } + + /************************************************************* + * ResourceBundle helper methods + * + *************************************************************/ + /** + * Returns the resource bundle for this plugin. + * + * @return the resource bundle for this plugin + */ + public ResourceBundle getResourceBundle() + { + return resourcebundle; + } + + /** + * Returns the resource bundle for the WSDL validator. + * + * @return the resource bundle for the WSDL validator + */ + public ResourceBundle getWSDLValidatorResourceBundle() + { + return wsdlValidatorResourceBundle; + } + + /** + * Returns the string for the given id. + * + * @param stringID - the id for the string + * @return the string for the given id + */ + public String getString(String stringID) + { + return getResourceBundle().getString(stringID); + } +} + +/** + * This class reads the plugin manifests and registers each WSDLExtensionValidator + */ +class WSDLValidatorPluginRegistryReader +{ + protected static final String PLUGIN_ID = "org.eclipse.wst.wsdl.validation"; + protected static final String ATT_CLASS = "class"; + protected static final String ATT_NAMESPACE = "namespace"; + protected static final String ATT_RESOURCEBUNDLE = "resourcebundle"; + protected static final int WSDL_VALIDATOR = 0; + protected static final int EXT_VALIDATOR = 1; + protected String extensionPointId; + protected String tagName; + protected int validatorType; + + /** + * + */ + public WSDLValidatorPluginRegistryReader(String extensionPointId, String tagName, int validatorType) + { + this.extensionPointId = extensionPointId; + this.tagName = tagName; + this.validatorType = validatorType; + } + + /** + * read from plugin registry and parse it. + */ + public void readRegistry() + { + IExtensionRegistry pluginRegistry = Platform.getExtensionRegistry(); + IExtensionPoint point = pluginRegistry.getExtensionPoint(PLUGIN_ID, extensionPointId); + if (point != null) + { + IConfigurationElement[] elements = point.getConfigurationElements(); + for (int i = 0; i < elements.length; i++) + { + readElement(elements[i]); + } + } + } + + /** + * readElement() - parse and deal with an extension like: + * + * <extension point="org.eclipse.validate.wsdl.WSDLExtensionValidator" + * id="soapValidator" + * name="SOAP Validator">> + * <validator> + * <run class=" org.eclipse.validate.wsdl.soap.SOAPValidator"/> + * </validator> + * <attribute name="namespace" value="http://schemas.xmlsoap.org/wsdl/soap/"/> + * </extension> + */ + protected void readElement(IConfigurationElement element) + { + if (element.getName().equals(tagName)) + { + String validatorClass = element.getAttribute(ATT_CLASS); + String namespace = element.getAttribute(ATT_NAMESPACE); + String resourceBundle = element.getAttribute(ATT_RESOURCEBUNDLE); + + if (validatorClass != null) + { + try + { + // ClassLoader pluginLoader = + // element.getDeclaringExtension().getDeclaringPluginDescriptor().getPlugin().getClass().getClassLoader(); + // modified to resolve certain situations where the plugin has not been initialized + + ClassLoader pluginLoader = + element.getDeclaringExtension().getDeclaringPluginDescriptor().getPluginClassLoader(); + +// if (validatorType == WSDL_VALIDATOR) +// { +// WSDL11ValidatorDelegate delegate = new WSDL11ValidatorDelegate(validatorClass, resourceBundle, pluginLoader); +// WSDLValidator.getInstance().registerWSDL11Validator(namespace, delegate); +// } + if (validatorType == EXT_VALIDATOR) + { + WSDLValidatorDelegate delegate = new WSDLValidatorDelegate(validatorClass, resourceBundle, pluginLoader); + WSDLValidator.getInstance().registerWSDLExtensionValidator(namespace, delegate); + } +// registerWSDLValidatorPluginExtensionWithClassName( +// pluginLoader, +// WSDLValidatorExtensionClass, +// WSDLValidatorExtensionNamespace); + } + catch (Exception e) + { + } + } + } + } + + /** + * Register the extension validator with the given class name and namespaces. + * + * @param classLoader - the class loader to create the validator + * @param className - the name of the extension validator + * @param namespace - the namespace of the extension validator + * @throws Exception + */ +// protected void registerWSDLValidatorPluginExtensionWithClassName( +// ClassLoader classLoader, +// String className, +// String namespace) +// throws Exception +// { +// try +// { +// Class validatorExtensionClass = classLoader != null ? classLoader.loadClass(className) : Class.forName(className); +// +// +// //IValidatorExtensionPlugin validatorHandler = (IValidatorExtensionPlugin)validatorExtensionClass.newInstance(); +// //add(namespace, validatorHandler.getValidator()); +// } +// catch (Exception e) +// { +// //System.out.println(e.getMessage()); +// //TODO: write the error message to the log file - use custom log writer class +// //ValidateWSDLPlugin.getInstance().getMsgLogger().write("WSDL Validator could not register the extension validator." + e.getMessage()); +// } +// } + + /** + * Register the loaded validator. + * + * @param namespace - the namespace of the validator + * @param validatorExtension - the extension validator + */ +// protected void add(String namespace, IWSDLValidator validatorExtension) +// { +// if (validatorType == WSDL_VALIDATOR) +// { +// WSDLConfigurator.registerWSDLValidator(namespace, validatorExtension); +// } +// else if (validatorType == WSI_VALIDATOR) +// { +// WSDLConfigurator.registerWSIValidator(namespace, validatorExtension); +// } +// } +} + +/** + * Read WSDl 1.1 extension validators. + * + * <extension + * point="com.ibm.etools.validation.validator" + * id="wsdlValidator" + * name="%_UI_WSDL_VALIDATOR"> + * <wsdl11validator + * namespace="http://schemas.xmlsoap.org/wsdl/soap/" + * class="org.eclipse.wsdl.validate.soap.wsdl11.SOAPValidator" + * resourcebundle="validatewsdlsoap"/> + * </extension> + * + */ +class WSDL11ValidatorPluginRegistryReader +{ + protected static final String PLUGIN_ID = "org.eclipse.wst.wsdl.validation"; + protected static final String ATT_CLASS = "class"; + protected static final String ATT_NAMESPACE = "namespace"; + protected static final String ATT_RESOURCEBUNDLE = "resourcebundle"; + protected String extensionPointId; + protected String tagName; + + /** + * Constructor. + * + * @param extensionPointId - the id of the extension point + * @param tagName - the tag name of the extension point + */ + public WSDL11ValidatorPluginRegistryReader(String extensionPointId, String tagName) + { + this.extensionPointId = extensionPointId; + this.tagName = tagName; + } + + /** + * Read from plugin registry and handle the configuration elements that match + * the spedified elements. + */ + public void readRegistry() + { + IExtensionRegistry pluginRegistry = Platform.getExtensionRegistry(); + IExtensionPoint point = pluginRegistry.getExtensionPoint(PLUGIN_ID, extensionPointId); + if (point != null) + { + IConfigurationElement[] elements = point.getConfigurationElements(); + for (int i = 0; i < elements.length; i++) + { + readElement(elements[i]); + } + } + } + + /** + * Parse and deal with the extension points. + * + * @param element The extension point element. + */ + protected void readElement(IConfigurationElement element) + { + if (element.getName().equals(tagName)) + { + String validatorClass = element.getAttribute(ATT_CLASS); + String namespace = element.getAttribute(ATT_NAMESPACE); + String resourceBundle = element.getAttribute(ATT_RESOURCEBUNDLE); + + if (validatorClass != null && namespace != null) + { + try + { + ClassLoader pluginLoader = + element.getDeclaringExtension().getDeclaringPluginDescriptor().getPluginClassLoader(); + WSDL11ValidatorDelegate delegate = new WSDL11ValidatorDelegate(validatorClass, resourceBundle, pluginLoader); + WSDLValidator.getInstance().registerWSDL11Validator(namespace, delegate); + } + catch (Exception e) + { + } + } + } + } +} + +/** + * This class reads the plugin manifests and registers each WSDLExtensionValidator + */ +class ExtXMLCatalogPluginRegistryReader +{ + protected static final String PLUGIN_ID = "org.eclipse.wst.wsdl.validation"; + protected static final String EXTENSION_POINT_ID = "xmlcatalog"; + + /** + * The xmlcatalog element allow adding an extension XML Catalog such as + * <xmlcatalog class="org.eclipse.wsdl.validate.ExtXMLCatalog"> + */ + protected static final String EXT_CATALOG_TAG_NAME = "xmlcatalog"; + protected static final String ATT_CLASS = "class"; + + /** + * The entity element allows adding specific XML catalog entities such as + * <entity + * publicid="http://schemas.xmlsoap.org/wsdl/" + * systemid="xsd/wsdl.xsd" /> + */ + protected static final String ENTITY_TAG_NAME = "entity"; + protected static final String ATT_PUBLIC_ID = "publicId"; + protected static final String ATT_SYSTEM_ID = "location"; + + /** + * The schemadir element allows adding a director of schemas to the XML catalog such as + * <schemadir location="c:\myschemadir" /> + * Note: It is more expensive to use this method then the entity method + * of adding schemas to the catalog as this method requires that all of + * the schemas be read. + */ + protected static final String SCHEMA_DIR_TAG_NAME = "schemadir"; + protected static final String ATT_LOCATION = "location"; + protected String pluginId, extensionPointId; + + /** + * read from plugin registry and parse it. + */ + public void readRegistry() + { + IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry(); + IExtensionPoint point = extensionRegistry.getExtensionPoint(PLUGIN_ID, EXTENSION_POINT_ID); + if (point != null) + { + IConfigurationElement[] elements = point.getConfigurationElements(); + for (int i = 0; i < elements.length; i++) + { + readElement(elements[i]); + } + } + } + + /** + * readElement() - parse and deal with an extension like: + * + * <extension point="com.ibm.etools.validate.wsdl.WSDLExtensionValidator" + * id="soapValidator" + * name="SOAP Validator">> + * <validator> + * <run class=" com.ibm.etools.validate.wsdl.soap.SOAPValidator"/> + * </validator> + * <attribute name="namespace" value="http://schemas.xmlsoap.org/wsdl/soap/"/> + * </extension> + */ + protected void readElement(IConfigurationElement element) + { + String elementname = element.getName(); + // Extension XML Catalogs. + if (elementname.equals(EXT_CATALOG_TAG_NAME)) + { + String xmlCatalogClass = element.getAttribute(ATT_CLASS); + + if (xmlCatalogClass != null) + { + try + { + // modified to resolve certain situations where the plugin has not been initialized + ClassLoader pluginLoader = + element.getDeclaringExtension().getDeclaringPluginDescriptor().getPluginClassLoader(); + // ClassLoader pluginLoader = + // element.getDeclaringExtension().getDeclaringPluginDescriptor().getPlugin().getClass().getClassLoader(); + XMLCatalog.setExtensionXMLCatalog(xmlCatalogClass, pluginLoader); + } + catch (Exception e) + { + System.out.println(e); + } + } + } + // XML Catalog entites. + else if(elementname.equals(ENTITY_TAG_NAME)) + { + String publicid = element.getAttribute(ATT_PUBLIC_ID); + String systemid = element.getAttribute(ATT_SYSTEM_ID); + if(publicid == null || systemid == null) + { + return; + } + Bundle bundle = Platform.getBundle(element.getDeclaringExtension().getNamespace()); + systemid = getAbsoluteLocation(systemid, bundle); + + XMLCatalog.addEntity(new XMLCatalogEntityHolder(publicid, systemid)); + } + // Schema directories for the XML Catalog. + else if(elementname.equals(SCHEMA_DIR_TAG_NAME)) + { + String location = element.getAttribute(ATT_LOCATION); + if(location != null) + { + Bundle bundle = Platform.getBundle(element.getDeclaringExtension().getNamespace()); + location = getAbsoluteLocation(location, bundle); + XMLCatalog.addSchemaDir(location); + } + } + } + + private String getAbsoluteLocation(String location, Bundle bundle) + { + URL url = null; + if(bundle != null) + { + url = bundle.getEntry(location); + } + + if(url != null) + { + try + { + url = Platform.resolve(url); + return url.toExternalForm(); + } + catch(IOException e) + { + //Unable to register the schema. + } + } + return location; + } +} + + + diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/eclipse/WSDLValidator.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/eclipse/WSDLValidator.java new file mode 100644 index 000000000..4adf55a26 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/eclipse/WSDLValidator.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * 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.eclipse; + +import java.util.Iterator; +import java.util.List; + +import org.eclipse.wst.wsdl.validation.internal.resolver.IExtensibleURIResolver; + +/** + * An Eclipse WSDL validator. This validator is the default validator + * used in the validation framework. There is only a single instance of + * this validator. When created, this validator registers all extension + * URI resolvers. + */ +public class WSDLValidator extends org.eclipse.wst.wsdl.validation.internal.WSDLValidator +{ + private static WSDLValidator instance = null; + + /** + * The constructor registers all of the URI resolvers defined via the + * WSDL URI resolver extension point with the WSDL validator. + * + */ + private WSDLValidator() + { + super(); + URIResolverRegistryReader uriRR = new URIResolverRegistryReader(); + List resolvers = uriRR.readRegistry(); + Iterator resolverIter = resolvers.iterator(); + while(resolverIter.hasNext()) + { + IExtensibleURIResolver resolver = (IExtensibleURIResolver)resolverIter.next(); + addURIResolver(resolver); + } + } + + /** + * Get the one and only instance of this Eclipse WSDL validator. + * + * @return The one and only instance of this Eclipse WSDL validator. + */ + public static WSDLValidator getInstance() + { + if(instance == null) + { + instance = new WSDLValidator(); + } + return instance; + } + +// /** +// * Validate the specified WSDL file. +// * +// * @param fileURI The URI of the WSDL file. +// * @return A validation report with the validation results. +// */ +// public IValidationReport validate(String fileURI) +// { +// return wsdlValidator.validate(fileURI); +// } +// /** +// * Validate the given WSDL InputStream +// * +// * @param fileURI The URI of the WSDL file. +// * @param inputStream the InputStream to validate +// * @return A validation report with the validation results. +// */ +// public IValidationReport validate(String fileURI, InputStream inputStream) +// { +// return wsdlValidator.validate(fileURI, inputStream); +// } + +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/exception/ValidateWSDLException.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/exception/ValidateWSDLException.java new file mode 100644 index 000000000..33d1b48b6 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/exception/ValidateWSDLException.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2001, 2005 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.exception; + +/** + * Custom exception for WSDL validation. + */ +public class ValidateWSDLException extends Exception +{ + /** + * Required serial version uid. + */ + private static final long serialVersionUID = 1L; + + /** + * Constructor. + * + * @param message The exception message + */ + public ValidateWSDLException(String message) + { + super(message); + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/resolver/IExtensibleURIResolver.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/resolver/IExtensibleURIResolver.java new file mode 100644 index 000000000..2030ae7f8 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/resolver/IExtensibleURIResolver.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * 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.resolver; + +/** + * An interface for the WSDL validator's URI resolver mechanism. The URI resolver + * is used to find the location of an entity. + */ +public interface IExtensibleURIResolver +{ + /** + * Resolve the location of the entity described by the publicId and systemId. + * + * @param baseLocation The location of the resource that contains the uri. + * @param publicId An optional public identifier (i.e. namespace name), or null if none. + * @param systemId An absolute or relative URI, or null if none. + * @param result The result of the resolution. + */ + public void resolve(String baseLocation, String publicId, String systemId, IURIResolutionResult result); +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/resolver/IURIResolutionResult.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/resolver/IURIResolutionResult.java new file mode 100644 index 000000000..236bb1165 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/resolver/IURIResolutionResult.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * 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.resolver; + +/** + * The representation of a URI resolution result. This interface is not meant to + * be implemented by clients. + * + */ +public interface IURIResolutionResult +{ + /** + * Get the logical location of the resolution result. + * + * @return The logical location of the resolution result. + */ + public String getLogicalLocation(); + + /** + * Set the logical location of the resolution result. + * + * @param logicalLocation The logical location of the resolution result. + */ + public void setLogicalLocation(String logicalLocation); + + /** + * Get the physical location of the resolution result. + * + * @return The physical location of the resolution result. + */ + public String getPhysicalLocation(); + + /** + * Set the physical location of the resolution result. + * + * @param physicalLocation The physical location of the resolution result. + */ + public void setPhysicalLocation(String physicalLocation); +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/resolver/URIResolutionResult.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/resolver/URIResolutionResult.java new file mode 100644 index 000000000..07df0c6f8 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/resolver/URIResolutionResult.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * 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.resolver; + +/** + * This class holds the URI resolution results. + * + */ +public class URIResolutionResult implements IURIResolutionResult +{ + private String logicalLocation = null; + private String physicalLocation = null; + + /** + * Constructor. + */ + public URIResolutionResult() + { + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.resolver.IURIResolutionResult#getLogicalLocation() + */ + public String getLogicalLocation() + { + return logicalLocation; + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.resolver.IURIResolutionResult#setLogicalLocation(java.lang.String) + */ + public void setLogicalLocation(String logicalLocation) + { + this.logicalLocation = logicalLocation; + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.resolver.IURIResolutionResult#getPhysicalLocation() + */ + public String getPhysicalLocation() + { + return physicalLocation; + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.resolver.IURIResolutionResult#setPhysicalLocation(java.lang.String) + */ + public void setPhysicalLocation(String physicalLocation) + { + this.physicalLocation = physicalLocation; + } + +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/resolver/URIResolver.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/resolver/URIResolver.java new file mode 100644 index 000000000..9e4b86f81 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/resolver/URIResolver.java @@ -0,0 +1,283 @@ +/******************************************************************************* + * 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.resolver; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.eclipse.wst.wsdl.validation.internal.util.LazyURLInputStream; +import org.eclipse.wst.wsdl.validation.internal.xml.XMLCatalog; + +/** + * This is the main URI resolver that calls out to all of the registered + * external URI resolvers to locate an entity. If none of the external resolvers + * can locate the entity the resolver will ask the internal WSDL validator XML + * catalog to resolve the location. + */ +public class URIResolver implements IExtensibleURIResolver, XMLEntityResolver +{ + private List extURIResolversList = new ArrayList(); + + /** + * Constructor. + */ + public URIResolver() + { + } + + + /** + * Add an extension URI resolver. + * + * @param uriResolver + * The extension URI resolver. + */ + public void addURIResolver(IExtensibleURIResolver uriResolver) + { + extURIResolversList.add(uriResolver); + } + + + /** + * @see org.eclipse.wst.wsdl.validation.internal.resolver.IExtensibleURIResolver#resolve(java.lang.String, java.lang.String, java.lang.String, org.eclipse.wst.wsdl.validation.internal.resolver.IURIResolutionResult) + */ + public void resolve(String baseLocation, String publicId, String systemId, IURIResolutionResult result) + { + Iterator resolverIter = extURIResolversList.iterator(); + while(resolverIter.hasNext()) + { + IExtensibleURIResolver resolver = (IExtensibleURIResolver)resolverIter.next(); + if (resolver == null) + { + continue; + } + resolver.resolve(baseLocation, publicId, systemId, result); + if (result.getLogicalLocation() != null && !result.getPhysicalLocation().equals(systemId)) + { + break; + } + } + + // If we haven't been able to locate the result yet ask the internal XML + // catalog. + if (result.getLogicalLocation() == null && (publicId != null || systemId != null)) + { + String tempresult = XMLCatalog.getInstance().resolveEntityLocation(publicId, systemId); + if(tempresult != null) + { + result.setLogicalLocation(tempresult); + result.setPhysicalLocation(tempresult); + } + } + if(result.getLogicalLocation() == null) + { + result.setLogicalLocation(normalize(baseLocation, systemId)); + result.setPhysicalLocation(result.getLogicalLocation()); + } + } + + public IURIResolutionResult resolve(String baseLocation, String publicId, String systemId) + { + IURIResolutionResult result= new URIResolutionResult(); + resolve(baseLocation, publicId, systemId, result); + return result; + } + + /* + * (non-Javadoc) + * + * @see org.apache.xerces.xni.parser.XMLEntityResolver#resolveEntity(org.apache.xerces.xni.XMLResourceIdentifier) + */ + public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) throws XNIException, IOException + { + String publicId = resourceIdentifier.getPublicId(); + String systemId = resourceIdentifier.getLiteralSystemId(); + if (publicId == null || publicId.equals("")) + { + publicId = resourceIdentifier.getNamespace(); + } + IURIResolutionResult result = resolve(resourceIdentifier.getBaseSystemId(), publicId, systemId); + XMLInputSource xmlInputSource = null; + if (result != null) + { + LazyURLInputStream is = new LazyURLInputStream(result.getPhysicalLocation()); + xmlInputSource = new XMLInputSource(publicId, result.getLogicalLocation(), result.getLogicalLocation(), is, null); + } + return xmlInputSource; + } + + /** + * Normalize the systemId. Make it absolute with respect to the + * baseLocation if necessary. + * + * @param baseLocation The base location of the file. + * @param systemId The system id of the file. + * @return A normalized version of the system id. + */ + protected String normalize(String baseLocation, String systemId) + { + if(systemId == null) + { + return systemId; + } + // Try to find a scheme in the systemId. + int schemaLoc = systemId.indexOf(':'); + if(schemaLoc != -1 && systemId.charAt(schemaLoc+1) == '/') + { + // A scheme has been found. The systemId is an + // absolute location so return it. + return systemId; + } + if(baseLocation == null) + { + return baseLocation; + } + + String result = ""; + + // Ensure all slashes in the locations are /. + baseLocation = baseLocation.replace('\\','/'); + systemId = systemId.replace('\\','/'); + + // Remove the trailing section of the baseLocation. + int lastSlash = baseLocation.lastIndexOf('/'); + String tempresult = baseLocation.substring(0, lastSlash+1); + + if(systemId.startsWith("/")) + { + systemId = systemId.substring(1); + } + + // Join the base location with the systemid + tempresult = tempresult + systemId; + + // While the relative location starts with a ../ or ./ change + // the result and the relative location. + int loc; + while((loc = tempresult.lastIndexOf("./")) != -1) + { + result = tempresult.substring(loc + 2) + result; + if(tempresult.charAt(loc - 1) == '.') + { + if(tempresult.charAt(loc - 2) == '/') + { + String temp = tempresult.substring(0, loc - 2); + int loc2 = temp.lastIndexOf('/'); + if(loc2 == -1) + { + // If there is no other / before this the URL must start with scheme:/../ + result = "../" + result; + tempresult = tempresult.substring(0, loc - 1); + } + else + { + // Remove the section that comes before this one from tempresult unless it's ../. + tempresult = tempresult.substring(0, loc - 1); + int numSectsToRemove = 1; + + while(tempresult.endsWith("./")) + { + int tempreslen = tempresult.length(); + if(tempreslen > 2 && tempresult.charAt(tempreslen -3) == '.') + { + if(tempreslen > 3 && tempresult.charAt(tempreslen - 4) == '/') + { + numSectsToRemove++; + tempresult = tempresult.substring(0, tempresult.length() -3); + } + else + { + break; + } + } + else + { + if(tempresult.charAt(tempresult.length() -2) == '/') + { + tempresult = tempresult.substring(0, tempresult.length() -2); + } + else + { + break; + } + } + } + // Remove the sections. + for(int i = 0; i < numSectsToRemove; i++) + { + String temp2 = tempresult.substring(0,tempresult.length()-1); + int loc3 = temp2.lastIndexOf('/'); + if(loc3 == -1) + { + break; + } + tempresult = tempresult.substring(0, loc3+1); + } + } + } + else + { + // The URI is of the form file://somedir../ so copy it as is + String temp = tempresult.substring(0, loc - 1); + int loc2 = temp.lastIndexOf('/'); + if(loc2 == -1) + { + // The URI must look like file:../ or ../ so copy over the whole tempresult. + result = tempresult.substring(0,loc+2) + result; + tempresult = ""; + } + else + { + // Copy over the whole somedir../ + result = tempresult.substring(loc2 + 1, tempresult.length()); + tempresult = tempresult.substring(0, loc2+1); + } + } + } + else + { + if(tempresult.charAt(loc -1 ) == '/') + { + // Result is of the form file://something/./something so remove the ./ + tempresult = tempresult.substring(0,loc); + } + else + { + // Result URI is of form file://somedir./ so copy over the whole section. + String temp = tempresult.substring(0, loc - 1); + int loc2 = temp.lastIndexOf('/'); + if(loc2 == -1) + { + // The URI must look like file:./ or ./ so copy over the whole tempresult. + result = tempresult.substring(0, loc) + result; + tempresult = ""; + } + else + { + // Copy over the whole somedir./ + result = tempresult.substring(loc2 + 1, tempresult.length()); + tempresult = tempresult.substring(0, loc2+1); + } + } + } + } + result = tempresult + result; + return result; + } + +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/resolver/URIResolverDelegate.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/resolver/URIResolverDelegate.java new file mode 100644 index 000000000..80a999297 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/resolver/URIResolverDelegate.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * 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.resolver; + + +/** + * A delegate to hold information about an extension URI resolver. + */ +public class URIResolverDelegate +{ + private String classname; + private ClassLoader classloader; + private IExtensibleURIResolver resolver = null; + + + /** + * Constructor. + * + * @param classname The class name of the URI resolver. + * @param classloader The class loader to use to load the URI resolver. + */ + public URIResolverDelegate(String classname, ClassLoader classloader) + { + this.classname = classname; + this.classloader = classloader; + } + + /** + * Get the URI resolver described by this delegate. + * + * @return The URI resolver described by this delegate. + */ + public IExtensibleURIResolver getURIResolver() + { + if(resolver == null) + { + try + { + resolver = (IExtensibleURIResolver)classloader.loadClass(classname).newInstance(); + } + catch(Exception e) + { + try + { + resolver = (IExtensibleURIResolver)getClass().getClassLoader().loadClass(classname).newInstance(); + } + catch(Exception e2) + { + } + } + } + return resolver; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ui/ant/ExtensionValidator.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ui/ant/ExtensionValidator.java new file mode 100644 index 000000000..6b9aa2003 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ui/ant/ExtensionValidator.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * 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.ui.ant; + +/** + * An extension Ant WSDL validator. + */ +public class ExtensionValidator +{ + private String classname = null; + private String namespace = null; + private String resourcebundle = null; + + public void setClass(String classname) + { + this.classname = classname; + } + + public String getClassName() + { + return this.classname; + } + + public void setNamespace(String namespace) + { + this.namespace = namespace; + } + + public String getNamespace() + { + return this.namespace; + } + + public void setResourceBundle(String resourcebundle) + { + this.resourcebundle = resourcebundle; + } + + public String getResourceBundle() + { + return this.resourcebundle; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ui/ant/URIResolver.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ui/ant/URIResolver.java new file mode 100644 index 000000000..2d66239b6 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ui/ant/URIResolver.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * 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.ui.ant; + +import org.apache.tools.ant.Task; + +/** + * The URIResolver task allows specifying an extension URI resolver with + * the WSDLValidate Ant task. + */ +public class URIResolver extends Task +{ + private String clazz = null; + + /** + * Set the class name of the extension URI resolver. + * + * @param clazz The class name of the extension URI resolver. + */ + public void setClassName(String clazz) + { + this.clazz = clazz; + } + + /** + * Get the class name of the extension URI resolver. + * + * @return The class name of the extension URI resolver. + */ + public String getClassName() + { + return clazz; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ui/ant/WSDLValidate.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ui/ant/WSDLValidate.java new file mode 100644 index 000000000..5ad53d9c2 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ui/ant/WSDLValidate.java @@ -0,0 +1,458 @@ +/******************************************************************************* + * 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.ui.ant; + +import java.io.File; + +import java.net.URL; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.DTDLocation; +import org.apache.tools.ant.types.FileSet; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.XMLCatalog; +import org.eclipse.wst.wsdl.validation.internal.IValidationMessage; +import org.eclipse.wst.wsdl.validation.internal.IValidationReport; +import org.eclipse.wst.wsdl.validation.internal.WSDLValidator; +import org.eclipse.wst.wsdl.validation.internal.WSDLValidatorDelegate; +import org.eclipse.wst.wsdl.validation.internal.resolver.URIResolverDelegate; +import org.eclipse.wst.wsdl.validation.internal.util.MessageGenerator; +import org.eclipse.wst.wsdl.validation.internal.wsdl11.WSDL11ValidatorDelegate; + +/** + * An Ant task to run WSDL validation on a file or a set of files. + * + * Options + * - file - the file to run validation on (optional if fileset is used) + * - failonerror - fail the build process on the first file with an error + * - wsicompliance - how to report WS-I errors - REQUIRE, SUGGEST, IGNORE (defaults to REQUIRE) + * + * Supported Nested Elements + * - xmlcatalog - an xml catalog + * - dtd - a dtd specification as would appear in an xmlcatalog + * - schema - a schema specification as would appear in an xmlcatalog + * - entity - an entity specification as would appear in an xmlcatalog + * - fileset - a set of files to validate + * - wsdl11validator - an extension WSDL 1.1 validator + * - uriresolver - an extension URI resolver + * + */ +public class WSDLValidate extends Task +{ + protected final String UI_PROPERTIES = "validatewsdlui"; + protected final String VALIDATOR_PROPERTIES = org.eclipse.wst.wsdl.validation.internal.Constants.WSDL_VALIDATOR_PROPERTIES_FILE; + protected final String _ERROR_NO_FILE_SPECIFIED = "_ERROR_NO_FILE_SPECIFIED"; + protected final String _UI_INFORMATION_DELIMITER = "_UI_INFORMATION_DELIMITER"; + protected final String _UI_ACTION_VALIDATING_FILE = "_UI_ACTION_VALIDATING_FILE"; + protected final String _UI_ERROR_MARKER = "_UI_ERROR_MARKER"; + protected final String _UI_WARNING_MARKER = "_UI_WARNING_MARKER"; + protected final String _UI_VALID = "_UI_VALID"; + protected final String _UI_INVALID = "_UI_INVALID"; + protected final String _EXC_UNABLE_TO_VALIDATE_FILE = "_EXC_UNABLE_TO_VALIDATE_FILE"; + protected final String _EXC_WSDL_FAIL_ON_ERROR = "_EXC_WSDL_FAIL_ON_ERROR"; + + protected final String FILE_PROTOCOL = "file:///"; + + // Global Vars + protected List filesets = new ArrayList(); + protected String file = null; + protected Path classpath; + protected String xsdDirectory = null; + protected boolean failOnError = false; + protected XMLCatalog globalXMLCatalog = new XMLCatalog(); + protected List wsdl11validators = new ArrayList(); + protected List extvalidators = new ArrayList(); + protected List extURIResolvers = new ArrayList(); + + /** + * Constuctor. + */ + public WSDLValidate() + { + } + + /** + * Tells the WSDL validate task to fail the build if an error is encountered. + * + * @param failOnError Whether to fail on error or not. + */ + public void setFailOnError(boolean failOnError) + { + this.failOnError = failOnError; + } + + /** + * Set the directory where the base schema files for the catalog are located. + * + * @param dir - the directory of the base schema files + */ + public void setSchemaDir(String dir) + { + xsdDirectory = dir; + } + + /** + * Set a file to run WSDL validation on. + * + * @param file - a file to run validation on + */ + public void setFile(String file) + { + this.file = file; + } + + /** + * Create a set of files to run WSDL validation on. + * + * @return the FileSet of files to run WSDL validation on + */ + public FileSet createFileset() + { + FileSet fileset = new FileSet(); + filesets.add(fileset); + return fileset; + } + + /** + * Add an XML catalog to the validator. + * + * @param catalog - the catalog to add to the validator + */ + public void addConfiguredXMLCatalog(XMLCatalog catalog) + { + globalXMLCatalog.addConfiguredXMLCatalog(catalog); + } + /** + * Add an extension validator. + * + * @param extVal The extension validator to add. + */ + public void addConfiguredExtensionValidator(ExtensionValidator extVal) + { + extvalidators.add(extVal); + } + /** + * Add an extension WSDL 1.1 validator. + * + * @param extVal The extension WSDL 1.1 validator to add. + */ + public void addConfiguredWSDL11Validator(ExtensionValidator extVal) + { + wsdl11validators.add(extVal); + } + + /** + * Allow specification of an entity outside of an XMLCatalog. + * + * @return a DTDLocation with the specified entity + **/ + public DTDLocation createEntity() + { + DTDLocation dtdLoc = new DTDLocation(); + globalXMLCatalog.addEntity(dtdLoc); + return dtdLoc; + } + + /** + * Allow specification of a DTD outside of an XMLCatalog. + * + * @return a DTDLocation with the specified DTD + **/ + public DTDLocation createDTD() + { + DTDLocation dtdLoc = new DTDLocation(); + globalXMLCatalog.addEntity(dtdLoc); + return dtdLoc; + } + + /** + * Create a URIResolver extension. + * + * @return A URIResolver. + */ + public URIResolver createURIResolver() + { + URIResolver urires = new URIResolver(); + extURIResolvers.add(urires.getClassName()); + return urires; + + } + + /** + * Get a list of all the files to run WSDL validation on. Takes the file and fileset + * and creates the list. + * + * @return the list of files to be validated + */ + protected List getFileList() + { + List files = new ArrayList(); + + // if a specific file was specified add it to the list + if (file != null) + { + try + { + URL url = new URL(file); + files.add(url.toExternalForm()); + } + catch(Exception e) + { + File theFile = new File(file); + if(!theFile.isAbsolute()) + { + theFile = new File(getProject().getBaseDir(), file); + } + String absFile = theFile.toString(); + if(!absFile.startsWith("file:")) + { + absFile = FILE_PROTOCOL + absFile; + } + absFile = absFile.replace('\\','/'); + files.add(absFile); + } + } + + // go through all filesets specified and add all the files to the list + Iterator fsIter = filesets.iterator(); + while (fsIter.hasNext()) + { + FileSet fileset = (FileSet)fsIter.next(); + DirectoryScanner ds = fileset.getDirectoryScanner(fileset.getProject()); + String basedir = ds.getBasedir().toString() + File.separator; + + String[] filelist = ds.getIncludedFiles(); + int numFiles = filelist.length; + if (files != null && numFiles > 0) + { + for (int i = 0; i < numFiles; i++) + { + String absFile = FILE_PROTOCOL + basedir + filelist[i]; + absFile = absFile.replace('\\','/'); + files.add(absFile); + } + } + } + return files; + } + + /* (non-Javadoc) + * @see org.apache.tools.ant.Task#execute() + */ + public void execute() throws BuildException + { + // the resource bundles for the ui and validator are needed + MessageGenerator messGen = null; + try + { + ResourceBundle uiRB = ResourceBundle.getBundle(UI_PROPERTIES); + messGen = new MessageGenerator(uiRB); + } + catch (MissingResourceException e) + { + // if the resource bundles can't be opened we can't report error so throw an exception + throw new BuildException("Unable to open resource bundle. " + e); + } + + // Set the XML catalog. + org.eclipse.wst.wsdl.validation.internal.xml.XMLCatalog.setExtensionXMLCatalog(XMLCatalogImpl.class.getName(), getClass().getClassLoader()); + XMLCatalogImpl xmlCatalog = (XMLCatalogImpl)org.eclipse.wst.wsdl.validation.internal.xml.XMLCatalog.getExtensionCatalogInstance(); + xmlCatalog.addXMLCatalog(globalXMLCatalog); + + WSDLValidator wsdlValidator = new WSDLValidator(); + + // Set the extension URIResolvers. + Iterator resolversIter = extURIResolvers.iterator(); + while(resolversIter.hasNext()) + { + String resolverClass = (String)resolversIter.next(); + wsdlValidator.addURIResolver(new URIResolverDelegate(resolverClass, getClass().getClassLoader()).getURIResolver()); + } + + // Get the list of files to validate. + List files = getFileList(); + + // Register the WSDL 1.1 extension validators. + Iterator wsdl11extIter = wsdl11validators.iterator(); + while(wsdl11extIter.hasNext()) + { + ExtensionValidator extVal = (ExtensionValidator)wsdl11extIter.next(); + WSDL11ValidatorDelegate delegate = new WSDL11ValidatorDelegate(extVal.getClassName(), extVal.getResourceBundle()); + wsdlValidator.registerWSDL11Validator(extVal.getNamespace(), delegate); + } + + // Register the extension validators. + Iterator extIter = extvalidators.iterator(); + while(extIter.hasNext()) + { + ExtensionValidator extVal = (ExtensionValidator)extIter.next(); + WSDLValidatorDelegate delegate = new WSDLValidatorDelegate(extVal.getClassName(), extVal.getResourceBundle()); + wsdlValidator.registerWSDLExtensionValidator(extVal.getNamespace(), delegate); + } + + // The user didn't specify any files to validate. + if (files == null || files.isEmpty()) + { + System.err.println(messGen.getString(_ERROR_NO_FILE_SPECIFIED)); + return; + } + + if (xsdDirectory != null) + { + org.eclipse.wst.wsdl.validation.internal.xml.XMLCatalog.addSchemaDir(xsdDirectory); + } + + // Validate all the files specified. + Iterator iFiles = files.iterator(); + + // Common strings needed in validation output. + String infoDelim = messGen.getString(_UI_INFORMATION_DELIMITER); + String valid = messGen.getString(_UI_VALID); + String invalid = messGen.getString(_UI_INVALID); + String errormarker = messGen.getString(_UI_ERROR_MARKER); + String warningmarker = messGen.getString(_UI_WARNING_MARKER); + + StringBuffer result = null; + boolean notvalid = true; + while (iFiles.hasNext()) + { + result = new StringBuffer(); + notvalid = false; + String filename = (String)iFiles.next(); + try + { + result.append(infoDelim).append("\n"); + result.append(messGen.getString(_UI_ACTION_VALIDATING_FILE, filename)).append(" - "); + + IValidationReport valReport = wsdlValidator.validate(filename); + + IValidationMessage[] messages = valReport.getValidationMessages(); + + if (!valReport.hasErrors()) + { + result.append(valid); + } + else + { + result.append(invalid); + notvalid = true; + } + result.append("\n").append(infoDelim).append("\n"); + + result.append(reportMessages(messages, errormarker, warningmarker)); + + System.out.println(result.toString()); + } + catch (Exception e) + { + System.err.println(messGen.getString(_EXC_UNABLE_TO_VALIDATE_FILE, filename, e)); + } + finally + { + if (notvalid && failOnError) + { + // To fail on error, throw a build exception. + throw new BuildException(messGen.getString(_EXC_WSDL_FAIL_ON_ERROR)); + } + } + } + + org.eclipse.wst.wsdl.validation.internal.xml.XMLCatalog.reset(); + + } + + /** + * Return a string with formatted output for the messages. + * + * @param messages The messages to report. + * @param errormarker The marker to use for error messages. + * @param warningmarker The marker to use for warning messages. + * @return A string with the formatted output. + */ + protected String reportMessages(IValidationMessage[] messages, String errormarker, String warningmarker) + { + StringBuffer returnBuffer = new StringBuffer(); + + if (messages == null) + return returnBuffer.toString(); + + String prefix = null; + int numMessages = messages.length; + for(int i = 0; i < numMessages; i++) + { + IValidationMessage message = messages[i]; + + if(message.getSeverity() == IValidationMessage.SEV_ERROR) + { + prefix = errormarker; + } + else if(message.getSeverity() == IValidationMessage.SEV_WARNING) + { + prefix = warningmarker; + } + else + { + prefix = ""; + }if(message.getSeverity() == IValidationMessage.SEV_ERROR) + { + prefix = errormarker; + } + else if(message.getSeverity() == IValidationMessage.SEV_WARNING) + { + prefix = warningmarker; + } + else + { + prefix = ""; + }if(message.getSeverity() == IValidationMessage.SEV_ERROR) + { + prefix = errormarker; + } + else if(message.getSeverity() == IValidationMessage.SEV_WARNING) + { + prefix = warningmarker; + } + else + { + prefix = ""; + }if(message.getSeverity() == IValidationMessage.SEV_ERROR) + { + prefix = errormarker; + } + else if(message.getSeverity() == IValidationMessage.SEV_WARNING) + { + prefix = warningmarker; + } + else + { + prefix = ""; + } + returnBuffer + .append(prefix) + .append(" ") + .append(message.getLine()) + .append(":") + .append(message.getColumn()) + .append(":") + .append(message.getMessage()) + .append("\n"); + } + return returnBuffer.toString(); + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ui/ant/XMLCatalogImpl.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ui/ant/XMLCatalogImpl.java new file mode 100644 index 000000000..2f762b1a4 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ui/ant/XMLCatalogImpl.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * 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.ui.ant; + +import org.apache.tools.ant.types.DTDLocation; +import org.apache.tools.ant.types.XMLCatalog; +import org.xml.sax.InputSource; + +/** + * An implementation of the WSDL Validator's XML Catalog that uses the XML Catalog + * from ant. + */ +public class XMLCatalogImpl extends org.eclipse.wst.wsdl.validation.internal.xml.XMLCatalog +{ + protected XMLCatalog xmlCatalog = new XMLCatalog(); + + /** + * @see org.eclipse.wst.wsdl.validation.internal.xml.XMLCatalog#addEntryToCatalog(java.lang.String, java.lang.String) + */ + public void addEntryToCatalog(String publicId, String systemId) + { + DTDLocation resLoc = new DTDLocation(); + resLoc.setLocation(systemId); + resLoc.setPublicId(publicId); + xmlCatalog.addEntity(resLoc); + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.xml.XMLCatalog#resolveEntityLocation(java.lang.String, java.lang.String) + */ + public String resolveEntityLocation(String publicId, String systemId) + { + String resolvedId = null; + + try + { + InputSource is = xmlCatalog.resolveEntity(publicId, systemId); + if (is != null) + { + resolvedId = is.getSystemId(); + } + } + // + catch (Exception e) + { + // Do nothing if the resource can't be resolved. + } + // needs to return null if it can't resolve the id + if (resolvedId != null && resolvedId.equals("")) + { + resolvedId = null; + } + return resolvedId; + } + + /** + * Add a configured XML Catalog to this catalog. + * + * @param catalog A configured XML catalog to add to this catalog. + */ + public void addXMLCatalog(XMLCatalog catalog) + { + xmlCatalog.addConfiguredXMLCatalog(catalog); + } + +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ui/text/WSDLValidate.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ui/text/WSDLValidate.java new file mode 100644 index 000000000..d7e939737 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/ui/text/WSDLValidate.java @@ -0,0 +1,376 @@ +/******************************************************************************* + * 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.ui.text; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Iterator; +import java.util.List; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.Vector; + +import org.eclipse.wst.wsdl.validation.internal.IValidationMessage; +import org.eclipse.wst.wsdl.validation.internal.IValidationReport; +import org.eclipse.wst.wsdl.validation.internal.WSDLValidator; +import org.eclipse.wst.wsdl.validation.internal.WSDLValidatorDelegate; +import org.eclipse.wst.wsdl.validation.internal.resolver.IExtensibleURIResolver; +import org.eclipse.wst.wsdl.validation.internal.resolver.URIResolverDelegate; +import org.eclipse.wst.wsdl.validation.internal.util.MessageGenerator; +import org.eclipse.wst.wsdl.validation.internal.wsdl11.WSDL11ValidatorDelegate; +import org.eclipse.wst.wsdl.validation.internal.xml.XMLCatalog; +import org.eclipse.wst.wsdl.validation.internal.xml.XMLCatalogEntityHolder; + +import com.ibm.wsdl.util.StringUtils; + +/** + * A commande line tool to run WSDL Validation on a single or multiple files. + * + * Options + * -schemaDir directory : a directory of schemas to load into the catalog + * -schema namespace location : a schema to load into the registry + * -wsdl11v classname namespace resourcebundle : register a WSDL 1.1 extension validator + * to load for the given namespace with the given resourcebundle + * -wsiv validatorClass namespace propertiesfile : register a WS-I validator + * -uriresolver URIResolverClass : register an extension URI resolver + */ +public class WSDLValidate +{ + private final String FILE_PREFIX = "file:///"; + private static final String VALIDATOR_PROPERTIES = + org.eclipse.wst.wsdl.validation.internal.Constants.WSDL_VALIDATOR_PROPERTIES_FILE; + private static final String UI_PROPERTIES = "validatewsdlui"; + private static final String _ERROR_WRONG_ARGUMENTS = "_ERROR_WRONG_ARGUMENTS"; + private static final String _UI_INFORMATION_DELIMITER = "_UI_INFORMATION_DELIMITER"; + private static final String _UI_ACTION_VALIDATING_FILE = "_UI_ACTION_VALIDATING_FILE"; + private static final String _UI_VALID = "_UI_VALID"; + private static final String _UI_INVALID = "_UI_INVALID"; + private static final String _UI_ERROR_MARKER = "_UI_ERROR_MARKER"; + private static final String _UI_WARNING_MARKER = "_UI_WARNING_MARKER"; + private static final String _ERROR_UNABLE_TO_LOAD_EXT_VALIDATOR = "_ERROR_UNABLE_TO_LOAD_EXT_VALIDATOR"; + + private static final String PARAM_WSDL11VAL = "-wsdl11v"; + private static final String PARAM_EXTVAL = "-extv"; + private static final String PARAM_SCHEMADIR = "-schemaDir"; + private static final String PARAM_SCHEMA = "-schema"; + private static final String PARAM_URIRESOLVER = "-uriresolver"; + + private static final String STRING_EMPTY = ""; + private static final String STRING_SPACE = " "; + private static final String STRING_DASH = "-"; + + + protected ResourceBundle resourceBundle; + protected List errors = null; + protected List warnings = null; + protected WSDLValidator wsdlValidator; + + /** + * Constuctor. + */ + public WSDLValidate() + { + wsdlValidator = new WSDLValidator(); + } + + public void addURIResolver(IExtensibleURIResolver uriResolver) + { + wsdlValidator.addURIResolver(uriResolver); + } + + /** + * Run WSDL validation on a given file. + * + * @param directory - the current dir for resolving relative file names + * @param filename - the name of the file to validate + * @param validatorRB - the WSDL validator resource bundle + * @throws Exception + */ + protected IValidationReport validateFile(String directory, String filename, ResourceBundle validatorRB) + throws Exception + { + // resolve the location of the file + String filelocation = null; + try + { + URL test = StringUtils.getURL(new URL(FILE_PREFIX + directory + "/"), filename); + filelocation = test.toExternalForm(); + } + catch (MalformedURLException e) + { + throw new Exception("Unable to resolve WSDL file location"); + } + // run validation on the file and record the errors and warnings + IValidationReport valReport = wsdlValidator.validate(filelocation); + return valReport; + } + + /** + * Returns a String with formatted output for a list of messages. + * + * @param messages The messages to get. + * @param errormarker The marker to use to label error messages. + * @param warningmarker The marker to use to label warning messages. + * @return A string with a formatted list of the messages. + */ + protected String getMessages(IValidationMessage[] messages, String errormarker, String warningmarker) + { + StringBuffer outputBuffer = new StringBuffer(); + if (messages != null) + { + // create a list of messages that looks like + // ERROR 1:1 Error message content + int numMessages = messages.length; + String marker = null; + for (int i = 0; i < numMessages; i++) + { + IValidationMessage message = messages[i]; + int severity = message.getSeverity(); + if (severity == IValidationMessage.SEV_ERROR) + { + marker = errormarker; + } + else if (severity == IValidationMessage.SEV_WARNING) + { + marker = warningmarker; + } + else + { + marker = STRING_EMPTY; + } + outputBuffer + .append(marker) + .append(STRING_SPACE) + .append(message.getLine()) + .append(":") + .append(message.getColumn()) + .append(STRING_SPACE) + .append(message.getMessage()) + .append("\n"); + } + } + return outputBuffer.toString(); + } + + /** + * The main entry point into the command line tool. + * Checks the command line arguments, registers the default validators and runs validation on the + * list of files. + * + * @param args - the arguments to the validator + */ + public static void main(String[] args) + { + List wsdlFiles = new Vector(); + MessageGenerator messGen = null; + ResourceBundle validatorRB = null; + try + { + ResourceBundle uiRB = ResourceBundle.getBundle(UI_PROPERTIES); + messGen = new MessageGenerator(uiRB); + validatorRB = ResourceBundle.getBundle(VALIDATOR_PROPERTIES); + } + catch (MissingResourceException e) + { + System.err.println("Validation failed: Unable to load the properties file."); + return; + } + // no arguments specified. Print usage. + if (args.length < 1) + { + System.out.println(messGen.getString(_ERROR_WRONG_ARGUMENTS)); + return; + } + + int argslength = args.length; + + WSDLValidate wsdlValidator = new WSDLValidate(); + // go through the parameters + for (int i = 0; i < argslength; i++) + { + String param = args[i]; + + // registering a validator + if (param.equalsIgnoreCase(WSDLValidate.PARAM_WSDL11VAL) || param.equalsIgnoreCase(WSDLValidate.PARAM_EXTVAL)) + { + + String validatorClass = args[++i]; + if (!validatorClass.startsWith(WSDLValidate.STRING_DASH)) + { + String namespace = args[++i]; + + if (!namespace.startsWith(WSDLValidate.STRING_DASH)) + { + String propertiesFile = args[++i]; + if (propertiesFile.startsWith(WSDLValidate.STRING_DASH)) + { + propertiesFile = null; + i--; + } + if(param.equalsIgnoreCase(WSDLValidate.PARAM_WSDL11VAL)) + { + WSDL11ValidatorDelegate delegate = new WSDL11ValidatorDelegate(validatorClass, propertiesFile); + wsdlValidator.wsdlValidator.registerWSDL11Validator(namespace, delegate); + } + else if(param.equalsIgnoreCase(WSDLValidate.PARAM_EXTVAL)) + { + WSDLValidatorDelegate delegate = new WSDLValidatorDelegate(validatorClass, propertiesFile); + wsdlValidator.wsdlValidator.registerWSDLExtensionValidator(namespace, delegate); + } + } + else + { + namespace = null; + i--; + } + } + else + { + validatorClass = null; + i--; + } + } + // registering a directory with schemas + else if (param.equalsIgnoreCase(WSDLValidate.PARAM_SCHEMADIR)) + { + String xsdDir = args[++i]; + XMLCatalog.addSchemaDir(xsdDir); + } + // registering a schema + else if (param.equalsIgnoreCase(WSDLValidate.PARAM_SCHEMA)) + { + String publicid = args[++i]; + String systemid = args[++i]; + XMLCatalog.addEntity(new XMLCatalogEntityHolder(publicid, systemid)); + } + else if(param.equalsIgnoreCase(PARAM_URIRESOLVER)) + { + String resolverClass = args[++i]; + wsdlValidator.addURIResolver(new URIResolverDelegate(resolverClass, null).getURIResolver()); + } + // a file to validate + else + { + if(!param.startsWith(WSDLValidate.STRING_DASH)) + { + wsdlFiles.add(param); + } + } + + } + // validate the file + StringBuffer outputBuffer = null; + String infoDelim = messGen.getString(_UI_INFORMATION_DELIMITER); + String valid = messGen.getString(_UI_VALID); + String invalid = messGen.getString(_UI_INVALID); + String errormarker = messGen.getString(_UI_ERROR_MARKER); + String warningmarker = messGen.getString(_UI_WARNING_MARKER); + + Iterator filesIter = wsdlFiles.iterator(); + while (filesIter.hasNext()) + { + outputBuffer = new StringBuffer(); + String wsdlFile = (String)filesIter.next(); + try + { + IValidationReport valReport = wsdlValidator.validateFile(System.getProperty("user.dir"), wsdlFile, validatorRB); + + outputBuffer.append(infoDelim).append("\n"); + outputBuffer.append(messGen.getString(_UI_ACTION_VALIDATING_FILE, wsdlFile)).append(" - "); + if (!valReport.hasErrors()) + { + outputBuffer.append(valid); + } + else + { + outputBuffer.append(invalid); + } + outputBuffer.append("\n").append(infoDelim).append("\n"); + outputBuffer.append(wsdlValidator.getMessages(valReport.getValidationMessages(), errormarker, warningmarker)); + System.out.println(outputBuffer.toString()); + } + catch (Exception e) + { + System.out.println(e.getMessage()); + } + } + } + + /** + * Load a validator into the wsdl validation framework registry. + * + * @param namespace - the namespace the validator checks + * @param validatorClass - the name of the class the implements IWSDLValidator + * @param propertiesFile - the name of the properties file for the validator + * @param type - the type of validator - WSDL or WS-I + * @param messGen - a MessageGenerator for producing error messages + */ +// protected static void loadExtensionValidator( +// String namespace, +// String validatorClass, +// String propertiesFile, +// Integer type, +// MessageGenerator messGen) +// { +// try +// { +// ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); +// IWSDLValidator validator = (IWSDLValidator)classLoader.loadClass(validatorClass).newInstance(); +// // if no properties file is specified we can still load the validator +// if (propertiesFile != null && !propertiesFile.equals("")) +// { +// ResourceBundle rb = ResourceBundle.getBundle(propertiesFile); +// validator.setResourceBundle(rb); +// } +// else +// { +// propertiesFile = null; +// } +// +// ValidatorRegistry.getInstance().registerValidator(namespace, validator, type); +// } +// catch (Exception e) +// { +// System.out.println(messGen.getString(_ERROR_UNABLE_TO_LOAD_EXT_VALIDATOR, namespace, e)); +// } +// +// } + // /** + // * loadWSDL11ExtensionValidator + // * Load an extension validator into the WSDL 1.1 validator + // * @param namespace + // * @param validatorClass + // * @param propertiesFile + // * @param type + // * @param classLoader + // */ + // protected static void loadWSDL11ExtensionValidator( + // String namespace, + // String validatorClass, + // String resourceBundle, + // ClassLoader classLoader) + // { + // try + // { + // Class valclass = classLoader.loadClass(validatorClass); + // IWSDL11Validator validator = (IWSDL11Validator)valclass.newInstance(); + // validator.setResourceBundle(ResourceBundle.getBundle(resourceBundle)); + // WSDLConfigurator.registerWSDL11Validator(namespace,validator); + // } + // catch(Exception e) + // { + // System.out.println("Unable to load the WSDL 1.1 validator for namespace " + // + namespace + e); + // } + // + // } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/util/ErrorMessage.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/util/ErrorMessage.java new file mode 100644 index 000000000..81bdc0e83 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/util/ErrorMessage.java @@ -0,0 +1,216 @@ +/******************************************************************************* + * 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.util; + +/** + * A class to hold validation messages. In this case an error message is a generic + * term for any kind of validation message. + */ +public class ErrorMessage +{ + private int errorLine, errorColumn, severity; + private String errorString, uri; + private int startOffset = -1; + private int endOffset = -1; + + /** + * Constructor. + */ + public ErrorMessage() + { + } + + /** + * Sets the message. + * + * @param error The message to set. + * @see #getErrorMessage + */ + public void setErrorMessage(String error) + { + errorString = error; + } + + /** + * Sets the severity of the message. + * + * @param severity The severity of the message. + * @see #getSeverity + */ + public void setSeverity(int severity) + { + this.severity = severity; + } + + /** + * Sets the severity of the message using string names for the severity. + * + * @param severity The string representation of the severity. + * @see #getSeverity + */ + public void setSeverity(String severity) + { + if (severity.equals("warning")) + { + this.severity = 0; + } + else if (severity.equals("error")) + { + this.severity = 1; + } + else if (severity.equals("fatal")) + { + this.severity = 2; + } + } + + /** + * Sets the line where the error is located. + * + * @param line The line where the error is located. + * @see #getErrorLine + */ + public void setErrorLine(int line) + { + errorLine = line; + } + + /** + * Sets the column where the error is located. + * + * @param column The column where the error is located. + * @see #getErrorColumn + */ + public void setErrorColumn(int column) + { + errorColumn = column; + } + + /** + * Returns the error message. + * + * @return The error message. + * @see #setErrorMessage + */ + public String getErrorMessage() + { + return errorString; + } + + /** + * Returns the severity of the error. + * + * @return The severity of the error. + * @see #setSeverity + */ + public int getSeverity() + { + return severity; + } + + /** + * Returns the line location of the error. + * + * @return The line location of the error. + * @see #setErrorLine + */ + public int getErrorLine() + { + return errorLine; + } + + /** + * Returns the column location of the error. + * + * @return The column location of the error. + * @see #setErrorColumn + */ + public int getErrorColumn() + { + return errorColumn; + } + + /** + * Sets the start offset. + * + * @param start The start offset. + * @see #getErrorStartOffset + */ + public void setErrorStartOffset(int start) + { + startOffset = start; + } + + /** + * Returns the error start offset. + * + * @return The error start offset. + * @see #setErrorStartOffset + */ + public int getErrorStartOffset() + { + return startOffset; + } + + /** + * Sets the end offset. + * + * @param end The end offset. + * @see #getErrorEndOffset + */ + public void setErrorEndOffset(int end) + { + endOffset = end; + } + + /** + * Returns the error end offset. + * + * @return The error end offset. + * @see #setErrorEndOffset + */ + public int getErrorEndOffset() + { + return endOffset; + } + + /** + * Adds a new line ot the error message. + * + * @param newLine The new line to add to the error message. + */ + public void addNewErrorMessageLine(String newLine) + { + errorString += "\n" + newLine; + } + + /** + * Set the URI of the error message. + * + * @param uri The URI to set. + */ + + public void setURI(String uri) + { + this.uri = uri; + } + + /** + * Get the URI of the error message. + * + * @return The URI of the error message. + */ + public String getURI() + { + return uri; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/util/LazyURLInputStream.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/util/LazyURLInputStream.java new file mode 100644 index 000000000..1bc6ab199 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/util/LazyURLInputStream.java @@ -0,0 +1,162 @@ +/******************************************************************************* + * Copyright (c) 2001, 2005 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.util; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + + +/** + * This class allows InputStreams to be created and returned to xerces without + * actually opening file handles or network connections until it is absolutely + * neccessary. + */ +public class LazyURLInputStream extends InputStream +{ + private static int debugTotalOpenStreamCount = 0; + protected InputStream inner; + protected String url; + protected boolean error; + boolean hasMarks; + boolean pretendFileIsStillOpen; + + public LazyURLInputStream(String url) + { + this.url = url; + inner = null; + pretendFileIsStillOpen = false; + } + + private void createInnerStreamIfRequired() throws IOException + { + if (inner == null && !error) + { + debugTotalOpenStreamCount++; + //System.out.println("Creating stream (" + debugTotalOpenStreamCount + ")-- " + url); + try + { + inner = new URL(url).openStream(); + pretendFileIsStillOpen = false; + hasMarks = false; + } + finally + { + if (inner == null) + { + error = true; + } + } + } + } + + protected void closeStream() throws IOException { + if (inner != null && !pretendFileIsStillOpen) { + inner.close(); + pretendFileIsStillOpen = true; + } + } + + public int available() throws IOException + { + if (pretendFileIsStillOpen) return 0; + createInnerStreamIfRequired(); + if (inner == null) throw new IOException("Stream not available"); + return inner.available(); + } + + public void close() throws IOException + { + if (pretendFileIsStillOpen) { + // Stop behaving as if the stream were still open. + pretendFileIsStillOpen = false; + } else { + if (inner != null) { + debugTotalOpenStreamCount--; + //System.out.println("Closing stream (" + debugTotalOpenStreamCount + ") -- " + url); + inner.close(); + } + } + } + + public void mark(int readlimit) + { + if (pretendFileIsStillOpen) return; + hasMarks = true; + try { + createInnerStreamIfRequired(); + inner.mark(readlimit); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public boolean markSupported() + { + if (pretendFileIsStillOpen) return false; + try { + createInnerStreamIfRequired(); + if (inner == null) return false; + return inner.markSupported(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return false; + } + + public int read() throws IOException + { + if (pretendFileIsStillOpen) return -1; + createInnerStreamIfRequired(); + if (inner == null) throw new IOException("Stream not available"); + int bytesRead = inner.read(); + if (bytesRead == -1 && !hasMarks) closeStream(); + return bytesRead; + } + + + public int read(byte[] b) throws IOException { + if (pretendFileIsStillOpen) return -1; + createInnerStreamIfRequired(); + if (inner == null) throw new IOException("Stream not available"); + int bytesRead = inner.read(b); + if (bytesRead == -1 && !hasMarks) closeStream(); + return bytesRead; + } + + public int read(byte[] b, int off, int len) throws IOException + { + if (pretendFileIsStillOpen) return -1; + createInnerStreamIfRequired(); + if (inner == null) throw new IOException("Stream not available"); + int bytesRead = inner.read(b, off, len); + if (bytesRead == -1 && !hasMarks) closeStream(); + return bytesRead; + } + + public void reset() throws IOException + { + if (pretendFileIsStillOpen) return; + createInnerStreamIfRequired(); + if (inner == null) throw new IOException("Stream not available"); + inner.reset(); + } + + public long skip(long n) throws IOException + { + if (pretendFileIsStillOpen) return 0; + createInnerStreamIfRequired(); + if (inner == null) throw new IOException("Stream not available"); + return inner.skip(n); + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/util/MessageGenerator.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/util/MessageGenerator.java new file mode 100644 index 000000000..0b78cb9c7 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/util/MessageGenerator.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * 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.util; + +import java.util.ResourceBundle; +import java.text.MessageFormat; + +/** + * A convenience class for working with resources in a resource bundle. + */ +public class MessageGenerator +{ + protected ResourceBundle resourcebundle; + + /** + * Constructor. + * + * @param rb The resource bundle to work with. + */ + public MessageGenerator(ResourceBundle rb) + { + resourcebundle = rb; + } + + /** + * Set the resourcebundle to the one specified. + * + * @param rb The resource bundle to set. + */ + protected void setResourceBundle(ResourceBundle rb) + { + resourcebundle = rb; + } + + /** + * Gets the string resource for the given key. + * + * @param key The key for the resource. + * @return The string from the resource bundle. + */ + public String getString(String key) + { + return resourcebundle.getString(key); + } + + /** + * Gets the string resource for the given key and does one substitution. + * + * @param key The key for the resource. + * @param s1 The substitution to perform. + * @return The string from the resource bundle. + */ + public String getString(String key, Object s1) + { + return MessageFormat.format(getString(key), new Object[] { s1 }); + } + + /** + * Gets the string resource for the given key and does two substitutions. + * + * @param key The key for the resource. + * @param s1 The first substitution to perform. + * @param s2 The second substitution to perform. + * @return The string from the resource bundle. + */ + public String getString(String key, Object s1, Object s2) + { + return MessageFormat.format(getString(key), new Object[] { s1, s2 }); + } + + /** + * Gets the string resource for the given key and does three substitutions. + * + * @param key The key for the resource. + * @param s1 The first substitution to perform. + * @param s2 The second substitution to perform. + * @param s3 The third substitution to perform. + * @return The string from the resource bundle. + */ + public String getString(String key, Object s1, Object s2, Object s3) + { + return MessageFormat.format(getString(key), new Object[] { s1, s2, s3 }); + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/IWSDL11ValidationInfo.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/IWSDL11ValidationInfo.java new file mode 100644 index 000000000..0c1bc4ff1 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/IWSDL11ValidationInfo.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * 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.util.Hashtable; + +import org.apache.xerces.xs.XSModel; +import org.eclipse.wst.wsdl.validation.internal.resolver.URIResolver; + +/** + * An interface for WSDL 1.1 validation information. Uses an existing + * validation info object and provides methods to set and retrieve + * schemas and convenience methods for setting errors with objects. + */ +public interface IWSDL11ValidationInfo +{ + /** + * Returns the URI of the file being validated. + * + * @return The URI of the file being validated. + */ + public String getFileURI(); + + /** + * Add a schema to the list of schemas available for this WSDL document. + * + * @param xsModel The schema to add to the list. + */ + public void addSchema(XSModel xsModel); + + /** + * Get an array of all the schemas available for this WSDL document. + * + * @return An array of all the schemas available for this WSDL document. + */ + public XSModel[] getSchemas(); + + /** + * Clear all the stored schemas. + */ + public void clearSchemas(); + + /** + * Set the element locations hashtable. + * + * @param elementLocations The hashtable to set with the element locations. + */ + public void setElementLocations(Hashtable elementLocations); + + /** + * Convenience method for extensibly validators to add error messages. + * + * @param message The error to add. + * @param element The object to add the error for. + */ + public void addError(String message, Object element); + + /** + * Convenience method for extensibly validators to add error messages. + * + * @param message The error to add. + * @param element The object to add the error for. + * @param errorKey The error key for this message + * @param messageArguments The strings used to create the message. + */ + public void addError(String message, Object element, String errorKey, Object[] messageArguments); + + /** + * Add an error message at the given line and column. + * + * @param message The error to add. + * @param line The line location of the error. + * @param column The column location of the error. + * @param uri The uri of the file containing the error. + */ + public void addError(String message, int line, int column, String uri); + + /** + * Convenience method for extensibly validators to add warning messages. + * + * @param message The warning to add. + * @param element The object to add the warning for. + */ + public void addWarning(String message, Object element); + + /** + * Add a warning message at the given line and column. + * + * @param message The warning to add. + * @param line The line location of the warning. + * @param column The column location of the warning. + * @param uri The uri of the file containing the warning. + */ + public void addWarning(String message, int line, int column, String uri); + + /** + * Get the URI resolver in use for this validation. The URI resolver + * returned is actually a URI resolver handler that will + * iterate through all of the registered URI resolvers. + * + * @return The URI resolver handler. + */ + public URIResolver getURIResolver(); +} + diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/IWSDL11Validator.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/IWSDL11Validator.java new file mode 100644 index 000000000..a6bd2e23d --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/IWSDL11Validator.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * 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.util.List; +import java.util.ResourceBundle; + +/** + * Interface for a validator plugged into the WSDL 1.1 validator. + */ +public interface IWSDL11Validator +{ + /** + * Validate the given element. + * + * @param element The element to validate. + * @param parents A list of parents of this element. + * @param valInfo The current validation information. + */ + public void validate(Object element, List parents, IWSDL11ValidationInfo valInfo); + + /** + * Set the resource bundle of the validator. + * + * @param rb The resource bundle to set. + */ + public void setResourceBundle(ResourceBundle rb); + +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/ImportHolder.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/ImportHolder.java new file mode 100644 index 000000000..205bc9b79 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/ImportHolder.java @@ -0,0 +1,602 @@ +/******************************************************************************* + * 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.resolver.IURIResolutionResult; +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 classpathURI = 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('\\','/'); + IURIResolutionResult classpathURI = valinfo.getURIResolver().resolve(this.contextURI, this.namespace, this.location); + if(classpathURI.getLogicalLocation() != null) + { + this.location = classpathURI.getLogicalLocation(); + } + if(classpathURI.getPhysicalLocation() != null) + { + this.classpathURI = classpathURI.getPhysicalLocation(); + 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.classpathURI)) + { + 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(); + String canonicalfileString = testfile.getCanonicalPath(); + + 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(classpathURI != null && !classpathURI.equals(location)) + { + inputSource.setByteStream(new URL(classpathURI).openStream()); + } + } + + 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; + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/LocationHolder.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/LocationHolder.java new file mode 100644 index 000000000..1def333f9 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/LocationHolder.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * 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; + +/** + * Holds the location information for an element in a document. + */ +public class LocationHolder +{ + private int line; + private int column; + private String uri; + + /** + * Constructor. + * + * @param line The line number. + * @param column The column number. + * @param uri The URI of the document. + */ + public LocationHolder(int line, int column, String uri) + { + this.line = line; + this.column = column; + this.uri = uri; + } + + /** + * Get the line number. + * + * @return The line number. + */ + public int getLine() + { + return line; + } + + /** + * Get the column number. + * + * @return The column number. + */ + public int getColumn() + { + return column; + } + + /** + * Get the file URI. + * + * @return The file URI. + */ + public String getURI() + { + return uri; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/ReaderError.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/ReaderError.java new file mode 100644 index 000000000..36b4e44dc --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/ReaderError.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * 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; + +/** + * Holds an error created when reading a WSDL document. + */ +public class ReaderError +{ + protected Object parentObject; // the object of the parent of the object with the error + protected Object object; // the object the error is associated with + protected String error; // the error associated with the object + + /** + * Constructor. + * + * @param parentObject the parent object of the object with the error + * @param object the object with the error + * @param error the error + */ + public ReaderError(Object parentObject, Object object, String error) + { + this.parentObject = parentObject; + this.object = object; + this.error = error; + } + + /** + * Returns the parent object of the object with the error. + * + * @return the parent object of the object with the error + */ + public Object getParentObject() + { + return parentObject; + } + + /** + * Returns the object with the error. + * + * @return the object with the error + */ + public Object getObject() + { + return object; + } + + /** + * Returns the error message. + * + * @return the error message + */ + public String getError() + { + return error; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/ValidatorRegistry.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/ValidatorRegistry.java new file mode 100644 index 000000000..90564f483 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/ValidatorRegistry.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * 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.util.Hashtable; +import java.util.Map; + + +/** + * A registry to hold all the WSDL 1.1 validators. + */ +public class ValidatorRegistry +{ + + protected static ValidatorRegistry verInstance; + + protected Map validatorReg = new Hashtable(); + + /** + * Constructor. + */ + protected ValidatorRegistry() + { + } + + /** + * Returns the instance of this registry. + * + * @return The instance of this registry. + */ + public static ValidatorRegistry getInstance() + { + if (verInstance == null) + { + verInstance = new ValidatorRegistry(); + } + return verInstance; + } + + /** + * Register this validator delegate with the given namespace. + * + * @param namespace The namespace the validator is associated with. + * @param valDelegate The validator delegate to register. + */ + public void registerValidator(String namespace, WSDL11ValidatorDelegate valDelegate) + { + // allow the null namespace but make it the empty string + if (namespace == null) + { + namespace = ""; + } + + // add the validator to the hashtable + validatorReg.put(namespace, valDelegate); + } + + /** + * Ask for the validator associated with this namespace. If none is found + * return null. + * + * @param namespace The namespace of the validator. + * @return The WSDL 1.1 validator for the given namespace. + */ + public IWSDL11Validator queryValidatorRegistry(String namespace) + { + // if the namespace is null allow it and treat it as the empty string + if (namespace == null) + { + namespace = ""; + } + WSDL11ValidatorDelegate delegate = (WSDL11ValidatorDelegate)validatorReg.get(namespace); + if(delegate != null) + { + return delegate.getValidator(); + } + return null; + } + + /** + * Convenience method that tells whether a validator for a given namespace is registered. + * + * @param namespace The namespace to check. + * @return True if there is a validator registered, false otherwise. + */ + public boolean hasRegisteredValidator(String namespace) + { + if (queryValidatorRegistry(namespace) != null) + { + return true; + } + return false; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/WSDL11BasicValidator.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/WSDL11BasicValidator.java new file mode 100644 index 000000000..4d7b0c238 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/WSDL11BasicValidator.java @@ -0,0 +1,691 @@ +/******************************************************************************* + * 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.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.ResourceBundle; +import java.util.Vector; + +import javax.wsdl.Binding; +import javax.wsdl.BindingFault; +import javax.wsdl.BindingInput; +import javax.wsdl.BindingOperation; +import javax.wsdl.BindingOutput; +import javax.wsdl.Definition; +import javax.wsdl.Fault; +import javax.wsdl.Input; +import javax.wsdl.Message; +import javax.wsdl.Operation; +import javax.wsdl.Output; +import javax.wsdl.Part; +import javax.wsdl.Port; +import javax.wsdl.PortType; +import javax.wsdl.Service; +import javax.wsdl.Types; +import javax.wsdl.extensions.ExtensibilityElement; +import javax.xml.namespace.QName; + +import org.apache.xerces.xs.XSModel; +import org.eclipse.wst.wsdl.validation.internal.util.MessageGenerator; +import org.eclipse.wst.wsdl.validation.internal.wsdl11.xsd.SchemaAttributeTable; +import org.eclipse.wst.wsdl.validation.internal.wsdl11.xsd.XSDValidator; + +import com.ibm.wsdl.Constants; +/** + * Validate the elements defined in a WSDL 1.1 Document. + */ +public class WSDL11BasicValidator implements IWSDL11Validator +{ + protected final String NAMESPACES_FEATURE_ID = "http://xml.org/sax/features/namespaces"; + protected final String VALIDATION_FEATURE_ID = "http://xml.org/sax/features/validation"; + protected final String SCHEMA_VALIDATION_FEATURE_ID = "http://apache.org/xml/features/validation/schema"; + protected final String SCHEMA_FULL_CHECKING_FEATURE_ID = + "http://apache.org/xml/features/validation/schema-full-checking"; + protected final String CONTINUE_AFTER_FATAL_ERROR_ID = "http://apache.org/xml/features/continue-after-fatal-error"; + protected final String SOAP_ENCODING_URI = "http://schemas.xmlsoap.org/soap/encoding/"; + + // Error and Warning Keys + private final String _PORT_NAME_NOT_UNIQUE = "_PORT_NAME_NOT_UNIQUE"; + private final String _NO_BINDING_FOR_PORT = "_NO_BINDING_FOR_PORT"; + private final String _NO_ADDRESS_PORT = "_NO_ADDRESS_PORT"; + private final String _MORE_THEN_ONE_ADDRESS_PORT = "_MORE_THEN_ONE_ADDRESS_PORT"; //TODO should be _MORE_THAN_ONE_ADDRESS_PORT, not THEN + private final String _PORTTYPE_UNDEFINED_FOR_BINDING = "_PORTTYPE_UNDEFINED_FOR_BINDING"; + private final String _OPERATION_UNDEFINED_FOR_PORTTYPE = "_OPERATION_UNDEFINED_FOR_PORTTYPE"; + private final String _OPERATION_NO_INPUT_OR_OUTPUT = "_OPERATION_NO_INPUT_OR_OUTPUT"; + private final String _INPUT_NAME_NOT_UNIQUE = "_INPUT_NAME_NOT_UNIQUE"; + private final String _MESSAGE_UNDEFINED_FOR_INPUT = "_MESSAGE_UNDEFINED_FOR_INPUT"; + private final String _OUTPUT_NAME_NOT_UNIQUE = "_OUTPUT_NAME_NOT_UNIQUE"; + private final String _MESSAGE_UNDEFINED_FOR_OUTPUT = "_MESSAGE_UNDEFINED_FOR_OUTPUT"; + private final String _MESSAGE_UNDEFINED_FOR_FAULT = "_MESSAGE_UNDEFINED_FOR_FAULT"; + private final String _PART_NO_ELEMENT_OR_TYPE = "_PART_NO_ELEMENT_OR_TYPE"; + private final String _PART_BOTH_ELEMENT_AND_TYPE = "_PART_BOTH_ELEMENT_AND_TYPE"; + private final String _PART_INVALID_ELEMENT = "_PART_INVALID_ELEMENT"; + private final String _PART_INVALID_TYPE = "_PART_INVALID_TYPE"; + private final String _WARN_SOAPENC_IMPORTED_PART = "_WARN_SOAPENC_IMPORTED_PART"; + + private final int ELEMENT = 0; + private final int TYPE = 1; + + private final String REQUEST = "Request"; + private final String RESPONSE = "Response"; + private final String QUOTE = "'"; + private final String EMPTY_STRING = ""; + + + //protected WSDL11ValidatorController validatorcontroller; + protected MessageGenerator messagegenerator; + + /** + * @see org.eclipse.wst.wsdl.validation.internal.wsdl11.IWSDL11Validator#validate(java.lang.Object, java.util.List, org.eclipse.wsdl.validate.wsdl11.IWSDL11ValidationInfo) + */ + public void validate(Object element, List parents, IWSDL11ValidationInfo valInfo) + { + //this.validatorcontroller = validatorcontroller; + //setDefaultResourceBundleIfNeeded(validatorcontroller); + Definition wsdlDefinition = (Definition)element; + //validateTypes(wsdlDefinition, valInfo); + validateServices(wsdlDefinition, valInfo); + validateBindings(wsdlDefinition, valInfo); + validatePortTypes(wsdlDefinition, valInfo); + validateMessages(wsdlDefinition, valInfo); + + } + + /** + * Takes a list of ExtensibilityElements and checks if there's a validator + * associated with each element and if so calls the validator. + * + * @param parents The list of parents of the elements. + * @param extensibilityElements The list of elements to validate. + * @param validatorcontroller The validator controller. + * @param wsdlDefinition The defnintions element for this document. + */ + protected void validateExtensibilityElementList( + List parents, + List extensibilityElements, + IWSDL11ValidationInfo valInfo) + { + ValidatorRegistry ver = ValidatorRegistry.getInstance(); + Iterator extElems = extensibilityElements.iterator(); + while (extElems.hasNext()) + { + ExtensibilityElement element = (ExtensibilityElement)extElems.next(); + String namespace = element.getElementType().getNamespaceURI(); + IWSDL11Validator val = ver.queryValidatorRegistry(namespace); + if (val != null) + { + val.validate(element, parents, valInfo); + } +// else +// { +// valInfo.addNamespaceWithNoValidator(namespace); +// } + } + } + + /** + * If the resourcebundle hasn't been set, set it to the one registered with the ValidatorController. + * + * @param validatorcontroller The validator controller to get the resource bundle from. + */ + // protected void setDefaultResourceBundleIfNeeded(WSDL11ValidatorController validatorcontroller) + // { + // if (messagegenerator == null) + // { + // setResourceBundle(validatorcontroller.getResourceBundle()); + // } + // } + + /** + * Set the resourcebundle to the one specified. + * + * @param rb The resource bundle to set. + */ + public void setResourceBundle(ResourceBundle rb) + { + messagegenerator = new MessageGenerator(rb); + } + + /** + * Ensure that the Types element is correct. + * + * @param wsdlDefinition The definitions element from the current document. + */ + + protected void validateTypes(Definition wsdlDefinition, IWSDL11ValidationInfo valInfo) + { + Types types = wsdlDefinition.getTypes(); + // ensure that types is defined + if (types != null) + { + List parents = new Vector(); + parents.add(wsdlDefinition); + Object extensibleElements[] = types.getExtensibilityElements().toArray(); + parents.add(0, types); + validateExtensibilityElementList(parents, types.getExtensibilityElements(), valInfo); + parents.remove(0); + } + } + + /** + * Validates all of the declared services for the definition. + * + * @param wsdlDefinition The WSDL definitions element. + */ + protected void validateServices(Definition wsdlDefinition, IWSDL11ValidationInfo valInfo) + { + if (wsdlDefinition.getServices() == null) + return; + Object services[] = wsdlDefinition.getServices().values().toArray(); + List parents = new Vector(); + parents.add(wsdlDefinition); + Hashtable allPorts = new Hashtable(); + + //TODO: check that ports in other imported files don't conflict with ports in this one + // // register all of the imported ports + // Iterator imports = wsdlDefinition.getImports().values().iterator(); + // while(imports.hasNext()) + // { + // Iterator impservices = ((Import)imports.next()).getDefinition().getServices().values().iterator(); + // while(impservices.hasNext()) + // { + // Iterator impports = ((Service)impservices.next()).getPorts().values().iterator(); + // while(impports.hasNext()) + // { + // Port tempP = (Port)impports.next(); + // allPorts.put(tempP.getName(),tempP); + // } + // } + // } + for (int i = 0; i < services.length; i++) + { + Service s = (Service)services[i]; + parents.add(0, s); + Object ports[] = s.getPorts().values().toArray(); + HashSet portInputs = new HashSet(); + HashSet portOutputs = new HashSet(); + for (int j = 0; j < ports.length; j++) + { + Port p = (Port)ports[j]; + parents.add(0, p); + // a Port name must be unique within the entire WDSL document + if (allPorts.contains(p.getName())) + { String[] args = {p.getName()}; + + valInfo.addError(messagegenerator.getString(_PORT_NAME_NOT_UNIQUE, QUOTE + args[0] + QUOTE), + p, _PORT_NAME_NOT_UNIQUE, args); + } + else + { + allPorts.put(p.getName(), p); + + // get the binding for this port and see if the PortType for the binding + // is defined + if (p.getBinding() == null || p.getBinding().isUndefined()) + { + String bindingName = EMPTY_STRING; + if (p.getBinding() != null) + { + bindingName = p.getBinding().getQName().getLocalPart(); + } + String args[] = {p.getName()}; + valInfo.addError( + messagegenerator.getString(_NO_BINDING_FOR_PORT, QUOTE + args[0] + QUOTE, QUOTE + bindingName + QUOTE), + p, _NO_BINDING_FOR_PORT, args); + } + else + { + // TODO: Check that the output of one port isn't the input of another and vice versa + // extensibility elements the port + // there can only be one and must be one extensibility element defined for a port + List extelems = p.getExtensibilityElements(); + if (extelems.size() < 1) + { String args[]= {p.getName()}; + valInfo.addError(messagegenerator.getString(_NO_ADDRESS_PORT, QUOTE + args[0] + QUOTE), + p, _NO_ADDRESS_PORT, args); + } + else if (extelems.size() > 1) + { + for (int k = 1; k < extelems.size(); k++) + { + String[] args = {p.getName()}; + valInfo.addError( + messagegenerator.getString(_MORE_THEN_ONE_ADDRESS_PORT, QUOTE + args[0] + QUOTE), + extelems.get(k), _MORE_THEN_ONE_ADDRESS_PORT, args); + } + } + validateExtensibilityElementList(parents, p.getExtensibilityElements(), valInfo); + } + } + + parents.remove(0); + } + // extensibility elements for the service + validateExtensibilityElementList(parents, s.getExtensibilityElements(), valInfo); + parents.remove(0); + } + } + + /** + * Checks that the bindings refer to valid PortTypes and all of the operations + // in a given binding refer to a defined operation within the corresponding + // PortType. + * + * @param wsdlDefinition The WSDL definitions element. + */ + protected void validateBindings(Definition wsdlDefinition, IWSDL11ValidationInfo valInfo) + { + if (wsdlDefinition.getBindings() == null) + return; + Object bindings[] = wsdlDefinition.getBindings().values().toArray(); + List parents = new Vector(); + parents.add(wsdlDefinition); + for (int i = 0; i < bindings.length; i++) + { + Binding b = (Binding)bindings[i]; + parents.add(0, b); + PortType portType = b.getPortType(); + + if (portType == null) + { + continue; + } + // the PortType is not defined so don't bother checking the operations + if (portType.isUndefined()) + { String[] args = {portType.getQName().getLocalPart(), b.getQName().getLocalPart()}; + valInfo.addError( + messagegenerator.getString( + _PORTTYPE_UNDEFINED_FOR_BINDING, + QUOTE + args[0] + QUOTE, + QUOTE + args[1] + QUOTE), + b, _PORTTYPE_UNDEFINED_FOR_BINDING, args); + } + else + { + // the PortType is defined so now we have to check that the operations are defined + Object bindingOperations[] = b.getBindingOperations().toArray(); + + // check if the operation is defined for each BindingOperation + for (int k = 0; k < bindingOperations.length; k++) + { + BindingOperation bo = (BindingOperation)bindingOperations[k]; + parents.add(0, bo); + if (bo.getOperation() == null || bo.getOperation().isUndefined()) + { + String[] args = {b.getQName().getLocalPart(), portType.getQName().getLocalPart()}; + valInfo.addError( + messagegenerator.getString( + _OPERATION_UNDEFINED_FOR_PORTTYPE, + QUOTE + args[0] + QUOTE, + QUOTE + args[1] + QUOTE), + bo, _OPERATION_UNDEFINED_FOR_PORTTYPE, args); + // nice idea to add suggestions to other elements to fix the error + // but it doesn't work with multipe files like this + //addValidationMessage(warningList,portType,portType.getQName().getLocalPart() + "Define an operation here to correspond with the operation in: " + bo.getName()); + } + // take care of all the extensibility elements in the binding operation, binding inputs, outputs and faults + else + { + BindingInput binput = bo.getBindingInput(); + if (binput != null) + { + parents.add(0, binput); + // extensibility elements for binding operation input + validateExtensibilityElementList( + parents, + bo.getBindingInput().getExtensibilityElements(), + valInfo); + parents.remove(0); + } + BindingOutput boutput = bo.getBindingOutput(); + if (boutput != null) + { + parents.add(0, boutput); + // extensibility elements for binding operation output + validateExtensibilityElementList( + parents, + bo.getBindingOutput().getExtensibilityElements(), + valInfo); + parents.remove(0); + } + // no input or output has been defined for the operation + if (binput == null && boutput == null) + { String[] args = { bo.getName() }; + valInfo.addError( + messagegenerator.getString(_OPERATION_NO_INPUT_OR_OUTPUT, QUOTE + args[0] + QUOTE), + bo, _OPERATION_NO_INPUT_OR_OUTPUT, args); + } + // extensibility elements for each binding operation fault + Iterator faults = bo.getBindingFaults().values().iterator(); + while (faults.hasNext()) + { + BindingFault bf = (BindingFault)faults.next(); + parents.add(0, bf); + validateExtensibilityElementList(parents, bf.getExtensibilityElements(), valInfo); + parents.remove(0); + } + } + // extensibility elements for binding operation + validateExtensibilityElementList(parents, bo.getExtensibilityElements(), valInfo); + parents.remove(0); + } + } + // extensibility elements for the binding + validateExtensibilityElementList(parents, b.getExtensibilityElements(), valInfo); + parents.remove(0); + } + + } + + /** + * Check that all of the PortTypes have valid messages associated with their + // operation input, output and fault types. + * + * @param wsdlDefinition The WSDL definitions element. + */ + protected void validatePortTypes(Definition wsdlDefinition, IWSDL11ValidationInfo valInfo) + { + if (wsdlDefinition.getPortTypes() == null) + return; + Object porttypes[] = wsdlDefinition.getPortTypes().values().toArray(); + + for (int i = 0; i < porttypes.length; i++) + { + PortType p = (PortType)porttypes[i]; + Object operations[] = p.getOperations().toArray(); + List inAndOutNames = new Vector(); + for (int j = 0; j < operations.length; j++) + { + Operation o = (Operation)operations[j]; + if (o == null || o.isUndefined()) + { + continue; + } + + // check that the messages are defined for the input, output and faults + Message m; + Input input = o.getInput(); + if (input != null) + { + String inputName = input.getName(); + // if the name isn't defined it defaults to this + if (inputName == null) + { + inputName = o.getName() + REQUEST; + } + if (inAndOutNames.contains(inputName)) + { String[] args = {inputName, p.getQName().getLocalPart() }; + valInfo.addError( + messagegenerator.getString( + _INPUT_NAME_NOT_UNIQUE, + QUOTE + args[0] + QUOTE, + QUOTE + args[1] + QUOTE), + input, _INPUT_NAME_NOT_UNIQUE, args); + } + else + { + inAndOutNames.add(inputName); + } + + m = input.getMessage(); + if (m != null && m.isUndefined()) + { + String messName = EMPTY_STRING; + QName messQName = m.getQName(); + if (messQName != null) + { + messName = messQName.getLocalPart(); + } + String[] args = {messName}; + valInfo.addError(messagegenerator.getString(_MESSAGE_UNDEFINED_FOR_INPUT, QUOTE + args[0] + QUOTE), + input, _MESSAGE_UNDEFINED_FOR_INPUT, args); + } + } + Output output = o.getOutput(); + if (output != null) + { + String outputName = output.getName(); + // if the name isn't defined it defaults to this + if (outputName == null) + { + outputName = o.getName() + RESPONSE; + } + + if (inAndOutNames.contains(outputName)) + { + String[] args = {outputName, p.getQName().getLocalPart()}; + + valInfo.addError( + messagegenerator.getString( + _OUTPUT_NAME_NOT_UNIQUE, + QUOTE + args[0] + QUOTE, + QUOTE + args[1] + QUOTE), + output, _OUTPUT_NAME_NOT_UNIQUE, args); + } + else + { + inAndOutNames.add(outputName); + } + + m = output.getMessage(); + if (m != null && m.isUndefined()) + { + String messName = EMPTY_STRING; + QName messQName = m.getQName(); + if (messQName != null) + { + messName = messQName.getLocalPart(); + } + String[] args = {messName}; + valInfo.addError(messagegenerator.getString(_MESSAGE_UNDEFINED_FOR_OUTPUT, QUOTE + args[0] + QUOTE), + output, _MESSAGE_UNDEFINED_FOR_OUTPUT, args); + } + } + + Object faults[] = o.getFaults().values().toArray(); + + //List faultNames = new Vector(); + for (int k = 0; k < faults.length; k++) + { + Fault f = (Fault)faults[k]; + m = f.getMessage(); + if (m != null && m.isUndefined()) + { + String messName = EMPTY_STRING; + QName messQName = m.getQName(); + if (messQName != null) + { + messName = messQName.getLocalPart(); + } + String args[] = {messName}; + valInfo.addError(messagegenerator.getString(_MESSAGE_UNDEFINED_FOR_FAULT, QUOTE + args[0] + QUOTE), + f, _MESSAGE_UNDEFINED_FOR_FAULT, args); + } + } + } + } + } + + /** + * Check that all the messages defined in the WSDL document are valid. + * + * @param wsdlDefinition The WSDL definitions element. + */ + protected void validateMessages(Definition wsdlDefinition, IWSDL11ValidationInfo valInfo) + { + if (wsdlDefinition.getMessages() == null) + return; + Iterator messages = wsdlDefinition.getMessages().values().iterator(); + + while (messages.hasNext()) + { + Message m = (Message)messages.next(); + if (!m.isUndefined()) + { + // if the message has a part (and it doesn't have to) + // ensure each message part has either an element or a type + if (!m.getParts().isEmpty()) + { + Iterator parts = m.getParts().values().iterator(); + while (parts.hasNext()) + { + Part p = (Part)parts.next(); + QName elementName = p.getElementName(); + QName typeName = p.getTypeName(); + Map extAtts = p.getExtensionAttributes(); + // TODO:This will have to be extended as parts can have extensibility elements + //ensure the part has a type or an element defined + if (elementName == null && typeName == null && (extAtts == null || extAtts.isEmpty())) + { String[] args = { p.getName()}; + valInfo.addError(messagegenerator.getString(_PART_NO_ELEMENT_OR_TYPE, QUOTE + args[0] + QUOTE), + p, _PART_NO_ELEMENT_OR_TYPE, args); + } + //here the part has both the element and type defined and it can only have one defined + else if (elementName != null && typeName != null) + { String[] args = {p.getName()}; + valInfo.addError(messagegenerator.getString(_PART_BOTH_ELEMENT_AND_TYPE, QUOTE + args[0] + QUOTE), + p, _PART_BOTH_ELEMENT_AND_TYPE, args); + } + else if (elementName != null) + { + if (!checkPartConstituent(elementName.getNamespaceURI(), + elementName.getLocalPart(), + ELEMENT, + p, + valInfo)) + { String[] args = {p.getName(), elementName.getLocalPart()}; + valInfo.addError( + messagegenerator.getString( + _PART_INVALID_ELEMENT, + QUOTE + args[0] + QUOTE, + QUOTE + args[1] + QUOTE), + p, _PART_INVALID_ELEMENT, args); + } + } + else if (typeName != null) + { + // check that the type itself is defined properly + if (!checkPartConstituent(typeName.getNamespaceURI(), typeName.getLocalPart(), TYPE, p, valInfo)) + { String[] args = {p.getName(), typeName.getLocalPart() }; + valInfo.addError( + messagegenerator.getString( + _PART_INVALID_TYPE, + QUOTE + args[0] + QUOTE, + QUOTE + args[1] + QUOTE), + p, _PART_INVALID_TYPE, args); + } + } + } + } + } + } + } + + /** + * Checks whether the given name is defined in the namespace for the part. A part is an + * ELEMENT or a TYPE. + * + * @param namespace The namespace to check. + * @param name The name to check. + * @param part The part to check, either ELEMENT or TYPE. + * @param partObject The object representing the given part. + * @return True if the part element of type is defined, false otherwise. + */ + protected boolean checkPartConstituent( + String namespace, + String name, + int part, + Part partObject, + IWSDL11ValidationInfo valInfo) + { + + boolean partvalid = false; + // First take care of the situation where it's from the schema namespace. + // The 1999, 2000 and 2001 schema namespaces are all accepted. + if (namespace.equals(Constants.NS_URI_XSD_2001) + || namespace.equals(Constants.NS_URI_XSD_1999) + || namespace.equals(Constants.NS_URI_XSD_2000)) + { + SchemaAttributeTable xsdTable = new SchemaAttributeTable(); + if (xsdTable.containsSymbol(name)) + { + partvalid = true; + } + } + // check inline and imported schema + else + { + XSModel[] schemas = valInfo.getSchemas(); + int numSchemas = schemas.length; + //Iterator schemasIter = schemas.iterator(); + for (int i = 0; i < numSchemas; i++) + { + XSModel schema = schemas[i]; + if (schema != null) + { + if (part == ELEMENT && schema.getElementDeclaration(name, namespace) != null) + { + partvalid = true; + break; + } + else if (part == TYPE && schema.getTypeDefinition(name, namespace) != null) + { + partvalid = true; + break; + } + } + } + } + // If the SOAP encoding namespace hasn't been explicitly imported do so + // now. + // Allow the SOAP encoding namespace to be automatically imported but mark + // it as a warning. + if (!partvalid && namespace.equals(SOAP_ENCODING_URI)) + { + try + { + XSDValidator xsdVal = new XSDValidator(); + String soapEnc = valInfo.getURIResolver().resolve(null, SOAP_ENCODING_URI, null).getPhysicalLocation(); + if(soapEnc != null) + { + xsdVal.validate(soapEnc, null); + // sanity check in case something goes wrong + if (xsdVal.isValid()) + { + XSModel xsModel = xsdVal.getXSModel(); + + if (part == ELEMENT && xsModel.getElementDeclaration(name, namespace) != null) + { + partvalid = true; + } + else if (part == TYPE && xsModel.getTypeDefinition(name, namespace) != null) + { + partvalid = true; + } + valInfo.addWarning(messagegenerator.getString(_WARN_SOAPENC_IMPORTED_PART, QUOTE + name + QUOTE), partObject); + } + } + } + catch (Exception e) + { + //TODO: log the error message + //System.out.println(e); + } + } + return partvalid; + } + +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/WSDL11ValidationInfoImpl.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/WSDL11ValidationInfoImpl.java new file mode 100644 index 000000000..4b30f0953 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/WSDL11ValidationInfoImpl.java @@ -0,0 +1,169 @@ +/******************************************************************************* + * 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.util.Hashtable; +import java.util.List; +import java.util.Vector; + +import org.apache.xerces.xs.XSModel; +import org.eclipse.wst.wsdl.validation.internal.IValidationInfo; +import org.eclipse.wst.wsdl.validation.internal.ValidationInfoImpl; +import org.eclipse.wst.wsdl.validation.internal.resolver.URIResolver; + +/** + * An implemenation of WSDL11ValidationInfo. + */ +public class WSDL11ValidationInfoImpl implements IWSDL11ValidationInfo +{ + private IValidationInfo valinfo = null; + private Hashtable elementlocations = null; + private List schemas = new Vector(); + + public WSDL11ValidationInfoImpl(IValidationInfo valinfo) + { + this.valinfo = valinfo; + } + /** + * @see org.eclipse.wst.wsdl.validation.internal.wsdl11.IWSDL11ValidationInfo#getFileURI() + */ + public String getFileURI() + { + return valinfo.getFileURI(); + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.wsdl11.IWSDL11ValidationInfo#addSchema(org.apache.xerces.xs.XSModel) + */ + public void addSchema(XSModel xsModel) + { + if (xsModel != null) + { + schemas.add(xsModel); + } + + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.wsdl11.IWSDL11ValidationInfo#getSchemas() + */ + public XSModel[] getSchemas() + { + return (XSModel[])schemas.toArray(new XSModel[schemas.size()]); + } + + /* (non-Javadoc) + * @see org.eclipse.wsdl.validate.wsdl11.WSDL11ValidationInfo#cleardSchemas() + */ + public void clearSchemas() + { + schemas.clear(); + } + /** + * @see org.eclipse.wst.wsdl.validation.internal.wsdl11.IWSDL11ValidationInfo#setElementLocations(java.util.Hashtable) + */ + public void setElementLocations(Hashtable elementLocations) + { + this.elementlocations = elementLocations; + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.wsdl11.IWSDL11ValidationInfo#addError(java.lang.String, java.lang.Object) + */ + public void addError(String message, Object element) + { + addError(message, element, null, null); + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.wsdl11.IWSDL11ValidationInfo#addError(java.lang.String, java.lang.Object, java.lang.String, java.lang.Object[]) + */ + public void addError(String message, Object element, String errorKey, Object[] messageArguments) + { + LocationHolder location; + if (elementlocations.containsKey(element)) + { + location = (LocationHolder)elementlocations.get(element); + addError(message, location.getLine(), location.getColumn(), location.getURI(), errorKey, messageArguments); + } + // if we give it an element that hasn't been defined we'll set the location + // at (0,0) so the error shows up but no line marker in the editor + else + { + addError(message, 0, 1, getFileURI()); + } + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.wsdl11.IWSDL11ValidationInfo#addWarning(java.lang.String, java.lang.Object) + */ + public void addWarning(String message, Object element) + { + LocationHolder location; + if (elementlocations.containsKey(element)) + { + location = (LocationHolder)elementlocations.get(element); + addWarning(message, location.getLine(), location.getColumn(), location.getURI()); + } + // if we give it an element that hasn't been defined we'll set the location + // at (0,0) so the error shows up but no line marker in the editor + else + { + addWarning(message, 0, 1, getFileURI()); + } + + } + + /** + * @see org.eclipse.wsdl.validate.wsdl11.WSDL11ValidationInfo#addNamespaceWithNoValidator(java.lang.String) + */ +// public void addNamespaceWithNoValidator(String namespace) +// { +// valinfo.addNamespaceWithNoValidator(namespace); +// +// } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.wsdl11.IWSDL11ValidationInfo#addError(java.lang.String, int, int) + */ + public void addError(String message, int line, int column, String uri) + { + addError(message, line, column, uri, null, null); + } + + public void addError(String message, int line, int column, String uri, String errorKey, Object[] messageArguments) + { + try + { ((ValidationInfoImpl)valinfo).addError(message, line, column, uri, errorKey, messageArguments); + } + catch (ClassCastException e) + { System.err.println(e); + valinfo.addError(message, line, column, uri); + } + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.wsdl11.IWSDL11ValidationInfo#addWarning(java.lang.String, int, int) + */ + public void addWarning(String message, int line, int column, String uri) + { + valinfo.addWarning(message, line, column, uri); + } + + /* (non-Javadoc) + * @see org.eclipse.wsdl.validate.wsdl11.WSDL11ValidationInfo#getURIResolver() + */ + public URIResolver getURIResolver() + { + return valinfo.getURIResolver(); + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/WSDL11ValidatorController.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/WSDL11ValidatorController.java new file mode 100644 index 000000000..aa46e81bb --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/WSDL11ValidatorController.java @@ -0,0 +1,420 @@ +/******************************************************************************* + * 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.util.Iterator; +import java.util.List; +import java.util.ResourceBundle; +import java.util.Vector; + +import javax.wsdl.Definition; +import javax.wsdl.WSDLException; + +import org.apache.xerces.xs.XSModel; +import org.eclipse.wst.wsdl.validation.internal.IWSDLValidator; +import org.eclipse.wst.wsdl.validation.internal.IValidationInfo; +import org.eclipse.wst.wsdl.validation.internal.exception.ValidateWSDLException; +import org.eclipse.wst.wsdl.validation.internal.util.MessageGenerator; +import org.w3c.dom.Document; + +import com.ibm.wsdl.Constants; + +/** + * The validator controller is the head of validation. + */ +public class WSDL11ValidatorController implements IWSDLValidator +{ + protected final String _WARN_NO_VALDIATOR = "_WARN_NO_VALDIATOR"; +// protected final int ERROR_MESSAGE = 0; +// protected final int WARNING_MESSAGE = 1; +// protected String fileURI; +// protected List schemas = new Vector(); +// protected Definition wsdlDefinition; + protected MessageGenerator messagegenerator = null; + //protected ValidationController validationController; + protected ValidatorRegistry ver = ValidatorRegistry.getInstance(); + + /** + * Constructor. + */ + public WSDL11ValidatorController() + { + } + + + /* (non-Javadoc) + * @see org.eclipse.wsdl.validate.IWSDLValidator#validate(org.w3c.dom.Document, org.eclipse.wsdl.validate.ValidationInfo) + */ + public void validate(Document domModel, IValidationInfo valInfo) throws ValidateWSDLException + { + // reset the variables +// reset(); +// fileURI = valInfo.getFileURI(); + //this.validationController = validationcontroller; + + IWSDL11ValidationInfo wsdlvalinfo = new WSDL11ValidationInfoImpl(valInfo); + WSDLDocument[] wsdlDocs = readWSDLDocument(domModel, valInfo.getFileURI(), getMessageGenerator(), wsdlvalinfo); + // Don't validate an null definitions element. Either the file is emtpy and valid or + // had an error when reading. + if(wsdlDocs != null) + { + int numWSDLDocs = wsdlDocs.length; + for(int i = 0; i < numWSDLDocs; i++) + { + WSDLDocument tempDoc = wsdlDocs[i]; + Definition wsdlDefinition = tempDoc.getDefinition(); + // Register the schemas. + List xsdList = tempDoc.getSchemas(); + Iterator xsdIter = xsdList.iterator(); + while (xsdIter.hasNext()) + { + wsdlvalinfo.addSchema((XSModel)xsdIter.next()); + } + // Set the element locations table. + wsdlvalinfo.setElementLocations(tempDoc.getElementLocations()); + // Set any reader errors. This needs to be done after the element locations table is set. + List readerErrors = tempDoc.getReaderErrors(); + if (readerErrors != null) + { + Iterator readerErrorsI = readerErrors.iterator(); + while (readerErrorsI.hasNext()) + { + ReaderError re = (ReaderError)readerErrorsI.next(); + wsdlvalinfo.addError(re.getError(), re.getObject()); + } + } + List readerWarnings = tempDoc.getReaderWarnings(); + if (readerWarnings != null) + { + Iterator readerWarningsI = readerWarnings.iterator(); + while (readerWarningsI.hasNext()) + { + ReaderError re = (ReaderError)readerWarningsI.next(); + wsdlvalinfo.addWarning(re.getError(), re.getObject()); + } + } + validateWSDLElement(Constants.NS_URI_WSDL, wsdlDefinition, new Vector(), wsdlvalinfo); + wsdlvalinfo.clearSchemas(); + } + } + + } + + /** + * Validate an imported WSDL document. Allows the calling class to have access to the internal + * components of the validation. + * + * @param wsdlvalinfo The WSDL 1.1 validation info object to use. + * @return The definitions element for the import. + * @throws ValidateWSDLException + */ +// protected Definition validateImport(WSDL11ValidationInfo wsdlvalinfo) +// { +// WSDLDocument[] wsdlDocs = null; +// try +// { +// wsdlDocs = readWSDLDocument(null, wsdlvalinfo.getFileURI(), getMessageGenerator(), wsdlvalinfo); +// } +// catch(ValidateWSDLException e) +// { +// // supress any validation issues with imported documents +// } +// // Don't validate an null definitions element. Either the file is emtpy and valid or +// // had an error when reading. +// if(wsdlDocs != null) +// { +// validateWSDLElement(Constants.NS_URI_WSDL, wsdlDefinition, new Vector(), wsdlvalinfo); +// } +// return wsdlDefinition; +// } + + /** + * Read in the WSDL document and set the model and imported schemas. + * + * @param domModel A DOM model of the document to be read. + * @param file The file to read. + * @param messagegenerator The messagegenerator the reader should use for any messages produced. + * @param wsdlvalinfo The validation information for the current validation. + * @return The definitions element for the WSDL document. + * @throws ValidateWSDLException + */ + protected WSDLDocument[] readWSDLDocument(Document domModel, String file, MessageGenerator messagegenerator, IWSDL11ValidationInfo wsdlvalinfo) throws ValidateWSDLException + { + WSDLDocument[] wsdlDocs = null; + try + { + + WSDLReaderImpl wsdlReader = new WSDLReaderImpl(wsdlvalinfo); + wsdlReader.setMessageGenerator(messagegenerator); + if(domModel != null) + { + wsdlDocs = wsdlReader.readWSDL(file, domModel); + } + else + { + wsdlDocs = wsdlReader.readWSDL(file); + } + //wsdlvalinfo.setElementLocations(wsdlReader.getElementLocationsHashtable()); +// List readerErrors = wsdlReader.getReaderErrors(); +// if (readerErrors != null) +// { +// Iterator readerErrorsI = readerErrors.iterator(); +// while (readerErrorsI.hasNext()) +// { +// ReaderError re = (ReaderError)readerErrorsI.next(); +// wsdlvalinfo.addError(re.getError(), re.getObject()); +// } +// } +// if (wsdlReader.hasImportSchemas()) +// { +// List xsdList = wsdlReader.getImportSchemas(); +// Iterator xsdIter = xsdList.iterator(); +// while (xsdIter.hasNext()) +// { +// wsdlvalinfo.addSchema((XSModel)xsdIter.next()); +// } +// +// } + + } + catch (WSDLException e) + { + throw new ValidateWSDLException(e.getMessage() + " " + e.getFaultCode()); + } + + catch (Exception e) + { + throw new ValidateWSDLException("unable to read file" + e.getMessage() + " " + e.toString()); + } + return wsdlDocs; + } + + /** + * Given a WSDL element, call ValidateElement for it. + * + * @param namespace The namespace of the element to validate. + * @param element The element to validate. + * @param parents The list of parents for this element. + */ + public void validateWSDLElement(String namespace, Object element, List parents, IWSDL11ValidationInfo wsdlvalinfo) + { + IWSDL11Validator val = ver.queryValidatorRegistry(namespace); + if (val != null) + { + val.validate(element, parents, wsdlvalinfo); + } + else + { + //TODO: Add this as a preference. + //wsdlvalinfo.addWarning(messagegenerator.getString(_WARN_NO_VALDIATOR, namespace), element); + } + } + + /** + * Add a schema to the list of schemas. + * + * @param xsModel The schema to add. + */ +// public void addSchema(XSModel xsModel) +// { +// if (xsModel != null) +// { +// schemas.add(xsModel); +// } +// } + + /** + * Return the list containing the schemas. + * + * @return The list of schemas. + */ +// public List getSchemas() +// { +// return schemas; +// } + + /** + * Get the ResourceBundle for this ValidatorManager. + * + * @return The resource bundle registered for this controller. + * @see #setResourceBundle + */ +// public ResourceBundle getResourceBundle() +// { +// return resourcebundle; +// } + + /** + * Set the ResourceBundle for this ValidatorManager. + * + * @param rb The resource bundle to set. + * @see #getResourceBundle + */ + public void setResourceBundle(ResourceBundle rb) + { + if (messagegenerator == null) + { + messagegenerator = new MessageGenerator(rb); + } + + } + + /** + * Set the message generator for this controller. + * + * @param mesgen The message generator to set for this controller. + */ + public void setMessageGenerator(MessageGenerator mesgen) + { + messagegenerator = mesgen; + } + + /** + * Get the message generator registered for this controller. + * + * @return The message generator registered for this controller. + */ + public MessageGenerator getMessageGenerator() + { + return messagegenerator; + } + + /** + * Return the filename for the file currently being validated. Some validators require this. + * + * @return The filename for the file being validated. + */ +// public String getFilename() +// { +// return fileURI; +// } + + /** + * Convenience method for extensibly validators to add error messages. + * + * @param object The object to add the error for. + * @param error The error to add. + */ +// public void addErrorMessage(Object object, String error) +// { +// addValidationMessage(ERROR_MESSAGE, object, error); +// errors = true; +// } + + /** + * Method for extensibly validators to add error messages when they know + * line and column numbers. + * + * @param line The line where the error message is located. + * @param column The column where the error message is located. + * @param error The error message. + */ +// public void addErrorMessage(int line, int column, String error) +// { +// addValidationMessage(ERROR_MESSAGE, line, column, error); +// errors = true; +// } + + /** + * Convenience method for extensibly validators to add warning messages. + * + * @param object The object to add the warning message. + * @param warning The warning message. + */ +// public void addWarningMessage(Object object, String warning) +// { +// addValidationMessage(WARNING_MESSAGE, object, warning); +// } + + /** + * Method for extensibly validators to add warning messages when they know + * line and column numbers. + * + * @param line The line where the error message is located. + * @param column The column where the error message is located. + * @param warning The warning message. + */ +// public void addWarningMessage(int line, int column, String warning) +// { +// addValidationMessage(WARNING_MESSAGE, line, column, warning); +// } + + /** + * If you have an object read in by the reader for this + * validatorcontroller the object can be passed in here and the line and column + * information will be abstracted from it. + * + * @param type The type of message to add. + * @param o The object that has the error (used to get the location). + * @param message The message to add. + */ +// protected void addValidationMessage(int type, Object o, String message) +// { +// int[] location; +// if (elementLocations.containsKey(o)) +// { +// location = (int[])elementLocations.get(o); +// } +// // if we give it an element that hasn't been defined we'll set the location +// // at (0,0) so the error shows up but no line marker in the editor +// else +// { +// location = new int[] { 0, 0 }; +// } +// addValidationMessage(type, location[0], location[1], message); +// } + + /** + * Creates a validation message of the specified type. + * + * @param type The type of validation message to add. + * @param line The line where the error message is located. + * @param column The line where the column message is located. + * @param message The message to add. + */ +// protected void addValidationMessage(int type, int line, int column, String message) +// { +// if (message != null) +// { +// if (type == ERROR_MESSAGE) +// { +// validationController.addErrorMessage(line, column, message); +// } +// else if (type == WARNING_MESSAGE) +// { +// validationController.addWarningMessage(line, column, message); +// } +// } +// } + + /** + * @see org.eclipse.wsdl.validate.controller.IWSDLValidator#isValid() + */ +// public boolean isValid() +// { +// return !errors; +// } + + /** + * Reset the validator controller. + */ +// protected void reset() +// { +// schemas = new Vector(); +// fileURI = ""; +// wsdlDefinition = null; +// elementLocations = null; +// resourcebundle = null; +// //validationController = null; +// errors = false; +// } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/WSDL11ValidatorDelegate.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/WSDL11ValidatorDelegate.java new file mode 100644 index 000000000..e627a7812 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/WSDL11ValidatorDelegate.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * 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.util.Locale; +import java.util.ResourceBundle; + + +/** + * The WSDL 1.1 validator delegate holds a reference to a validator to be instantiated at + * a later point. + */ +public class WSDL11ValidatorDelegate +{ + private String validatorClassname = null; + private String resourceBundle = null; + private ClassLoader classLoader = null; + private IWSDL11Validator validator = null; + + /** + * Create a delegate for a validator by its class name and resource bundle name. + * + * @param validatorClassname The name of the validator class. + * @param resourceBundle The name of the validator base resource bundle. + */ + public WSDL11ValidatorDelegate(String validatorClassname, String resourceBundle) + { + this.validatorClassname = validatorClassname; + this.resourceBundle = resourceBundle; + } + + /** + * Create a delegate for a validator by its class name, resource bundle name and + * a class loader to load the validator and bundle. + * + * @param validatorClassname The name of the validator class. + * @param resourceBundle The name of the validator base resource bundle. + * @param classLoader The class loader to use to load the validator and bundle. + */ + public WSDL11ValidatorDelegate(String validatorClassname, String resourceBundle, ClassLoader classLoader) + { + this(validatorClassname, resourceBundle); + this.classLoader = classLoader; + } + + /** + * Get the validator specified in this delegate. + * + * @return The WSDL 1.1 validator specified by this delegate. + */ + public IWSDL11Validator getValidator() + { + if (validator == null) + { + if(classLoader == null) + { + classLoader = getClass().getClassLoader(); + } + try + { + Class validatorClass = + classLoader != null ? classLoader.loadClass(validatorClassname) : Class.forName(validatorClassname); + + validator = (IWSDL11Validator)validatorClass.newInstance(); + if (resourceBundle != null) + { + ResourceBundle validatorBundle = ResourceBundle.getBundle(resourceBundle, Locale.getDefault(), classLoader); + validator.setResourceBundle(validatorBundle); + } + } + catch (ClassNotFoundException e) + { + // TODO: add logging + System.err.println(e); + } + catch (IllegalAccessException e) + { + // TODO: add logging + System.err.println(e); + } + catch (InstantiationException e) + { + // TODO: add logging + System.err.println(e); + } + } + return validator; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/WSDLDocument.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/WSDLDocument.java new file mode 100644 index 000000000..ebb113182 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/WSDLDocument.java @@ -0,0 +1,2000 @@ +/******************************************************************************* + * 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.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.Vector; + +import javax.wsdl.Binding; +import javax.wsdl.BindingFault; +import javax.wsdl.BindingInput; +import javax.wsdl.BindingOperation; +import javax.wsdl.BindingOutput; +import javax.wsdl.Definition; +import javax.wsdl.Fault; +import javax.wsdl.Input; +import javax.wsdl.Message; +import javax.wsdl.Operation; +import javax.wsdl.OperationType; +import javax.wsdl.Output; +import javax.wsdl.Part; +import javax.wsdl.Port; +import javax.wsdl.PortType; +import javax.wsdl.Service; +import javax.wsdl.Types; +import javax.wsdl.WSDLException; +import javax.wsdl.extensions.ExtensibilityElement; +import javax.wsdl.extensions.ExtensionDeserializer; +import javax.wsdl.extensions.ExtensionRegistry; +import javax.wsdl.extensions.UnknownExtensibilityElement; +import javax.wsdl.factory.WSDLFactory; +import javax.xml.namespace.QName; + +import org.apache.xerces.dom.ElementImpl; +import org.apache.xerces.dom.ElementNSImpl; +import org.apache.xerces.xs.XSModel; +import org.eclipse.wst.wsdl.validation.internal.util.MessageGenerator; +import org.eclipse.wst.wsdl.validation.internal.wsdl11.xsd.InlineSchemaValidator; +import org.eclipse.wst.wsdl.validation.internal.xml.ElementLocation; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +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; +import com.ibm.wsdl.util.xml.XPathUtils; + +/** + * A WSDL document that knows how to parse itself. + */ +public class WSDLDocument +{ + 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 }); + + private static final String _ERROR_MULTIPLE_TYPES_DEFINED = "_ERROR_MULTIPLE_TYPES_DEFINED"; + private static final String _UNABLE_TO_IMPORT_NO_LOCATION = "_UNABLE_TO_IMPORT_NO_LOCATION"; + + protected ExtensionRegistry extReg = null; + protected String factoryImplName = null; + + // store the element locations within the file - line and column numbers + // the location info is stored as an int array of length 2 {linenumber, colnumber} + protected Hashtable elementLocations = new Hashtable(); + + // hold the reader errors + protected List readerErrors = new ArrayList(); + protected List readerWarnings = new ArrayList(); + protected MessageGenerator messagegenerator; + + private Definition def = null; + private Set importedDefs = new TreeSet(); + private Element typesEl = null; + private List messages = new ArrayList(); + private List porttypes = new ArrayList(); + private List bindings = new ArrayList(); + private List services = new ArrayList(); + private List extelements = new ArrayList(); + private int depth; + // Hold the schemas that are imported or declared inline in this wsdl document. + private List schemas = new ArrayList(); + private IWSDL11ValidationInfo valinfo; + + /** + * Constructor. Performs a preparse of the document and handles imports and types. + * + * @param documentBaseURI The URI of this WSDL document. + * @param defEl The definitions element. + * @param depth The depth of this document in a document tree. + * @param messagegenerator A messagegenerator used for retrieving strings. + * @param valinfo A WSDL11ValidationInfo object for reporting messages. + * @throws WSDLException + */ + public WSDLDocument(String documentBaseURI, Element defEl, int depth, MessageGenerator messagegenerator, IWSDL11ValidationInfo valinfo) throws WSDLException + { + this.messagegenerator = messagegenerator; + this.valinfo = valinfo; + this.depth = depth; + + checkElementName(defEl, Constants.Q_ELEM_DEFINITIONS); + + WSDLFactory factory = + (factoryImplName != null) ? WSDLFactory.newInstance(factoryImplName) : WSDLFactory.newInstance(); + def = factory.newDefinition(); + + if (extReg != null) + { + def.setExtensionRegistry(extReg); + } + + String name = DOMUtils.getAttribute(defEl, Constants.ATTR_NAME); + String targetNamespace = DOMUtils.getAttribute(defEl, Constants.ATTR_TARGET_NAMESPACE); + 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)) + { + def.addNamespace(localPart, value); + } + else + { + def.addNamespace(null, value); + } + } + } + + // There are problems when the model is created and the order of elements is not + // Import - Types - Message - PortType - Binding - Service so we need to read them + // into the model in that order + // Performance wise this should be modified as we have to make 5 extra loops through + // all of the elements as a result + + // take care of Imports, Types, Documentation and extensibleelements together - saves a pass for Documentation + // later and Docs don't effect anything else - Imports and Types are essentially the same thing + // no preconceived ideas about extensible elements + Element tempEl = DOMUtils.getFirstChildElement(defEl); + + while (tempEl != null) + { + + if (QNameUtils.matches(Constants.Q_ELEM_IMPORT, tempEl)) + { + String namespaceURI = DOMUtils.getAttribute(tempEl, Constants.ATTR_NAMESPACE); + String locationURI = DOMUtils.getAttribute(tempEl, Constants.ATTR_LOCATION); + if(locationURI == null || locationURI.equals("")) + { + addReaderError(def, tempEl, messagegenerator.getString(_UNABLE_TO_IMPORT_NO_LOCATION)); + } + else + { + ImportHolder ih = new ImportHolder(namespaceURI, locationURI, def.getDocumentBaseURI(), this, depth+1, tempEl, messagegenerator, valinfo); + importedDefs.add(ih); + } + setLocation(tempEl, tempEl); +// if (importedDefs == null) +// { +// importedDefs = new Hashtable(); +// } +// if (documentBaseURI != null) +// { +// importedDefs.put(documentBaseURI, def); +// } +// def.addImport(parseImport(tempEl, def, importedDefs)); + } + else if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl)) + { + def.setDocumentationElement(tempEl); + } + else if (QNameUtils.matches(Constants.Q_ELEM_TYPES, tempEl)) + { + if(typesEl != null) + { + setLocation(tempEl, tempEl); + addReaderError(def, tempEl, messagegenerator.getString(_ERROR_MULTIPLE_TYPES_DEFINED)); + } + else + { + typesEl = tempEl; + parseTypes(); + } +// def.setTypes(parseTypes(tempEl, def)); + } + else if (QNameUtils.matches(Constants.Q_ELEM_MESSAGE, tempEl)) + { + messages.add(tempEl); + //def.addMessage(parseMessage(tempEl, def)); + } + else if (QNameUtils.matches(Constants.Q_ELEM_PORT_TYPE, tempEl)) + { + porttypes.add(tempEl); + // PortType pt = parsePortType(tempEl, def); + // if(pt != null) + // { + // def.addPortType(pt); + // } + } + else if (QNameUtils.matches(Constants.Q_ELEM_BINDING, tempEl)) + { + bindings.add(tempEl); + //def.addBinding(parseBinding(tempEl, def)); + } + else if (QNameUtils.matches(Constants.Q_ELEM_SERVICE, tempEl)) + { + services.add(tempEl); + //def.addService(parseService(tempEl, def)); + } + else + { + extelements.add(tempEl); + // def.addExtensibilityElement( + // parseExtensibilityElement(Definition.class, tempEl, def)); + } + tempEl = DOMUtils.getNextSiblingElement(tempEl); + } + + } + + /** + * Get the definitions element for this document. + * + * @return The definitions element for this document. + */ + public Definition getDefinition() + { + return def; + } + + /** + * Get a set of the imports in this document. + * + * @return A set of the imports in this document. + */ + public Set getImports() + { + return importedDefs; + } + + /** + * + * @param def + * @param doc + * @param namespace + * @param location + */ +// public void setImport(Definition def, Element doc, String namespace, String location) +// { +// if(location == null || location.equals("")) +// { +// valinfo.addError()_UNABLE_TO_IMPORT_NO_LOCATION +// } +// Import imp = def.createImport(); +// imp.setDefinition(def); +// imp.setDocumentationElement(doc); +// imp.setNamespaceURI(namespace); +// imp.setLocationURI(location); +// def.addImport(imp); +// } + + /** + * Parse the types in the WSDL document. Handles documentation, import and schema + * elements. + */ + public void parseTypes() + { + Types types = def.createTypes(); + + Element tempEl = DOMUtils.getFirstChildElement(typesEl); + + while (tempEl != null) + { + if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl)) + { + types.setDocumentationElement(tempEl); + } + else if (tempEl.getLocalName().equalsIgnoreCase("import")) + //else if (QNameUtils.matches(Constants.Q_ELEM_IMPORT, tempEl)) + { + // this shouldn't really be used here but a little hack will make + // life easier + //parseImport(tempEl, def, (Map)new Hashtable()); + String namespaceURI = DOMUtils.getAttribute(tempEl, Constants.ATTR_NAMESPACE); + String locationURI = DOMUtils.getAttribute(tempEl, "schemaLocation"); + importedDefs.add(new ImportHolder(namespaceURI, locationURI, def.getDocumentBaseURI(), this, depth+1, tempEl, messagegenerator, valinfo)); + try + { + types.addExtensibilityElement(parseExtensibilityElement(Types.class, tempEl, def)); + } + catch(WSDLException e) + { + + } + } + else + { + try + { + ExtensibilityElement extElem = parseExtensibilityElement(Types.class, tempEl, def); + types.addExtensibilityElement(extElem); + } + catch(WSDLException e) + { + + } + } + + tempEl = DOMUtils.getNextSiblingElement(tempEl); + } + def.setTypes(types); + + valinfo.setElementLocations(elementLocations); + List typesElems = types.getExtensibilityElements(); + if(typesElems != null) + { + Iterator typesElemsIter = typesElems.iterator(); + while(typesElemsIter.hasNext()) + { + ExtensibilityElement typeElement = (ExtensibilityElement)typesElemsIter.next(); + + InlineSchemaValidator xsdVal = new InlineSchemaValidator(); + xsdVal.setMessageGenerator(messagegenerator); + + List parents = new ArrayList(); + parents.add(def); + parents.add(0,types); + xsdVal.validate(typeElement, parents,valinfo); + XSModel[] typesSchemas = valinfo.getSchemas(); + List typesSchemaList = new ArrayList(); + for(int i = 0; i < typesSchemas.length; i++) + { + typesSchemaList.add(typesSchemas[i]); + } + schemas.addAll(typesSchemaList); + valinfo.clearSchemas(); + } + } + valinfo.setElementLocations(null); + } + + /** + * Parse the messages in this document. + */ + public void parseMessages() + { + for (int i = 0; i < messages.size(); i++) + { + try + { + def.addMessage(parseMessage((Element)messages.get(i), def)); + } + catch(WSDLException e) + {} + } + } + + /** + * Parse the portTypes in this document. + */ + public void parsePorttypes() + { + for (int i = 0; i < porttypes.size(); i++) + { + try + { + PortType pt = parsePortType((Element)porttypes.get(i), def); + if (pt != null) + { + def.addPortType(pt); + } + } + catch(WSDLException e) + {} + } + } + + /** + * Parse the bindings in this document. + */ + public void parseBindings() + { + for (int i = 0; i < bindings.size(); i++) + { + try + { + def.addBinding(parseBinding((Element)bindings.get(i), def)); + } + catch(WSDLException e) + {} + } + } + + /** + * Parse the services in this document. + */ + public void parseServices() + { + for (int i = 0; i < services.size(); i++) + { + try + { + def.addService(parseService((Element)services.get(i), def)); + } + catch(WSDLException e) + {} + } + } + + /** + * Parse the extensibility elements in this document. + */ + public void parseExtensibilityElements() + { + for (int i = 0; i < extelements.size(); i++) + { + try + { + def.addExtensibilityElement(parseExtensibilityElement(Definition.class, (Element)extelements.get(i), def)); + } + catch(WSDLException e) + {} + } + } + + /** + * Add the given list of schemas to the schemas for this document. + * + * @param schemas The list of schemas to add to this document's schemas. + */ + public void addSchemas(List schemas) + { + this.schemas.addAll(schemas); + } + + /** + * Get the schemas associated with this document. + * + * @return The schemas associated with this document. + */ + public List getSchemas() + { + return schemas; + } + + /** + * Parse the specified binding. + * + * @param bindingEl The binding element. + * @param def The definitions element. + * @return A WSDL binding element. + * @throws WSDLException + */ + protected Binding parseBinding(Element bindingEl, Definition def) throws WSDLException + { + Binding binding = null; + String name = DOMUtils.getAttribute(bindingEl, Constants.ATTR_NAME); + QName portTypeName; + try + { + portTypeName = DOMUtils.getQualifiedAttributeValue(bindingEl, Constants.ATTR_TYPE, Constants.ELEM_BINDING, false); + } + catch (Exception e) + { + //the call above fails if there is no qualified namespace for the message name + portTypeName = new QName(null, DOMUtils.getAttribute(bindingEl, "type")); + } + + PortType portType = null; + + if (name != null) + { + QName bindingName = new QName(def.getTargetNamespace(), name); + + binding = def.getBinding(bindingName); + + if (binding == null) + { + binding = def.createBinding(); + binding.setQName(bindingName); + } + // report an error if a binding with this name has already been defined + else if (!binding.isUndefined()) + { + //addReaderError(def,bindingEl, "_BINDING_NAME_ALREADY_DEFINED"); + addReaderError( + def, + bindingEl, + messagegenerator.getString("_BINDING_NAME_ALREADY_DEFINED", "'" + binding.getQName().getLocalPart() + "'")); + } + } + else + { + binding = def.createBinding(); + } + + // Whether it was retrieved or created, the definition has been found. + binding.setUndefined(false); + + if (portTypeName != null) + { + portType = def.getPortType(portTypeName); + + if (portType == null) + { + portType = def.createPortType(); + portType.setQName(portTypeName); + def.addPortType(portType); + } + + binding.setPortType(portType); + } + + Element tempEl = DOMUtils.getFirstChildElement(bindingEl); + + while (tempEl != null) + { + if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl)) + { + binding.setDocumentationElement(tempEl); + } + else if (QNameUtils.matches(Constants.Q_ELEM_OPERATION, tempEl)) + { + binding.addBindingOperation(parseBindingOperation(tempEl, portType, def)); + } + else + { + binding.addExtensibilityElement(parseExtensibilityElement(Binding.class, tempEl, def)); + } + + tempEl = DOMUtils.getNextSiblingElement(tempEl); + } + + // add the location of this element to elementLocations + setLocation(binding, bindingEl); + + return binding; + } + + /** + * Parse a specific binding operation. + * + * @param bindingOperationEl The binding operation element. + * @param portType The portType the binding references. + * @param def The definitions element. + * @return A WSDL binding operation element. + * @throws WSDLException + */ + protected BindingOperation parseBindingOperation(Element bindingOperationEl, PortType portType, Definition def) + throws WSDLException + { + BindingOperation bindingOperation = def.createBindingOperation(); + String name = DOMUtils.getAttribute(bindingOperationEl, Constants.ATTR_NAME); + + if (name != null) + { + bindingOperation.setName(name); + } + + Element tempEl = DOMUtils.getFirstChildElement(bindingOperationEl); + + while (tempEl != null) + { + if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl)) + { + bindingOperation.setDocumentationElement(tempEl); + } + else if (QNameUtils.matches(Constants.Q_ELEM_INPUT, tempEl)) + { + bindingOperation.setBindingInput(parseBindingInput(tempEl, def)); + } + else if (QNameUtils.matches(Constants.Q_ELEM_OUTPUT, tempEl)) + { + bindingOperation.setBindingOutput(parseBindingOutput(tempEl, def)); + } + else if (QNameUtils.matches(Constants.Q_ELEM_FAULT, tempEl)) + { + bindingOperation.addBindingFault(parseBindingFault(tempEl, def)); + } + else + { + bindingOperation.addExtensibilityElement(parseExtensibilityElement(BindingOperation.class, tempEl, def)); + } + + tempEl = DOMUtils.getNextSiblingElement(tempEl); + } + + if (portType != null) + { + BindingInput bindingInput = bindingOperation.getBindingInput(); + BindingOutput bindingOutput = bindingOperation.getBindingOutput(); + String inputName = (bindingInput != null ? bindingInput.getName() : null); + String outputName = (bindingOutput != null ? bindingOutput.getName() : null); + + // hack code to get at operations that are defined with the same name but different + // inputs and outputs + Operation op = null; + List operations = portType.getOperations(); + // get a list of all operations with matching names + List matchingOperations = new Vector(); + Iterator iOperations = operations.iterator(); + while (iOperations.hasNext()) + { + Operation oper = (Operation)iOperations.next(); + if (oper.getName().equalsIgnoreCase(bindingOperation.getName())) + { + matchingOperations.add(oper); + } + } + + if (matchingOperations != null) + { + // If there's only one matching operation this is what we're referring to. + // Only matching if binding operation input name and output name are + // both null or the same as the portType operation input and output names. + // the portType operation name + if (matchingOperations.size() == 1) + { + // only say the single operation is the one we're looking for if the names + // of the binding input and output are not specified + Operation tempOp = (Operation)matchingOperations.get(0); + boolean inputOK = false; + boolean outputOK = false; + Input tempInput = tempOp.getInput(); + Output tempOutput = tempOp.getOutput(); + + // order is important in these conditions. condition 2 must fail for 3 to work + // check the input + if (tempInput == null && bindingInput == null) + { + inputOK = true; + } + else if (bindingInput == null || bindingInput.getName() == null) + { + inputOK = true; + } + else if (tempInput != null && bindingInput.getName().equals(tempInput.getName())) + { + inputOK = true; + } + // check the output + if (tempOutput == null && bindingOutput == null) + { + outputOK = true; + } + else if (bindingOutput == null || bindingOutput.getName() == null) + { + outputOK = true; + } + else if (tempOutput != null && bindingOutput.getName().equals(tempOutput.getName())) + { + outputOK = true; + } + if (inputOK && outputOK) + { + op = tempOp; + } + // op = (Operation) matchingOperations.get(0); + } + // otherwise find the operation with the same name, inputname, outputname signature + if (matchingOperations != null && op == null) + { + Iterator iMatchingOperations = matchingOperations.iterator(); + while (iMatchingOperations.hasNext()) + { + + boolean inputNamesEqual = false; + boolean outputNamesEqual = false; + Operation oper = (Operation)iMatchingOperations.next(); + // if (oper.getName().equalsIgnoreCase(bindingOperation.getName())) + // { + Input opInput = oper.getInput(); + if (opInput != null && bindingInput != null) + { + String opInputName = opInput.getName(); + String bindingInputName = bindingInput.getName(); + if (opInputName != null && opInputName.equalsIgnoreCase(bindingInputName)) + { + inputNamesEqual = true; + } + else if (opInputName == null && bindingInputName == null) + { + inputNamesEqual = true; + } + } + else if (opInput == null && bindingInput == null) + { + inputNamesEqual = true; + } + Output opOutput = oper.getOutput(); + if (opOutput != null && bindingOutput != null) + { + String opOutputName = opOutput.getName(); + String bindingOutputName = bindingOutput.getName(); + if (opOutputName != null && opOutputName.equalsIgnoreCase(bindingOutputName)) + { + outputNamesEqual = true; + } + else if (opOutputName == null && bindingOutputName == null) + { + outputNamesEqual = true; + } + } + else if (opOutput == null && bindingOutput == null) + { + outputNamesEqual = true; + } + if (inputNamesEqual && outputNamesEqual) + { + op = oper; + break; + } + //} + } + } + } + //Operation op = portType.getOperation(name, inputName, outputName); + + if (op == null) + { + op = def.createOperation(); + op.setName(name); + portType.addOperation(op); + } + + bindingOperation.setOperation(op); + } + + // add the location of this element to elementLocations + setLocation(bindingOperation, bindingOperationEl); + + return bindingOperation; + } + + /** + * Parse a specific binding input element. + * + * @param bindingInputEl The binding input element. + * @param def The definitions element. + * @return A WSDL binding input element. + * @throws WSDLException + */ + protected BindingInput parseBindingInput(Element bindingInputEl, Definition def) throws WSDLException + { + BindingInput bindingInput = def.createBindingInput(); + String name = DOMUtils.getAttribute(bindingInputEl, Constants.ATTR_NAME); + + if (name != null) + { + bindingInput.setName(name); + } + + Element tempEl = DOMUtils.getFirstChildElement(bindingInputEl); + + while (tempEl != null) + { + if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl)) + { + bindingInput.setDocumentationElement(tempEl); + } + else + { + bindingInput.addExtensibilityElement(parseExtensibilityElement(BindingInput.class, tempEl, def)); + } + + tempEl = DOMUtils.getNextSiblingElement(tempEl); + } + + // add the location of this element to elementLocations + setLocation(bindingInput, bindingInputEl); + + return bindingInput; + } + + /** + * Parse a specific binding output element. + * + * @param bindingOutputEl The binding output element. + * @param def The definitions element. + * @return A WSDL binding output element. + * @throws WSDLException + */ + protected BindingOutput parseBindingOutput(Element bindingOutputEl, Definition def) throws WSDLException + { + BindingOutput bindingOutput = def.createBindingOutput(); + String name = DOMUtils.getAttribute(bindingOutputEl, Constants.ATTR_NAME); + + if (name != null) + { + bindingOutput.setName(name); + } + + Element tempEl = DOMUtils.getFirstChildElement(bindingOutputEl); + + while (tempEl != null) + { + if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl)) + { + bindingOutput.setDocumentationElement(tempEl); + } + else + { + bindingOutput.addExtensibilityElement(parseExtensibilityElement(BindingOutput.class, tempEl, def)); + } + + tempEl = DOMUtils.getNextSiblingElement(tempEl); + } + + // add the location of this element to elementLocations + setLocation(bindingOutput, bindingOutputEl); + + return bindingOutput; + } + + /** + * Parse a specific binding fault element. + * + * @param bindingFaultEl The binding fault element. + * @param def The definitions element. + * @return A WSDL binding fault element. + * @throws WSDLException + */ + protected BindingFault parseBindingFault(Element bindingFaultEl, Definition def) throws WSDLException + { + BindingFault bindingFault = def.createBindingFault(); + String name = DOMUtils.getAttribute(bindingFaultEl, Constants.ATTR_NAME); + + if (name != null) + { + bindingFault.setName(name); + } + + Element tempEl = DOMUtils.getFirstChildElement(bindingFaultEl); + + while (tempEl != null) + { + if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl)) + { + bindingFault.setDocumentationElement(tempEl); + } + else + { + bindingFault.addExtensibilityElement(parseExtensibilityElement(BindingFault.class, tempEl, def)); + } + + tempEl = DOMUtils.getNextSiblingElement(tempEl); + } + + // add the location of this element to elementLocations + setLocation(bindingFault, bindingFaultEl); + + return bindingFault; + } + + /** + * Parse a specific message element. + * + * @param msgEl The message element. + * @param def The definitions element. + * @return A WSDL message element. + * @throws WSDLException + */ + protected Message parseMessage(Element msgEl, Definition def) throws WSDLException + { + Message msg = null; + String name = DOMUtils.getAttribute(msgEl, Constants.ATTR_NAME); + + if (name != null) + { + QName messageName = new QName(def.getTargetNamespace(), name); + + msg = def.getMessage(messageName); + + if (msg == null) + { + msg = def.createMessage(); + msg.setQName(messageName); + } + else if (!msg.isUndefined()) + { + // produce an error message as a message with this name has already been defined + addReaderError( + def, + msgEl, + messagegenerator.getString("_MESSAGE_NAME_ALREADY_DEFINED", "'" + msg.getQName().getLocalPart() + "'")); + } + } + else + { + msg = def.createMessage(); + } + + // Whether it was retrieved or created, the definition has been found. + msg.setUndefined(false); + + Element tempEl = DOMUtils.getFirstChildElement(msgEl); + + while (tempEl != null) + { + if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl)) + { + msg.setDocumentationElement(tempEl); + } + else if (QNameUtils.matches(Constants.Q_ELEM_PART, tempEl)) + { + msg.addPart(parsePart(tempEl, def)); + } + else + { + // XML Validation will catch this + DOMUtils.throwWSDLException(tempEl); + } + + tempEl = DOMUtils.getNextSiblingElement(tempEl); + } + + // add the location of this element to elementLocations + setLocation(msg, msgEl); + + return msg; + } + + /** + * Parse a specific part element. + * + * @param partEl The part element. + * @param def The definitions element. + * @return A WSDL part element. + * @throws WSDLException + */ + protected Part parsePart(Element partEl, Definition def) throws WSDLException + { + Part part = def.createPart(); + String name = DOMUtils.getAttribute(partEl, Constants.ATTR_NAME); + + QName elementName; + try + { + elementName = DOMUtils.getQualifiedAttributeValue(partEl, Constants.ATTR_ELEMENT, Constants.ELEM_MESSAGE, false); + } + catch (Exception e) + { + //the call above fails if there is no qualified namespace for the element name + elementName = new QName(null, DOMUtils.getAttribute(partEl, "element")); + } + + QName typeName; + try + { + typeName = DOMUtils.getQualifiedAttributeValue(partEl, Constants.ATTR_TYPE, + // Corrected - was ATTR_ELEMENT + Constants.ELEM_MESSAGE, false); + } + catch (Exception e) + { + //the call above fails if there is no qualified namespace for the element attribute + typeName = new QName(null, DOMUtils.getAttribute(partEl, "name")); + } + + if (name != null) + { + part.setName(name); + } + + if (elementName != null) + { + part.setElementName(elementName); + } + + if (typeName != null) + { + part.setTypeName(typeName); + } + + Element tempEl = DOMUtils.getFirstChildElement(partEl); + + while (tempEl != null) + { + if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl)) + { + part.setDocumentationElement(tempEl); + } + else + { + // XML Validation will catch this + DOMUtils.throwWSDLException(tempEl); + } + + tempEl = DOMUtils.getNextSiblingElement(tempEl); + } + + Map extensionAttributes = part.getExtensionAttributes(); + + extensionAttributes.putAll(getPartAttributes(partEl, def)); + + // Need to do something here to locate part definition. + + // add the location of this element to elementLocations + setLocation(part, partEl); + + return part; + } + + /** + * Get a map of the part attributes. + * + * @param el The part attributes element. + * @param def The defintions element. + * @return A map containing the part attributes. + * @throws WSDLException + */ + protected Map getPartAttributes(Element el, Definition def) throws WSDLException + { + Map attributes = new HashMap(); + NamedNodeMap nodeMap = el.getAttributes(); + int atts = nodeMap.getLength(); + + for (int a = 0; a < atts; a++) + { + Attr attribute = (Attr)nodeMap.item(a); + String lName = attribute.getLocalName(); + String nSpace = attribute.getNamespaceURI(); + String prefix = attribute.getPrefix(); + QName name = new QName(nSpace, lName); + + if (nSpace != null && !nSpace.equals(Constants.NS_URI_WSDL)) + { + if (!nSpace.equals(Constants.NS_URI_XMLNS)) + { + String strValue = attribute.getValue(); + QName qValue = null; + + try + { + qValue = DOMUtils.getQName(strValue, el); + } + catch (WSDLException e) + { + qValue = new QName(strValue); + } + + attributes.put(name, qValue); + + String tempNSUri = def.getNamespace(prefix); + + while (tempNSUri != null && !tempNSUri.equals(nSpace)) + { + prefix += "_"; + tempNSUri = def.getNamespace(prefix); + } + + def.addNamespace(prefix, nSpace); + } + } + else if ( + !lName.equals(Constants.ATTR_NAME) + && !lName.equals(Constants.ATTR_ELEMENT) + && !lName.equals(Constants.ATTR_TYPE)) + { + WSDLException wsdlExc = + new WSDLException( + WSDLException.INVALID_WSDL, + "Encountered illegal " + + "part extension " + + "attribute '" + + name + + "'. Extension " + + "attributes must be in " + + "a namespace other than " + + "WSDL's."); + + wsdlExc.setLocation(XPathUtils.getXPathExprFromNode(el)); + //throw wsdlExc; + } + } + + // add the location of this element to elementLocations + setLocation(attributes, el); + + return attributes; + } + + /** + * Parse a specific portType element. + * + * @param portTypeEl The portType element. + * @param def The defintions element. + * @return A WSDL portType element. + * @throws WSDLException + */ + protected PortType parsePortType(Element portTypeEl, Definition def) throws WSDLException + { + + PortType portType = null; + String name = DOMUtils.getAttribute(portTypeEl, Constants.ATTR_NAME); + + if (name != null) + { + QName portTypeName = new QName(def.getTargetNamespace(), name); + + portType = def.getPortType(portTypeName); + + if (portType == null) + { + portType = def.createPortType(); + portType.setQName(portTypeName); + } + else if (!portType.isUndefined()) + { + // if the PortType has already been defined produce an error and return null + addReaderError( + def, + portTypeEl, + messagegenerator.getString("_PORTTYPE_NAME_ALREADY_DEFINED", "'" + portType.getQName().getLocalPart() + "'")); + return null; + } + } + else + { + portType = def.createPortType(); + } + + // Whether it was retrieved or created, the definition has been found. + portType.setUndefined(false); + + 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)) + { + // modified so duplicate operations will not be added to porttype + Operation op = parseOperation(tempEl, portType, def); + if (op != null) + { + portType.addOperation(op); + } + //portType.addOperation(parseOperation(tempEl, portType, def)); + } + else + { + // something else that shouldn't be here + // NEED TO ADD TO ERROR LIST + //DOMUtils.throwWSDLException(tempEl); + } + + tempEl = DOMUtils.getNextSiblingElement(tempEl); + } + + // add the location of this element to elementLocations + setLocation(portType, portTypeEl); + + return portType; + } + + /** + * Parse a specific operation element. + * + * @param opEl The operation element. + * @param portType The portType element. + * @param def The definitions element. + * @return A WSDL operation element. + * @throws WSDLException + */ + protected Operation parseOperation(Element opEl, PortType portType, Definition def) throws WSDLException + { + Operation op = null; + String name = DOMUtils.getAttribute(opEl, Constants.ATTR_NAME); + String parameterOrderStr = DOMUtils.getAttribute(opEl, Constants.ATTR_PARAMETER_ORDER); + Element tempEl = DOMUtils.getFirstChildElement(opEl); + List messageOrder = new Vector(); + Element docEl = null; + Input input = null; + Output output = null; + List faults = new Vector(); + + while (tempEl != null) + { + if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl)) + { + docEl = tempEl; + } + else if (QNameUtils.matches(Constants.Q_ELEM_INPUT, tempEl)) + { + input = parseInput(tempEl, def); + messageOrder.add(Constants.ELEM_INPUT); + } + else if (QNameUtils.matches(Constants.Q_ELEM_OUTPUT, tempEl)) + { + output = parseOutput(tempEl, def); + messageOrder.add(Constants.ELEM_OUTPUT); + } + else if (QNameUtils.matches(Constants.Q_ELEM_FAULT, tempEl)) + { + faults.add(parseFault(tempEl, def)); + } + else + { + // invalid element in the operation + // XML check will catch this + DOMUtils.throwWSDLException(tempEl); + } + + tempEl = DOMUtils.getNextSiblingElement(tempEl); + } + + if (name != null) + { + String inputName = (input != null ? input.getName() : null); + String outputName = (output != null ? output.getName() : null); + + boolean opDefined = false; + + try + { + + //op = portType.getOperation(name, inputName, outputName); + + //Operation op = null; + List operations = portType.getOperations(); + if (operations != null) + { + + Iterator iOperations = operations.iterator(); + while (iOperations.hasNext()) + { + boolean inputNamesEqual = false; + boolean outputNamesEqual = false; + Operation oper = (Operation)iOperations.next(); + if (oper.getName().equalsIgnoreCase(name)) + { + Input opInput = oper.getInput(); + if (opInput != null && input != null) + { + String opInputName = opInput.getName(); + if (opInputName != null && inputName != null && opInputName.equalsIgnoreCase(inputName)) + { + inputNamesEqual = true; + } + else if (opInputName == null && inputName == null) + { + inputNamesEqual = true; + } + } + else if (opInput == null && input == null) + { + inputNamesEqual = true; + } + Output opOutput = oper.getOutput(); + if (opOutput != null && output != null) + { + String opOutputName = opOutput.getName(); + if (opOutputName != null && outputName != null && opOutputName.equalsIgnoreCase(outputName)) + { + outputNamesEqual = true; + } + else if (opOutputName == null && outputName == null) + { + outputNamesEqual = true; + } + } + else if (opOutput == null && output == null) + { + outputNamesEqual = true; + } + if (inputNamesEqual && outputNamesEqual) + { + op = oper; + break; + } + } + } + } + } + catch (Exception e) + { + opDefined = true; + } + + if (op != null /*&& !op.isUndefined()*/ + ) + { + //op = null; + opDefined = true; + + } + + if (op != null && !opDefined) + { + if (inputName == null) + { + Input tempIn = op.getInput(); + + if (tempIn != null) + { + if (tempIn.getName() != null) + { + //op = null; + opDefined = true; + } + } + } + } + + if (op != null && !opDefined) + { + if (outputName == null) + { + Output tempOut = op.getOutput(); + + if (tempOut != null) + { + if (tempOut.getName() != null) + { + //op = null; + opDefined = true; + } + } + } + } + + if (opDefined) + { + // instead of creating a new one with the same name we're going to return null. + // According to the WSDL 1.2 working draft operation overloading is no longer allowed. + // Going to use that here to save a lot of work + setLocation(op, opEl); + addReaderError( + portType, + op, + messagegenerator.getString( + "_DUPLICATE_OPERATION_FOR_PORTTYPE", + "'" + op.getName() + "'", + "'" + portType.getQName().getLocalPart() + "'")); + return null; + } + if (op == null) + { + op = def.createOperation(); + op.setName(name); + + } + } + else + { + op = def.createOperation(); + } + + // 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.setInput(input); + } + + if (output != null) + { + op.setOutput(output); + } + + if (faults.size() > 0) + { + Iterator faultIterator = faults.iterator(); + + while (faultIterator.hasNext()) + { + Fault f = (Fault)faultIterator.next(); + // if the fault isn't defined yet + if (op.getFault(f.getName()) == null) + { + op.addFault(f); + } + else + { + addReaderError( + op, + f, + messagegenerator.getString("_DUPLICATE_FAULT_NAME", "'" + f.getName() + "'", "'" + op.getName() + "'")); + //faultErrors.add(new Object[]{f,"Duplicate Name",op}); + } + } + } + + OperationType style = null; + + if (messageOrder.equals(STYLE_ONE_WAY)) + { + style = OperationType.ONE_WAY; + } + else if (messageOrder.equals(STYLE_REQUEST_RESPONSE)) + { + style = OperationType.REQUEST_RESPONSE; + } + else if (messageOrder.equals(STYLE_SOLICIT_RESPONSE)) + { + style = OperationType.SOLICIT_RESPONSE; + } + else if (messageOrder.equals(STYLE_NOTIFICATION)) + { + style = OperationType.NOTIFICATION; + } + + if (style != null) + { + op.setStyle(style); + } + + // add the location of this element to elementLocations + setLocation(op, opEl); + + // modified to remove duplicate operations + // if(opDefined) + // { + // addReaderError(portType,op,ValidateWSDLPlugin.getInstance().getString("_DUPLICATE_OPERATION_FOR_PORTTYPE","'"+op.getName()+"'","'"+portType.getQName().getLocalPart()+"'")); + // return null; + // } + return op; + } + + /** + * Parse a specific service element. + * + * @param serviceEl The service element. + * @param def The defintions element. + * @return A WSDL service element. + * @throws WSDLException + */ + protected Service parseService(Element serviceEl, Definition def) throws WSDLException + { + Service service = def.createService(); + String name = DOMUtils.getAttribute(serviceEl, Constants.ATTR_NAME); + + if (name != null) + { + service.setQName(new QName(def.getTargetNamespace(), name)); + } + Service s; + // a service with this name has already been defined + if ((s = def.getService(service.getQName())) != null) + { + addReaderError( + def, + serviceEl, + messagegenerator.getString("_SERVICE_NAME_ALREADY_DEFINED", "'" + s.getQName().getLocalPart() + "'")); + return s; + } + Element tempEl = DOMUtils.getFirstChildElement(serviceEl); + + while (tempEl != null) + { + if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl)) + { + service.setDocumentationElement(tempEl); + } + else if (QNameUtils.matches(Constants.Q_ELEM_PORT, tempEl)) + { + service.addPort(parsePort(tempEl, def)); + } + else + { + service.addExtensibilityElement(parseExtensibilityElement(Service.class, tempEl, def)); + } + + tempEl = DOMUtils.getNextSiblingElement(tempEl); + } + + // add the location of this element to elementLocations + setLocation(service, serviceEl); + + return service; + } + + /** + * Parse a specific port element. + * + * @param portEl The port element. + * @param def The definitions element. + * @return A WSDL port element. + * @throws WSDLException + */ + protected Port parsePort(Element portEl, Definition def) throws WSDLException + { + Port port = def.createPort(); + String name = DOMUtils.getAttribute(portEl, Constants.ATTR_NAME); + QName bindingStr; + try + { + bindingStr = DOMUtils.getQualifiedAttributeValue(portEl, Constants.ATTR_BINDING, Constants.ELEM_PORT, false); + } + catch (Exception e) + { + //the call above fails if there is no qualified namespace for the message name + bindingStr = new QName(null, DOMUtils.getAttribute(portEl, "binding")); + } + + if (name != null) + { + port.setName(name); + } + + if (bindingStr != null) + { + Binding binding = def.getBinding(bindingStr); + + if (binding == null) + { + binding = def.createBinding(); + binding.setQName(bindingStr); + def.addBinding(binding); + } + + port.setBinding(binding); + } + + Element tempEl = DOMUtils.getFirstChildElement(portEl); + + while (tempEl != null) + { + if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl)) + { + port.setDocumentationElement(tempEl); + } + else + { + port.addExtensibilityElement(parseExtensibilityElement(Port.class, tempEl, def)); + } + + tempEl = DOMUtils.getNextSiblingElement(tempEl); + } + + // add the location of this element to elementLocations + setLocation(port, portEl); + + return port; + } + + /** + * Parse a specific extensibility element. + * + * @param parentType The parent type of the extensibility element. + * @param el The extensibility element. + * @param def The definitions element. + * @return A WSDL extensibility element. + * @throws WSDLException + */ + protected ExtensibilityElement parseExtensibilityElement(Class parentType, Element el, Definition def) + throws WSDLException + { + QName elementType = QNameUtils.newQName(el); + + try + { + ExtensionRegistry extReg = def.getExtensionRegistry(); + + if (extReg == null) + { + throw new WSDLException( + WSDLException.CONFIGURATION_ERROR, + "No ExtensionRegistry set for this " + + "Definition, so unable to deserialize " + + "a '" + + elementType + + "' element in the " + + "context of a '" + + parentType.getName() + + "'."); + } + + ExtensionDeserializer extDS = extReg.queryDeserializer(parentType, elementType); + + // asign the ExtensibilityElement to a var so we can add it to the locations + ExtensibilityElement extElem = extDS.unmarshall(parentType, elementType, el, def, extReg); + // add the location of this element to elementLocations + // this might not work properly + setLocation(extElem, el); + + // register all of the child Elements so we can find them later + // used for inline schema validation + registerChildElements(extElem); + + return extElem; + } + catch (WSDLException e) + { + if (e.getLocation() == null) + { + e.setLocation(XPathUtils.getXPathExprFromNode(el)); + } + throw e; + } + } + + /** + * Parse a specific input element. + * + * @param inputEl The input element. + * @param def The defintions element. + * @return A WSDL input element. + * @throws WSDLException + */ + protected Input parseInput(Element inputEl, Definition def) throws WSDLException + { + + Input input = def.createInput(); + String name = DOMUtils.getAttribute(inputEl, Constants.ATTR_NAME); + QName messageName = null; + try + { + messageName = DOMUtils.getQualifiedAttributeValue(inputEl, Constants.ATTR_MESSAGE, Constants.ELEM_INPUT, false); + } + catch (Exception e) + { + //the call above fails if there is no qualified namespace for the message name + messageName = new QName(null, DOMUtils.getAttribute(inputEl, "message")); + } + + if (name != null) + { + input.setName(name); + } + + if (messageName != null) + { + Message message = def.getMessage(messageName); + + if (message == null) + { + message = def.createMessage(); + message.setQName(messageName); + def.addMessage(message); + } + + input.setMessage(message); + } + + Element tempEl = DOMUtils.getFirstChildElement(inputEl); + + while (tempEl != null) + { + if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl)) + { + input.setDocumentationElement(tempEl); + } + else + { + // XML Validation will catch this + DOMUtils.throwWSDLException(tempEl); + } + + tempEl = DOMUtils.getNextSiblingElement(tempEl); + } + + // add the location of this element to elementLocations + setLocation(input, inputEl); + + return input; + } + + /** + * Parse a specific output element. + * + * @param outputEl The output element. + * @param def The defintions element. + * @return A WSDL output element. + * @throws WSDLException + */ + protected Output parseOutput(Element outputEl, Definition def) throws WSDLException + { + Output output = def.createOutput(); + String name = DOMUtils.getAttribute(outputEl, Constants.ATTR_NAME); + QName messageName = null; + try + { + messageName = DOMUtils.getQualifiedAttributeValue(outputEl, Constants.ATTR_MESSAGE, Constants.ELEM_OUTPUT, false); + } + catch (Exception e) + { + //the call above fails if there is no qualified namespace for the message name + messageName = new QName(null, DOMUtils.getAttribute(outputEl, "message")); + } + + if (name != null) + { + output.setName(name); + } + + if (messageName != null) + { + Message message = def.getMessage(messageName); + + if (message == null) + { + message = def.createMessage(); + message.setQName(messageName); + def.addMessage(message); + } + + output.setMessage(message); + } + + Element tempEl = DOMUtils.getFirstChildElement(outputEl); + + while (tempEl != null) + { + if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl)) + { + output.setDocumentationElement(tempEl); + } + else + { + // XML Validation will catch this + DOMUtils.throwWSDLException(tempEl); + } + + tempEl = DOMUtils.getNextSiblingElement(tempEl); + } + + // add the location of this element to elementLocations + setLocation(output, outputEl); + + return output; + } + + /** + * Parse a specific fault element. + * + * @param faultEl The fault element to parse. + * @param def The definitions element. + * @return A WSDL fault element. + * @throws WSDLException + */ + protected Fault parseFault(Element faultEl, Definition def) throws WSDLException + { + Fault fault = def.createFault(); + String name = DOMUtils.getAttribute(faultEl, Constants.ATTR_NAME); + QName messageName = null; + try + { + messageName = DOMUtils.getQualifiedAttributeValue(faultEl, Constants.ATTR_MESSAGE, Constants.ELEM_INPUT, false); + } + catch (Exception e) + { + //the call above fails if there is no qualified namespace for the message name + messageName = new QName(null, DOMUtils.getAttribute(faultEl, "message")); + } + + if (name != null) + { + fault.setName(name); + } + + if (messageName != null) + { + Message message = def.getMessage(messageName); + + if (message == null) + { + message = def.createMessage(); + message.setQName(messageName); + def.addMessage(message); + } + + fault.setMessage(message); + } + + Element tempEl = DOMUtils.getFirstChildElement(faultEl); + + while (tempEl != null) + { + if (QNameUtils.matches(Constants.Q_ELEM_DOCUMENTATION, tempEl)) + { + fault.setDocumentationElement(tempEl); + } + else + { + // XML Validation will catch this + DOMUtils.throwWSDLException(tempEl); + } + + tempEl = DOMUtils.getNextSiblingElement(tempEl); + } + + // add the location of this element to elementLocations + setLocation(fault, faultEl); + + return fault; + } + + /** + * Set the messagegenerator for the reader. + * + * @param mg The message generator to set. + */ + public void setMessageGenerator(MessageGenerator mg) + { + messagegenerator = mg; + } + + /** + * Add the refObject to the elementLocation hashtable with the location defined in element. + * + * @param refObject The object to add. + * @param element The element that contains the location information. + */ + protected void setLocation(Object refObject, Element element) + { + try + { + ElementImpl elementImpl = (ElementImpl)element; + ElementLocation elementLocation = (ElementLocation)elementImpl.getUserData(); + if (elementLocation != null) + { + + elementLocations.put( + refObject, + new LocationHolder(elementLocation.getLineNumber(), elementLocation.getColumnNumber(), def.getDocumentBaseURI())); + } + } + catch (ClassCastException e) + { + } + } + /** + * Add a reader error to the list. + * + * @param parentobject The parent object of the object with the error. + * @param object The object with the error. + * @param error The error message. + */ + protected void addReaderError(Object parentobject, Object object, String error) + { + readerErrors.add(new ReaderError(parentobject, object, error)); + } + + /** + * Add a reader warning to the list. + * + * @param parentobject The parent object of the object with the error. + * @param object The object with the error. + * @param warning The warning message. + */ + protected void addReaderWarning(Object parentobject, Object object, String warning) + { + readerWarnings.add(new ReaderError(parentobject, object, warning)); + } + + /** + * Register all of the locations of the child elements of the extensibility + * element given. + * + * @param extElem The extensibility element whose child elements will be registered. + */ + + protected void registerChildElements(ExtensibilityElement extElem) + { + // only add those that are of type unknown. if they're known they + // will take care of themselves + if (extElem instanceof UnknownExtensibilityElement) + { + Element elem = ((UnknownExtensibilityElement)extElem).getElement(); + registerChildElementsRecursively(elem); + } + } + + /** + * Register the location of all of the child elements of elem. + * + * @param elem The element whose child elements will be registered. + */ + protected void registerChildElementsRecursively(Element elem) + { + if (elem instanceof ElementNSImpl) + { + setLocation(elem, elem); + + // call the method recursively for each child element + NodeList childNodes = elem.getChildNodes(); + + for (int i = 0; i < childNodes.getLength() || i < 5; i++) + { + Node n = childNodes.item(i); + // we only want nodes that are Elements + if (n instanceof Element) + { + Element child = (Element)n; + registerChildElementsRecursively(child); + } + } + } + } + /** + * Check that an element name matches the expected name. + * + * @param el The element with the name to check. + * @param qname The name to check against. + * @throws WSDLException + */ + private static void checkElementName(Element el, QName qname) throws WSDLException + { + if (!QNameUtils.matches(qname, el)) + { + WSDLException wsdlExc = new WSDLException(WSDLException.INVALID_WSDL, "Expected element '" + qname + "'."); + + wsdlExc.setLocation(XPathUtils.getXPathExprFromNode(el)); + + throw wsdlExc; + } + } + + /** + * Get the element locations hashtable. + * + * @return The element locations hashtable. + */ + public Hashtable getElementLocations() + { + return elementLocations; + } + + /** + * Get the reader errors. + * + * @return The reader errors. + */ + public List getReaderErrors() + { + return readerErrors; + } + + /** + * Get reader warnings. + * + * @return The reader warnings. + */ + public List getReaderWarnings() + { + return readerWarnings; + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/WSDLReaderImpl.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/WSDLReaderImpl.java new file mode 100644 index 000000000..4e6ecd6a9 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/WSDLReaderImpl.java @@ -0,0 +1,427 @@ +/******************************************************************************* + * 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.Reader; +import java.net.URL; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.wsdl.Import; +import javax.wsdl.WSDLException; + +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.parsers.DOMParser; +import org.apache.xerces.parsers.StandardParserConfiguration; +import org.apache.xerces.xni.XNIException; +import org.eclipse.wst.wsdl.validation.internal.util.MessageGenerator; +import org.eclipse.wst.wsdl.validation.internal.xml.LineNumberDOMParser; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import com.ibm.wsdl.DefinitionImpl; +import com.ibm.wsdl.util.StringUtils; + +/** + * A WSDL reader that supports cyclic WSDL imports, schema imports and inline schemas. + * This reader is based on the WSDLReaderImpl from WSDL4J. + */ +public class WSDLReaderImpl +{ + protected MessageGenerator messagegenerator; + protected IWSDL11ValidationInfo wsdlvalinfo; + + /** + * Constructor. + * + * @param wsdlvalinfo The WSDL 1.1 validation info object to use. + */ + public WSDLReaderImpl(IWSDL11ValidationInfo wsdlvalinfo) + { + this.wsdlvalinfo = wsdlvalinfo; + } + + /** + * Parse the root document. This method will find all imports and parse them as + * well creating a WSDLDocument for each unique WSDL file. This method supports + * cyclic WSDL import statements such that file A can import file B and file B + * can import file A. + * + * @param documentBaseURI The base URI of the root document. + * @param defEl The definition element of the root document. + * @return An array of WSDLDocuments containing all of the unique files in the description. + * @throws WSDLException + */ + protected WSDLDocument[] parseDocument(String documentBaseURI, Element defEl) throws WSDLException + { + int initialImportArraySize = 20; + List[] filesAtDepth = new ArrayList[initialImportArraySize]; + Map filesImporting = new Hashtable(); + SortedSet parsedImports = new TreeSet(); + SortedSet importsToParse = new TreeSet(); + int maxdepth = 0; + + WSDLDocument rootdoc = new WSDLDocument(documentBaseURI, defEl, 0, messagegenerator, wsdlvalinfo); + String targetNamespace = rootdoc.getDefinition().getTargetNamespace(); + ImportHolder rootImport = new ImportHolder(targetNamespace, documentBaseURI, documentBaseURI, rootdoc, 0, null, messagegenerator, wsdlvalinfo); + rootImport.createWSDLImport(rootdoc); + parsedImports.add(rootImport); + List rootList = new ArrayList(); + filesImporting.put(rootImport.getLocation(), new ArrayList()); + rootList.add(rootdoc); + filesAtDepth[0] = rootList; + importsToParse.addAll(rootdoc.getImports()); + Set imps = rootdoc.getImports(); + Iterator impIter = imps.iterator(); + while(impIter.hasNext()) + { + ImportHolder imp = (ImportHolder)impIter.next(); + List tempList = new ArrayList(); + tempList.add(imp.getImportingDocument()); + filesImporting.put(imp.getLocation(), tempList); + } + + while(!importsToParse.isEmpty()) + { + ImportHolder imp = (ImportHolder)importsToParse.first(); + // It's important to initialize the import here so each import + // is only created once. In the case of reciprical imports this + // avoids an infinite loop. + imp.initialize(); + WSDLDocument impDoc = imp.getWSDLDocument(); + + importsToParse.remove(imp); + + parsedImports.add(imp); + + // Add new imports to the list of imports to parse. + // Remove all the imports that have already been parsed. + if(impDoc != null) + { + // Increate import array if necessary. + if(imp.getDepth() >= initialImportArraySize) + { + List[] tempArray = new List[filesAtDepth.length + initialImportArraySize]; + System.arraycopy(filesAtDepth, 0, tempArray, 0, filesAtDepth.length); + filesAtDepth = tempArray; + } + // Create the list for the depth if necessary. + int impDepth = imp.getDepth(); + if(filesAtDepth[impDepth] == null) + { + if(maxdepth < impDepth) + { + maxdepth = impDepth; + } + filesAtDepth[impDepth] = new ArrayList(); + } + filesAtDepth[imp.getDepth()].add(impDoc); + + Set imports = impDoc.getImports(); + ImportHolder[] importsArray = (ImportHolder[])imports.toArray(new ImportHolder[imports.size()]); + for(int i = 0; i < importsArray.length; i++) + { + ImportHolder ih = importsArray[i]; + // If already parsed, add the definition importing this file to the list. + if(filesImporting.containsKey(ih.getLocation())) + { + ((List)filesImporting.get(ih.getLocation())).add(ih.getImportingDocument()); + } + // Otherwise add it to the list to parse. + else + { + // Add this import to the list of files importing list. + List tempList = new ArrayList(); + tempList.add(ih.getImportingDocument()); + filesImporting.put(ih.getLocation(), tempList); + importsToParse.add(ih); + } + } + } + } + + // Add all of the imports to the respective documents. + Iterator importElementsIter = parsedImports.iterator(); + while(importElementsIter.hasNext()) + { + ImportHolder imp = (ImportHolder)importElementsIter.next(); + List files = (List)filesImporting.get(imp.getLocation()); + Iterator filesIter = files.iterator(); + while(filesIter.hasNext()) + { + WSDLDocument doc = (WSDLDocument)filesIter.next(); + + DefinitionImpl def = (DefinitionImpl)doc.getDefinition(); + Import impElem = imp.getImport(); + if(impElem != null) + { + def.addImport(impElem); + if(!imp.isWSDLFileImport()) + { + doc.addSchemas(imp.getSchemas()); + } + } + + } + } + + // Parse the WSDL documents. + // Parse the Messages. + for(int i = maxdepth; i >=0; i--) + { + List docs = filesAtDepth[i]; + Iterator docsIter = docs.iterator(); + while(docsIter.hasNext()) + { + WSDLDocument doc = (WSDLDocument)docsIter.next(); + doc.parseMessages(); + } + } + // Parse the Porttypes. + for(int i = maxdepth; i >=0; i--) + { + List docs = filesAtDepth[i]; + Iterator docsIter = docs.iterator(); + while(docsIter.hasNext()) + { + WSDLDocument doc = (WSDLDocument)docsIter.next(); + doc.parsePorttypes(); + } + } + // Parse the Bindings. + for(int i = maxdepth; i >=0; i--) + { + List docs = filesAtDepth[i]; + Iterator docsIter = docs.iterator(); + while(docsIter.hasNext()) + { + WSDLDocument doc = (WSDLDocument)docsIter.next(); + doc.parseBindings(); + } + } + // Parse the Services. + for(int i = maxdepth; i >=0; i--) + { + List docs = filesAtDepth[i]; + Iterator docsIter = docs.iterator(); + while(docsIter.hasNext()) + { + WSDLDocument doc = (WSDLDocument)docsIter.next(); + doc.parseServices(); + } + } + // Parse the Extensibility Elements. + for(int i = maxdepth; i >=0; i--) + { + List docs = filesAtDepth[i]; + Iterator docsIter = docs.iterator(); + while(docsIter.hasNext()) + { + WSDLDocument doc = (WSDLDocument)docsIter.next(); + doc.parseExtensibilityElements(); + } + } + + List wsdlDocs = new ArrayList(); + for(int i = maxdepth; i >=0; i--) + { + List docs = filesAtDepth[i]; + Iterator docsIter = docs.iterator(); + while(docsIter.hasNext()) + { + WSDLDocument doc = (WSDLDocument)docsIter.next(); + wsdlDocs.add(doc); + } + } + + return (WSDLDocument[])wsdlDocs.toArray(new WSDLDocument[wsdlDocs.size()]); + } + + /** + * Get the WSDL document. + * + * @param inputSource The source of the document being retrieved. + * @param desc The description of the document being retrieved. + * @return The WSDL document. + * @throws WSDLException + */ + public static Document getDocument(InputSource inputSource, String desc) throws WSDLException + { + try + { + StandardParserConfiguration configuration = new StandardParserConfiguration() + { + protected XMLErrorReporter createErrorReporter() + { + return new XMLErrorReporter() + { + public void reportError(String domain, String key, Object[] arguments, short severity) throws XNIException + { + boolean reportError = true; + if (key.equals("PrematureEOF")) + { + reportError = false; + } + + if (reportError) + { + super.reportError(domain, key, arguments, severity); + } + } + }; + } + }; + + ErrorHandler errorHandler = new ErrorHandler() + { + /* (non-Javadoc) + * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException) + */ + public void error(SAXParseException exception) throws SAXException + { + // TODO Auto-generated method stub + + } + /* (non-Javadoc) + * @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException) + */ + public void fatalError(SAXParseException exception) throws SAXException + { + // TODO Auto-generated method stub + + } + /* (non-Javadoc) + * @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException) + */ + public void warning(SAXParseException exception) throws SAXException + { + // TODO Auto-generated method stub + + } + }; + + DOMParser builder = new LineNumberDOMParser(configuration); + builder.setErrorHandler(errorHandler); + builder.parse(inputSource); + Document doc = builder.getDocument(); + + return doc; + } + catch (Throwable t) + { + throw new WSDLException(WSDLException.PARSER_ERROR, "Problem parsing '" + desc + "'.", t); + } + } + + /** + * Read a WSDL document using a context URI and file URI. + * + * @param contextURI The context URI to use. + * @param wsdlURI The WSDL URI to use. + * @return An array of WSDLDocuments. + * @throws WSDLException + */ + public WSDLDocument[] readWSDL(String contextURI, String wsdlURI) throws WSDLException + { + try + { + URL contextURL = (contextURI != null) ? StringUtils.getURL(null, contextURI) : null; + URL url = StringUtils.getURL(contextURL, wsdlURI); + Reader reader = StringUtils.getContentAsReader(url); + InputSource inputSource = new InputSource(reader); + Document doc = getDocument(inputSource, wsdlURI); + reader.close(); + WSDLDocument[] wsdlDocs = null; + // only parse the document if it isn't empty + if(doc.getDocumentElement() != null) + { + wsdlDocs = readWSDL(url.toString(), doc); + } + return wsdlDocs; + } + catch (WSDLException e) + { + throw e; + } + catch (Throwable t) + { + throw new WSDLException( + WSDLException.OTHER_ERROR, + "Unable to resolve imported document at '" + wsdlURI + "'.", + t); + } + } + + /** + * Set the messagegenerator for the reader. + * + * @param mg The message generator to set. + */ + public void setMessageGenerator(MessageGenerator mg) + { + messagegenerator = mg; + } + + /** + * Read the WSDL document accessible via the specified + * URI into a WSDL definition. + * + * @param wsdlURI A URI pointing to a WSDL file. + * @return An array of WSDLDocuments. + */ + public WSDLDocument[] readWSDL(String wsdlURI) throws WSDLException + { + return readWSDL(null, wsdlURI); + } + + /** + * Read the WSDL document described by a URI and its definitions element. + * + * @param documentBaseURI The URI of the WSDL document. + * @param definitionsElement The definitions element for the WSDL document. + * @return An array of WSDLDocuments. + * @throws WSDLException + */ + protected WSDLDocument[] readWSDL(String documentBaseURI, + Element definitionsElement) + throws WSDLException + { + return parseDocument(documentBaseURI, definitionsElement); + } + + /** + * Read the specified WSDL document. + * + * @param documentBaseURI The document base URI. + * @param wsdlDocument The WSDL document. + * @return An array of WSDLDocuments. + */ + public WSDLDocument[] readWSDL(String documentBaseURI, Document wsdlDocument) + throws WSDLException + { + return readWSDL(documentBaseURI, wsdlDocument.getDocumentElement()); + } + + + +} + diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/http/HTTPValidator.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/http/HTTPValidator.java new file mode 100644 index 000000000..6780e48e2 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/http/HTTPValidator.java @@ -0,0 +1,334 @@ +/******************************************************************************* + * 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.http; + +import java.util.Iterator; +import java.util.List; +import java.util.ResourceBundle; + +import javax.wsdl.Binding; +import javax.wsdl.BindingInput; +import javax.wsdl.BindingOperation; +import javax.wsdl.Port; +import javax.wsdl.extensions.ExtensibilityElement; +import javax.wsdl.extensions.http.HTTPOperation; + +import org.eclipse.wst.wsdl.validation.internal.util.MessageGenerator; +import org.eclipse.wst.wsdl.validation.internal.wsdl11.IWSDL11Validator; +import org.eclipse.wst.wsdl.validation.internal.wsdl11.IWSDL11ValidationInfo; + +import com.ibm.wsdl.BindingImpl; +import com.ibm.wsdl.BindingInputImpl; +import com.ibm.wsdl.BindingOperationImpl; +import com.ibm.wsdl.PortImpl; +import com.ibm.wsdl.extensions.http.HTTPAddressImpl; +import com.ibm.wsdl.extensions.http.HTTPBindingImpl; +import com.ibm.wsdl.extensions.http.HTTPOperationImpl; +import com.ibm.wsdl.extensions.http.HTTPUrlEncodedImpl; +import com.ibm.wsdl.extensions.http.HTTPUrlReplacementImpl; + +/** + * The HTTP validator is an extension WSDL validator that validates all elements in the HTTP + * namespace. + */ +public class HTTPValidator implements IWSDL11Validator +{ + private final String _ERROR_INVALID_PORT_ELEMENT = "_ERROR_INVALID_PORT_ELEMENT"; + private final String _ERROR_INVALID_BINDING_ELEMENT = "_ERROR_INVALID_BINDING_ELEMENT"; + private final String _ERROR_INVALID_BINDING_OPERATION_ELEMENT = "_ERROR_INVALID_BINDING_OPERATION_ELEMENT"; + private final String _ERROR_INVALID_BINDING_INPUT_ELEMENT = "_ERROR_INVALID_BINDING_INPUT_ELEMENT"; + private final String _ERROR_INVALID_HTTP_ELEMENT_FOR_LOCATION = "_ERROR_INVALID_HTTP_ELEMENT_FOR_LOCATION"; + private final String _ERROR_NO_LOCATION_FOR_ADDRESS = "_ERROR_NO_LOCATION_FOR_ADDRESS"; + private final String _ERROR_NO_HTTPBINDING_FOR_ADDRESS = "_ERROR_NO_HTTPBINDING_FOR_ADDRESS"; + private final String _ERROR_INVALID_BINDING_VERB = "_ERROR_INVALID_BINDING_VERB"; + private final String _ERROR_INVALID_LOCATION_URI = "_ERROR_INVALID_LOCATION_URI"; + private final String _ERROR_NO_HTTPBINDING_FOR_OPERATION = "_ERROR_NO_HTTPBINDING_FOR_OPERATION"; + private final String _ERROR_NOT_ONLY_ELEMENT_DEFINED = "_ERROR_NOT_ONLY_ELEMENT_DEFINED"; + private final String _ERROR_NO_HTTPOPERATION_FOR_URL = "_ERROR_NO_HTTPOPERATION_FOR_URL"; + + private final String GET = "GET"; + private final String POST = "POST"; + + private final String QUOTE = "'"; + private final String EMPTY_STRING = ""; + + private MessageGenerator messagegenerator; + + /** + * @see org.eclipse.wst.wsdl.validation.internal.wsdl11.IWSDL11Validator#validate(java.lang.Object, java.util.List, org.eclipse.wsdl.validate.wsdl11.IWSDL11ValidationInfo) + */ + public void validate(Object element, List parents, IWSDL11ValidationInfo valInfo) + { + // Port HTTP definition + // make sure every port has only one address element defined + // if it is an address element, validate it + if (parents.get(0).getClass() == PortImpl.class) + { + if (element.getClass() == HTTPAddressImpl.class) + { + validateAddress(element, parents, valInfo); + } + else + { + ExtensibilityElement e = (ExtensibilityElement)element; + valInfo.addError( + messagegenerator.getString(_ERROR_INVALID_PORT_ELEMENT, QUOTE + e.getElementType().getLocalPart() + QUOTE), + element); + } + } + + // Binding HTTP definition + // A HTTP Binding must have a verb of GET or POST + else if (parents.get(0).getClass() == BindingImpl.class) + { + if (element.getClass() == HTTPBindingImpl.class) + { + validateBinding(element, parents, valInfo); + } + else + { + ExtensibilityElement e = (ExtensibilityElement)element; + valInfo.addError( + messagegenerator.getString(_ERROR_INVALID_BINDING_ELEMENT, QUOTE + e.getElementType().getLocalPart() + QUOTE), + element); + } + } + // Binding Operation HTTP definition + // A HTTP Operation has a location uri defined + else if (parents.get(0).getClass() == BindingOperationImpl.class) + { + if (element.getClass() == HTTPOperationImpl.class) + { + validateOperation(element, parents, valInfo); + } + else + { + ExtensibilityElement e = (ExtensibilityElement)element; + valInfo.addError( + messagegenerator.getString( + _ERROR_INVALID_BINDING_OPERATION_ELEMENT, + QUOTE + e.getElementType().getLocalPart() + QUOTE), + element); + } + + } + else if (parents.get(0).getClass() == BindingInputImpl.class) + { + // validate the HTTP urlEncoded and urlReplacement + if (element.getClass() == HTTPUrlEncodedImpl.class || element.getClass() == HTTPUrlReplacementImpl.class) + { + validateHttpUrl(element, parents, valInfo); + } + else + { + ExtensibilityElement e = (ExtensibilityElement)element; + valInfo.addError( + messagegenerator.getString(_ERROR_INVALID_BINDING_INPUT_ELEMENT, QUOTE + e.getElementType().getLocalPart() + QUOTE), + element); + } + } + + // in this case there has been a HTTP element defined that is not defined for this point in the HTTP namespace + else + { + ExtensibilityElement e = (ExtensibilityElement)element; + valInfo.addError( + messagegenerator.getString( + _ERROR_INVALID_HTTP_ELEMENT_FOR_LOCATION, + QUOTE + e.getElementType().getLocalPart() + QUOTE), + element); + } + + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.wsdl11.validator.IWSDL11Validator#setResourceBundle(java.util.ResourceBundle) + */ + public void setResourceBundle(ResourceBundle rb) + { + if (messagegenerator == null) + { + messagegenerator = new MessageGenerator(rb); + } + } + + /** + * Ensure that the HTTP address has a value specified for it's uri and that there is a HTTP Binding defined + * for the Binding specified in the port. + * + * @param element The HTTP address element. + * @param parents The list of parents of the HTTP address element. + * @param validatorcontroller The validator controller in charge of validation. + */ + protected void validateAddress(Object element, List parents, IWSDL11ValidationInfo valInfo) + { + HTTPAddressImpl ha = (HTTPAddressImpl)element; + + String uri = ha.getLocationURI(); + if (uri == null || uri.equalsIgnoreCase(EMPTY_STRING)) + { + valInfo.addError(messagegenerator.getString(_ERROR_NO_LOCATION_FOR_ADDRESS), ha); + } + + Port port = (Port)parents.get(0); + + Binding binding = port.getBinding(); + + if (!hasHttpBinding(binding)) + { + valInfo.addError( + messagegenerator.getString( + _ERROR_NO_HTTPBINDING_FOR_ADDRESS, + QUOTE + binding.getQName().getLocalPart() + QUOTE, + QUOTE + port.getName() + QUOTE), + ha); + } + } + + /** + * Ensure the HTTP Binding defined is valid. A HTTP Binding must have a verb of GET or POST. + * + * @param element The HTTP binding element. + * @param parents The list of parents of the HTTP binding element. + * @param validatorcontroller The validator controller in charge of validation. + */ + protected void validateBinding(Object element, List parents, IWSDL11ValidationInfo valInfo) + { + HTTPBindingImpl hb = (HTTPBindingImpl)element; + + String verb = hb.getVerb(); + + if (verb != null && !verb.equals(GET) && !verb.equals(POST)) + { + valInfo.addError(messagegenerator.getString(_ERROR_INVALID_BINDING_VERB, QUOTE + verb + QUOTE), element); + } + } + + /** + * An operation must have a location defined. A HTTP Binding must be specified to use an operation. + * + * @param element The HTTP operation element. + * @param parents The list of parents of the HTTP operation element. + * @param validatorcontroller The validator controller in charge of validation. + */ + protected void validateOperation(Object element, List parents, IWSDL11ValidationInfo valInfo) + { + HTTPOperation ho = (HTTPOperation)element; + + String locationURI = ho.getLocationURI(); + + if (locationURI != null && locationURI.equalsIgnoreCase(EMPTY_STRING)) + { + valInfo.addError(messagegenerator.getString(_ERROR_INVALID_LOCATION_URI), element); + } + + Binding binding = (Binding)parents.get(1); + if (!hasHttpBinding(binding)) + { + valInfo.addError( + messagegenerator.getString(_ERROR_NO_HTTPBINDING_FOR_OPERATION, QUOTE + binding.getQName().getLocalPart() + QUOTE), + ho); + } + } + + /** + * Validate the HTTP urlReplacement or urlEncoded. Ensure the HTTP operation has been defined. + * Ensure that either element is the only element specified. + * + * @param element The HTTP binding operation element. + * @param parents The list of parents of the HTTP binding operation element. + * @param validatorcontroller The validator controller in charge of validation. + */ + protected void validateHttpUrl(Object element, List parents, IWSDL11ValidationInfo valInfo) + { + BindingOperation operation = (BindingOperation)parents.get(1); + + String elementName; + if (element.getClass() == HTTPUrlEncodedImpl.class) + { + elementName = "urlEncoded"; + } + else if (element.getClass() == HTTPUrlReplacementImpl.class) + { + elementName = "urlReplacement"; + } + else + { + elementName = EMPTY_STRING; + } + + BindingInput input = (BindingInput)parents.get(0); + if (input.getExtensibilityElements().size() != 1) + { + valInfo.addError(messagegenerator.getString(_ERROR_NOT_ONLY_ELEMENT_DEFINED, elementName), element); + } + + if (!hasHttpOperation(operation)) + { + valInfo.addError( + messagegenerator.getString(_ERROR_NO_HTTPOPERATION_FOR_URL, QUOTE + operation.getName() + QUOTE, elementName), + element); + } + } + + /** + * Given a BindingOperation tells whether it has a HTTP operation defined for it. + * + * @param binding The HTTP binding operation element. + * @return True if there is an HTTP operation defined, false otherwise. + */ + protected boolean hasHttpOperation(BindingOperation operation) + { + if (operation != null) + { + List extelems = operation.getExtensibilityElements(); + if (extelems != null) + { + Iterator iextelems = extelems.iterator(); + while (iextelems.hasNext()) + { + if (iextelems.next().getClass() == HTTPOperationImpl.class) + { + return true; + } + } + } + } + return false; + } + + /** + * Given a binding returns true if it has a HTTP binding defined. + * + * @param binding The binding to check. + * @return True if there is an HTTP binding defined. + */ + protected boolean hasHttpBinding(Binding binding) + { + if (binding != null) + { + List extelems = binding.getExtensibilityElements(); + if (extelems != null) + { + Iterator iextelems = extelems.iterator(); + while (iextelems.hasNext()) + { + if (iextelems.next().getClass() == HTTPBindingImpl.class) + { + return true; + } + } + } + } + return false; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/mime/MIMEValidator.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/mime/MIMEValidator.java new file mode 100644 index 000000000..54fcea8f2 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/mime/MIMEValidator.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * 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.mime; + +import java.util.List; +import java.util.ResourceBundle; + +import org.eclipse.wst.wsdl.validation.internal.util.MessageGenerator; +import org.eclipse.wst.wsdl.validation.internal.wsdl11.IWSDL11Validator; +import org.eclipse.wst.wsdl.validation.internal.wsdl11.IWSDL11ValidationInfo; + +/** + * The MIME validator plugs into the WSDL validator to provide + * validation for all elements in a WSDL document within the MIME namespace. + */ +public class MIMEValidator implements IWSDL11Validator +{ + protected MessageGenerator messagegenerator; + + /** + * @see org.eclipse.wst.wsdl.validation.internal.wsdl11.IWSDL11Validator#validate(java.lang.Object, java.util.List, org.eclipse.wsdl.validate.wsdl11.IWSDL11ValidationInfo) + */ + public void validate(Object element, List parents, IWSDL11ValidationInfo valInfo) + { + + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.wsdl11.validator.IWSDL11Validator#setResourceBundle(java.util.ResourceBundle) + */ + public void setResourceBundle(ResourceBundle rb) + { + if (messagegenerator == null) + { + messagegenerator = new MessageGenerator(rb); + } + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/soap/SOAPValidator.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/soap/SOAPValidator.java new file mode 100644 index 000000000..b3a95493e --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/soap/SOAPValidator.java @@ -0,0 +1,603 @@ +/******************************************************************************* + * 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.soap; + +import java.util.Iterator; +import java.util.List; +import java.util.ResourceBundle; + +import javax.wsdl.Binding; +import javax.wsdl.BindingFault; +import javax.wsdl.BindingOperation; +import javax.wsdl.Definition; +import javax.wsdl.Input; +import javax.wsdl.Message; +import javax.wsdl.Operation; +import javax.wsdl.Output; +import javax.wsdl.Part; +import javax.wsdl.Port; +import javax.wsdl.extensions.ExtensibilityElement; +import javax.wsdl.extensions.soap.SOAPOperation; +import javax.xml.namespace.QName; + +import org.eclipse.wst.wsdl.validation.internal.util.MessageGenerator; +import org.eclipse.wst.wsdl.validation.internal.wsdl11.IWSDL11Validator; +import org.eclipse.wst.wsdl.validation.internal.wsdl11.IWSDL11ValidationInfo; + +import com.ibm.wsdl.BindingFaultImpl; +import com.ibm.wsdl.BindingImpl; +import com.ibm.wsdl.BindingInputImpl; +import com.ibm.wsdl.BindingOperationImpl; +import com.ibm.wsdl.BindingOutputImpl; +import com.ibm.wsdl.PortImpl; +import com.ibm.wsdl.extensions.soap.SOAPAddressImpl; +import com.ibm.wsdl.extensions.soap.SOAPBindingImpl; +import com.ibm.wsdl.extensions.soap.SOAPBodyImpl; +import com.ibm.wsdl.extensions.soap.SOAPFaultImpl; +import com.ibm.wsdl.extensions.soap.SOAPHeaderFaultImpl; +import com.ibm.wsdl.extensions.soap.SOAPHeaderImpl; +import com.ibm.wsdl.extensions.soap.SOAPOperationImpl; + +/** + * The SOAP validator plugs into the WSDL validator to provide + * validation for all elements in a WSDL document within the SOAP namespace. + * + */ +public class SOAPValidator implements IWSDL11Validator +{ + private final String _ERROR_INVALID_PORT_ELEMENT = "_ERROR_INVALID_PORT_ELEMENT"; + private final String _ERROR_INVALID_BINDING_ELEMENT = "_ERROR_INVALID_BINDING_ELEMENT"; + private final String _ERROR_INVALID_BINDING_OPERATION_ELEMENT = "_ERROR_INVALID_BINDING_OPERATION_ELEMENT"; + private final String _ERROR_INVALID_HEADER_BODY_ELEMENT = "_ERROR_INVALID_HEADER_BODY_ELEMENT"; + private final String _ERROR_INVALID_FAULT_ELEMENT = "_ERROR_INVALID_FAULT_ELEMENT"; + private final String _ERROR_INVALID_SOAP_ELEMENT_FOR_LOCATION = "_ERROR_INVALID_SOAP_ELEMENT_FOR_LOCATION"; + private final String _ERROR_NO_LOCATION_FOR_ADDRESS = "_ERROR_NO_LOCATION_FOR_ADDRESS"; + private final String _ERROR_NO_SOAPBINDING_FOR_ADDRESS = "_ERROR_NO_SOAPBINDING_FOR_ADDRESS"; + private final String _ERROR_INVALID_BINDING_STYLE = "_ERROR_INVALID_BINDING_STYLE"; + private final String _ERROR_INVALID_BINDING_URI = "_ERROR_INVALID_BINDING_URI"; + private final String _ERROR_INVALID_OPERATION_STYLE = "_ERROR_INVALID_OPERATION_STYLE"; + private final String _ERROR_NO_SOAPBINDING_FOR_OPERATION = "_ERROR_NO_SOAPBINDING_FOR_OPERATION"; + private final String _ERROR_INVALID_BODY_ENCODING_STYLE = "_ERROR_INVALID_BODY_ENCODING_STYLE"; + private final String _ERROR_INVALID_BODY_NAMESPACE_FOR_ENCODED = "_ERROR_INVALID_BODY_NAMESPACE_FOR_ENCODED"; + private final String _ERROR_INVALID_BODY_USE = "_ERROR_INVALID_BODY_USE"; + private final String _ERROR_INVALID_BODY_PART_NOT_TYPE = "_ERROR_INVALID_BODY_PART_NOT_TYPE"; + private final String _ERROR_INVALID_BODY_PART_UNDEFINED = "_ERROR_INVALID_BODY_PART_UNDEFINED"; + private final String _ERROR_NO_SOAPBINDING_FOR_BODY = "_ERROR_NO_SOAPBINDING_FOR_BODY"; + private final String _ERROR_HEADER_MESSAGE_UNDEFINED = "_ERROR_HEADER_MESSAGE_UNDEFINED"; + private final String _ERROR_HEADER_PART_UNDEFINED = "_ERROR_HEADER_PART_UNDEFINED"; + private final String _ERROR_HEADER_USE_UNDEFINED = "_ERROR_HEADER_USE_UNDEFINED"; + private final String _ERROR_HEADER_ENCODINGSTYLE_UNDEFINED = "_ERROR_HEADER_ENCODINGSTYLE_UNDEFINED"; + private final String _ERROR_HEADER_NAMESPACE_UNDEFINED = "_ERROR_HEADER_NAMESPACE_UNDEFINED"; + private final String _ERROR_NO_SOAPBINDING_FOR_HEADER = "_ERROR_NO_SOAPBINDING_FOR_HEADER"; + private final String _ERROR_HEADERFAULT_MESSAGE_UNDEFINED = "_ERROR_HEADERFAULT_MESSAGE_UNDEFINED"; + private final String _ERROR_HEADERFAULT_PART_UNDEFINED = "_ERROR_HEADERFAULT_PART_UNDEFINED"; + private final String _ERROR_HEADERFAULT_USE_UNDEFINED = "_ERROR_HEADERFAULT_USE_UNDEFINED"; + private final String _ERROR_HEADERFAULT_ENCODINGSTYLE_UNDEFINED = "_ERROR_HEADERFAULT_ENCODINGSTYLE_UNDEFINED"; + private final String _ERROR_HEADERFAULT_NAMESPACE_UNDEFINED = "_ERROR_HEADERFAULT_NAMESPACE_UNDEFINED"; + private final String _ERROR_INVALID_FAULT_NAME = "_ERROR_INVALID_FAULT_NAME"; + private final String _ERROR_INVALID_FAULT_ENCODING_STYLE = "_ERROR_INVALID_FAULT_ENCODING_STYLE"; + private final String _ERROR_INVALID_FAULT_NAMESPACE_FOR_ENCODED = "_ERROR_INVALID_FAULT_NAMESPACE_FOR_ENCODED"; + + private final String ENCODED = "encoded"; + private final String LITERAL = "literal"; + private final String RPC = "rpc"; + private final String DOCUMENT = "document"; + + private final String QUOTE = "'"; + private final String EMPTY_STRING = ""; + + protected MessageGenerator messagegenerator; + + /** + * @see org.eclipse.wst.wsdl.validation.internal.wsdl11.IWSDL11Validator#validate(java.lang.Object, java.util.List, org.eclipse.wsdl.validate.wsdl11.IWSDL11ValidationInfo) + */ + public void validate(Object element, List parents, IWSDL11ValidationInfo valInfo) + { + // Port SOAP definition + // make sure every port has only one address element defined + // if it is an address element, validate it + if (parents.get(0).getClass() == PortImpl.class) + { + if (element.getClass() == SOAPAddressImpl.class) + { + validateAddress(element, parents, valInfo); + } + else + { + ExtensibilityElement e = (ExtensibilityElement)element; + valInfo.addError( + messagegenerator.getString(_ERROR_INVALID_PORT_ELEMENT, QUOTE + e.getElementType().getLocalPart() + QUOTE), element); + } + } + + // Binding SOAP definition + // A SOAP Binding must have a style or rpc or document or no style defined - defaults to document + // Must have a transport uri defined - check if the uri is empty + else if (parents.get(0).getClass() == BindingImpl.class) + { + if (element.getClass() == SOAPBindingImpl.class) + { + validateBinding(element, parents, valInfo); + } + else + { + ExtensibilityElement e = (ExtensibilityElement)element; + valInfo.addError( + messagegenerator.getString(_ERROR_INVALID_BINDING_ELEMENT, QUOTE + e.getElementType().getLocalPart() + QUOTE), element); + } + } + // Binding Operation SOAP definition + // A SOAP Operation may have a style defined in which case it must be document or rpc + // and may have a soapAction uri defined + else if (parents.get(0).getClass() == BindingOperationImpl.class) + { + if (element.getClass() == SOAPOperationImpl.class) + { + validateOperation(element, parents, valInfo); + } + else + { + ExtensibilityElement e = (ExtensibilityElement)element; + valInfo.addError( + messagegenerator.getString( + _ERROR_INVALID_BINDING_OPERATION_ELEMENT, + QUOTE + e.getElementType().getLocalPart() + QUOTE), element); + } + + } + else if ( + parents.get(0).getClass() == BindingInputImpl.class || parents.get(0).getClass() == BindingOutputImpl.class) + { + // validate the SOAP body + if (element.getClass() == SOAPBodyImpl.class) + { + validateBody(element, parents, valInfo); + } + // valiate the SOAP header + else if (element.getClass() == SOAPHeaderImpl.class) + { + validateHeader(element, parents, valInfo); + } + else + { + ExtensibilityElement e = (ExtensibilityElement)element; + valInfo.addError( + messagegenerator.getString(_ERROR_INVALID_HEADER_BODY_ELEMENT, QUOTE + e.getElementType().getLocalPart() + QUOTE), element); + } + } + else if (parents.get(0).getClass() == BindingFaultImpl.class) + { + if (element.getClass() == SOAPFaultImpl.class) + { + validateFault(element, parents, valInfo); + } + else + { + ExtensibilityElement e = (ExtensibilityElement)element; + valInfo.addError( + messagegenerator.getString(_ERROR_INVALID_FAULT_ELEMENT, QUOTE + e.getElementType().getLocalPart() + QUOTE), element); + } + } + // in this case there has been a SOAP element defined that is not defined for this point in the SOAP namespace + else + { + ExtensibilityElement e = (ExtensibilityElement)element; + valInfo.addError( + messagegenerator.getString( + _ERROR_INVALID_SOAP_ELEMENT_FOR_LOCATION, + QUOTE + e.getElementType().getLocalPart() + QUOTE), element); + } + + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.wsdl11.validator.IWSDL11Validator#setResourceBundle(java.util.ResourceBundle) + */ + public void setResourceBundle(ResourceBundle rb) + { + if (messagegenerator == null) + { + messagegenerator = new MessageGenerator(rb); + } + } + + /** + * Ensure that the SOAP address has a value specified for it's uri and that the binding has a SOAP + * Binding defined. + * + * @param element The SOAP address element. + * @param parents A list of parents of the SOAP address element. + * @param valInfo The validation info for this validation. + */ + protected void validateAddress(Object element, List parents, IWSDL11ValidationInfo valInfo) + { + SOAPAddressImpl sa = (SOAPAddressImpl)element; + + String uri = sa.getLocationURI(); + if (uri == null || uri.equalsIgnoreCase(EMPTY_STRING)) + { + valInfo.addError(messagegenerator.getString(_ERROR_NO_LOCATION_FOR_ADDRESS), sa); + } + + Port port = (Port)parents.get(0); + + Binding binding = port.getBinding(); + + if (!hasSoapBinding(binding)) + { + valInfo.addError( + messagegenerator.getString( + _ERROR_NO_SOAPBINDING_FOR_ADDRESS, + QUOTE + binding.getQName().getLocalPart() + QUOTE, + QUOTE + port.getName() + QUOTE), sa); + } + } + + /** + * Ensure the SOAP Binding defined is valid. A SOAP Binding must have a style of rpc or document + * or no style defined (defaults to document.) A valid (non empty) URI must also be specified. + * + * @param element The SOAP binding element. + * @param parents A list of parents of the SOAP binding element. + * @param valInfo The validation info for this validation. + */ + protected void validateBinding(Object element, List parents, IWSDL11ValidationInfo valInfo) + { + SOAPBindingImpl sb = (SOAPBindingImpl)element; + + String style = sb.getStyle(); + String uri = sb.getTransportURI(); + + if (style != null && !style.equalsIgnoreCase(RPC) && !style.equalsIgnoreCase(DOCUMENT)) + { + valInfo.addError( + messagegenerator.getString(_ERROR_INVALID_BINDING_STYLE, QUOTE + sb.getStyle() + QUOTE), element); + } + if (uri.equalsIgnoreCase(EMPTY_STRING)) + { + valInfo.addError(messagegenerator.getString(_ERROR_INVALID_BINDING_URI), element); + } + } + + /** + * An operation may have a style defined. If it is defined it must be rpc or document. It may also have a + * uri defined which must be non empty. It may have a soapAction defined as well. + * + * @param element The SOAP operation element. + * @param parents A list of parents of the SOAP operation element. + * @param valInfo The validation info for this validation. + */ + protected void validateOperation(Object element, List parents, IWSDL11ValidationInfo valInfo) + { + SOAPOperation so = (SOAPOperation)element; + + String soapStyle = so.getStyle(); + + if (soapStyle != null && !soapStyle.equalsIgnoreCase(RPC) && !soapStyle.equalsIgnoreCase(DOCUMENT)) + { + valInfo.addError(messagegenerator.getString(_ERROR_INVALID_OPERATION_STYLE), element); + } + + Binding binding = (Binding)parents.get(1); + if (!hasSoapBinding(binding)) + { + valInfo.addError( + messagegenerator.getString(_ERROR_NO_SOAPBINDING_FOR_OPERATION, QUOTE + binding.getQName().getLocalPart() + QUOTE), so); + } + } + + /** + * Validate the SOAP body. If encoded a body must have an encodingStyle. Also, + * if specified, all of the parts listed must be defined parts and in the encoding use case, the parts + * must have types defined. + * + * @param element The SOAP body element. + * @param parents A list of parents of the SOAP body element. + * @param valInfo The validation info for this validation. + */ + protected void validateBody(Object element, List parents, IWSDL11ValidationInfo valInfo) + { + SOAPBodyImpl sb = (SOAPBodyImpl)element; + + String use = sb.getUse(); + + // if the use = encoded then there must be encodingStyles. + if (use != null && use.equalsIgnoreCase(ENCODED)) + { + List encodingStyles = sb.getEncodingStyles(); + if (encodingStyles == null || encodingStyles.size() == 0) + { + valInfo.addError(messagegenerator.getString(_ERROR_INVALID_BODY_ENCODING_STYLE), sb); + } + } + else if (use != null && !use.equalsIgnoreCase(LITERAL)) + { + valInfo.addError(messagegenerator.getString(_ERROR_INVALID_BODY_USE, QUOTE + use + QUOTE), sb); + } + + //Check that the parts are valid + // parts must be defined in the message specified for the operation + List parts = sb.getParts(); + + if (parts != null) + { + Iterator partsIterator = parts.iterator(); + while (partsIterator.hasNext()) + { + String part = (String)partsIterator.next(); + BindingOperation bo = (BindingOperation)parents.get(1); + Operation o = bo.getOperation(); + + if (o != null && !o.isUndefined()) + { + // get the message from the input or output if it exists + Message mess = null; + if (parents.get(0).getClass() == BindingInputImpl.class) + { + Input input = o.getInput(); + + if (input != null) + { + mess = input.getMessage(); + } + } + else if (parents.get(0).getClass() == BindingOutputImpl.class) + { + Output output = o.getOutput(); + + if (output != null) + { + mess = output.getMessage(); + } + } + + if (mess != null && !mess.isUndefined()) + { + Part p = mess.getPart(part); + + if (p != null) + { + // if the use is encoded the parts must all have a type defined + if (use != null && use.equalsIgnoreCase(ENCODED)) + { + if (p.getTypeName() == null) + { + // part error - part needs to be type and isn't + valInfo.addError( + messagegenerator.getString(_ERROR_INVALID_BODY_PART_NOT_TYPE, QUOTE + part + QUOTE), sb); + } + } + } + else + { + //part error - part isn't defined + valInfo.addError( + messagegenerator.getString(_ERROR_INVALID_BODY_PART_UNDEFINED, QUOTE + part + QUOTE), sb); + } + } + else + { + //part error - input isn't defined + valInfo.addError( + messagegenerator.getString(_ERROR_INVALID_BODY_PART_UNDEFINED, QUOTE + part + QUOTE), sb); + } + } + else + { + // parts error - operation isn't defined + valInfo.addError( + messagegenerator.getString(_ERROR_INVALID_BODY_PART_UNDEFINED, QUOTE + part + QUOTE), sb); + } + } + } + + Binding binding = (Binding)parents.get(2); + if (!hasSoapBinding(binding)) + { + valInfo.addError( + messagegenerator.getString(_ERROR_NO_SOAPBINDING_FOR_BODY, QUOTE + binding.getQName().getLocalPart() + QUOTE), sb); + } + } + + /** + * A SOAP header must have a message, part and use defined. If the use is encoded, must + * also have a non-empty encodingStyle and namespace defined. + * A SOAP header may have headerfaults defined as well. + * + * @param element The SOAP header element. + * @param parents A list of parents of the SOAP header element. + * @param valInfo The validation info for this validation. + */ + protected void validateHeader(Object element, List parents, IWSDL11ValidationInfo valInfo) + { + SOAPHeaderImpl soapHeader = (SOAPHeaderImpl)element; + + QName messageQName = soapHeader.getMessage(); + Message message = ((Definition)parents.get(parents.size() - 1)).getMessage(messageQName); + if (message == null) + { + // message undefined + valInfo.addError( + messagegenerator.getString(_ERROR_HEADER_MESSAGE_UNDEFINED, QUOTE + messageQName.getLocalPart() + QUOTE), soapHeader); + } + else + { + String partname = soapHeader.getPart(); + Part part = message.getPart(partname); + if (part == null) + { + // part undefined + valInfo.addError( + messagegenerator.getString( + _ERROR_HEADER_PART_UNDEFINED, + QUOTE + partname + QUOTE, + QUOTE + messageQName.getLocalPart() + QUOTE), soapHeader); + } + } + + String use = soapHeader.getUse(); + if (use != null && !use.equalsIgnoreCase(LITERAL) && !use.equalsIgnoreCase(ENCODED)) + { + // use undefined + valInfo.addError( + messagegenerator.getString(_ERROR_HEADER_USE_UNDEFINED, QUOTE + use + QUOTE), soapHeader); + } + + if (use.equalsIgnoreCase(ENCODED)) + { + List encodingStyles = soapHeader.getEncodingStyles(); + if (encodingStyles == null || encodingStyles.isEmpty()) + { + // no encodingStyle defined + valInfo.addError(messagegenerator.getString(_ERROR_HEADER_ENCODINGSTYLE_UNDEFINED), soapHeader); + } + + String namespace = soapHeader.getNamespaceURI(); + if (namespace == null || namespace.equalsIgnoreCase(EMPTY_STRING)) + { + // no namespace defined + valInfo.addError(messagegenerator.getString(_ERROR_HEADER_NAMESPACE_UNDEFINED), soapHeader); + } + } + + List headerFaults = soapHeader.getSOAPHeaderFaults(); + if (headerFaults != null) + { + Iterator iheaderFaults = headerFaults.iterator(); + while (iheaderFaults.hasNext()) + { + validateHeaderFault(iheaderFaults.next(), parents, valInfo); + } + } + + Binding binding = (Binding)parents.get(2); + if (!hasSoapBinding(binding)) + { + valInfo.addError( + messagegenerator.getString(_ERROR_NO_SOAPBINDING_FOR_HEADER, QUOTE + binding.getQName().getLocalPart() + QUOTE), soapHeader); + } + } + + /** + * A SOAP headerfault must have a message, part and use defined. If the use is encoded, must + * also have a non-empty encodingStyle and namespace defined. + * + * @param element The SOAP header fault element. + * @param parents A list of parents of the SOAP header fault element. + * @param valInfo The validation info for this validation. + */ + protected void validateHeaderFault(Object element, List parents, IWSDL11ValidationInfo valInfo) + { + SOAPHeaderFaultImpl soapHeaderFault = (SOAPHeaderFaultImpl)element; + + QName messageQName = soapHeaderFault.getMessage(); + Message message = ((Definition)parents.get(parents.size() - 1)).getMessage(messageQName); + if (message == null) + { + // message undefined + valInfo.addError( + messagegenerator.getString(_ERROR_HEADERFAULT_MESSAGE_UNDEFINED, QUOTE + messageQName.getLocalPart() + QUOTE), soapHeaderFault); + } + else + { + String partname = soapHeaderFault.getPart(); + Part part = message.getPart(partname); + if (part == null) + { + // part undefined + valInfo.addError( + messagegenerator.getString( + _ERROR_HEADERFAULT_PART_UNDEFINED, + QUOTE + partname + QUOTE, + QUOTE + messageQName.getLocalPart() + QUOTE), soapHeaderFault); + } + } + + String use = soapHeaderFault.getUse(); + if (use != null && !use.equalsIgnoreCase(LITERAL) && !use.equalsIgnoreCase(ENCODED)) + { + // use undefined + valInfo.addError( + messagegenerator.getString(_ERROR_HEADERFAULT_USE_UNDEFINED, QUOTE + use + QUOTE), soapHeaderFault); + } + + if (use.equalsIgnoreCase(ENCODED)) + { + List encodingStyles = soapHeaderFault.getEncodingStyles(); + if (encodingStyles == null || encodingStyles.isEmpty()) + { + // no encodingStyle defined + valInfo.addError( + messagegenerator.getString(_ERROR_HEADERFAULT_ENCODINGSTYLE_UNDEFINED), soapHeaderFault); + } + + String namespace = soapHeaderFault.getNamespaceURI(); + if (namespace == null || namespace.equalsIgnoreCase(EMPTY_STRING)) + { + // no namespace defined + valInfo.addError( + messagegenerator.getString(_ERROR_HEADERFAULT_NAMESPACE_UNDEFINED), soapHeaderFault); + } + } + } + + /** + * Validate the SOAP fault. A SOAP fault must have a name defined that corresponds with the name + * specified in the portType. If encoded a fault must have an encodingStyle and a namespaceURI. + * + * @param element The SOAP fault element. + * @param parents A list of parents of the SOAP fault element. + * @param validationInfo The validation info for this validation. + */ + protected void validateFault(Object element, List parents, IWSDL11ValidationInfo valInfo) + { + SOAPFaultImpl fault = (SOAPFaultImpl)element; + + String name = fault.getName(); + + String parentName = ((BindingFault)parents.get(0)).getName(); + + if (!name.equals(parentName)) + { + valInfo.addError( + messagegenerator.getString(_ERROR_INVALID_FAULT_NAME, QUOTE + name + QUOTE, QUOTE + parentName + QUOTE), fault); + } + + } + + /** + * Method hasSoapBinding. - helper Method + * Given a binding returns true if it has a SOAP binding defined. + * + * @param binding - the SOAP binding to check + * @return true if a binding has a SOAP binding defined, false otherwise + */ + protected boolean hasSoapBinding(Binding binding) + { + if (binding != null) + { + List extelems = binding.getExtensibilityElements(); + if (extelems != null) + { + Iterator iextelems = extelems.iterator(); + while (iextelems.hasNext()) + { + if (iextelems.next().getClass() == SOAPBindingImpl.class) + { + return true; + } + } + } + } + return false; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/DOMError.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/DOMError.java new file mode 100644 index 000000000..329b1118b --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/DOMError.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2005 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.xsd; + +/** + * This interface is used to signify error levels that are the result of + * XMLParseException. They conceptually correspond to org.w3c.dom.DOMError but + * we use our own interface, since DOMError is not in Java 1.4, and its + * package changes from Xerces 2.6.2 and Xerces 2.7.0. + */ + +public interface DOMError { + int SEVERITY_WARNING = 1; + int SEVERITY_ERROR = 2; + int SEVERITY_FATAL_ERROR = 3; +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/FileEntityResolver.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/FileEntityResolver.java new file mode 100644 index 000000000..2119778f3 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/FileEntityResolver.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * 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.xsd; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.eclipse.wst.wsdl.validation.internal.util.LazyURLInputStream; + +/** + * Entity resolve to resolve file entities. + */ +public class FileEntityResolver implements XMLEntityResolver +{ + + /** + * @see org.apache.xerces.xni.parser.XMLEntityResolver#resolveEntity(org.apache.xerces.xni.XMLResourceIdentifier) + */ + public XMLInputSource resolveEntity(XMLResourceIdentifier resource) throws XNIException, IOException + { + String publicId = resource.getPublicId(); + String systemId = resource.getExpandedSystemId(); + String namespace = resource.getNamespace(); + String url = null; + if(systemId != null) + { + url = systemId; + } + else if(publicId != null) + { + url = publicId; + } + else if(namespace != null) + { + url = namespace; + } + if(url != null) + { + InputStream is = new LazyURLInputStream(url); + return new XMLInputSource(publicId, resource.getExpandedSystemId(), resource.getExpandedSystemId(), is, null); + } + return null; + } + +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/InlineSchemaGenerator.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/InlineSchemaGenerator.java new file mode 100644 index 000000000..1792ec172 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/InlineSchemaGenerator.java @@ -0,0 +1,667 @@ +/******************************************************************************* + * 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.xsd; + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.Vector; + +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import com.ibm.wsdl.Constants; + +/** + * Generate a String representation of a schema for an inline schema. Will add imports for unresolved + * namespaces. + */ +public class InlineSchemaGenerator +{ + protected static final String SOAP_ENCODING_URI = "http://schemas.xmlsoap.org/soap/encoding/"; + protected static final String FILE_PREFIX = "file:///"; + protected static final String XMLNS = "xmlns"; + protected static final String TARGETNAMESPACE = "targetNamespace"; + protected static final String NAMESPACE = "namespace"; + protected static final String IMPORT = "import"; + protected static final String INCLUDE = "include"; + protected static final String SCHEMA = "schema"; + protected static final String SCHEMALOCATION = "schemaLocation"; + protected static final String TYPE = "type"; + protected static final String NAME = "name"; + protected static final String[] ignoreNamespaces = + { Constants.NS_URI_XSD_1999, Constants.NS_URI_XSD_2000, Constants.NS_URI_XSD_2001 }; + + protected static InlineSchemaGenerator instance = null; + + /** + * Constructor. + */ + protected InlineSchemaGenerator() + { + } + + /** + * Get the instance of the InlineSchemaGenerator. + * + * @return The instance of the inline schema generator. + */ + protected static InlineSchemaGenerator getInstance() + { + if (instance == null) + { + instance = new InlineSchemaGenerator(); + } + return instance; + } + + /** + * Create a string representation of a schema from the element provided. + * + * @param element The root element of the schema. + * @param elements A list of the elements in the schema in order. + * @param filelocation The URI of the file that contains the schema. + * @param validImportNSs A set of namespaces for which it's valid to create import statements. + * @return A string representation of a schema. + */ + public static String createXSDString(Element element, List elements, String filelocation, Set validImportNSs) + { + return InlineSchemaGenerator.createXSDString(element, elements, filelocation, new Hashtable(), validImportNSs); + } + + /** + * Creates a String representing the schema model with the root element of + * extElem. Calls createXSDStringRecursively to take care of building the String + * after it obtains the Element from the UnknownExtensibilityElement. + * + * @param element The root element of the schema. + * @param elements A list to contain the elements in the schema in order. + * @param filelocation The location of the file the schema is located in. + * @param parentNSs A hashtable of parent namespaces to used to resolve prefixes. + * @param validImportNSs A set of namespaces for which it's valid to create import statements. + * @return A string representation of the schema with the root element 'element'. + */ + public static String createXSDString(Element element, List elements, String filelocation, Hashtable parentNSs, Set validImportNSs) + { + Set importNSs = new TreeSet(); + importNSs.addAll(validImportNSs); + importNSs.add(SOAP_ENCODING_URI); + + InlineSchemaGenerator schemaGenerator = InlineSchemaGenerator.getInstance(); + Hashtable nsResolver = schemaGenerator.getNSResolver(element); + List reqns = schemaGenerator.getNamespacePrefixes(element); + Hashtable reqNSDecl = schemaGenerator.resolveNamespaces(reqns, nsResolver, parentNSs); + //Hashtable reqNSDecl = schemaGenerator.getRequiredNSDeclarations(reqns, nsResolver, parentNSs); + List importNS = schemaGenerator.getImportNamespaces(element); + reqns = schemaGenerator.removeImports(reqns, importNS); + reqns = schemaGenerator.removeLocalNamespaces(reqns, element); + reqns = schemaGenerator.restrictImports(reqns, validImportNSs); + return schemaGenerator.createXSDStringRecursively(element, elements, reqns, reqNSDecl, filelocation); + } + /** + * Returns true if the SOAP encoding namespace is required but not imported. + * + * @param element The root element of the schema. + * @param filelocation The location of the file containing the schema. + * @param parentNSs A hashtable of the parent namespaces. + * @return True if the soap encoding namespace is required but not imported, false otherwise. + */ + public static boolean soapEncodingRequiredNotImported(Element element, String filelocation, Hashtable parentNSs) + { + InlineSchemaGenerator schemaGenerator = InlineSchemaGenerator.getInstance(); + Hashtable nsResolver = schemaGenerator.getNSResolver(element); + List reqns = null; + + reqns = schemaGenerator.getNamespacePrefixes(element); + schemaGenerator.resolveNamespaces(reqns, nsResolver, parentNSs); + //schemaGenerator.resolveUndeclaredNamespaces(reqns, parentNSs); + List importNS = schemaGenerator.getImportNamespaces(element); + reqns = schemaGenerator.removeImports(reqns, importNS); + reqns = schemaGenerator.removeLocalNamespaces(reqns, element); + return schemaGenerator.checkSOAPEncodingRequired(reqns); + } + /** + * Resolve the undeclared namespaces. + * + * @param unresolvedNSs A list of unresolved namespaces. + * @param nsResolver The namespace resolver to use. + * @return A hashtable of prefixes and namespaces. + */ +// protected Hashtable resolveUndeclaredNamespaces(List unresolvedNSs, Hashtable nsResolver) +// { +// Hashtable namespaces = new Hashtable(); +// if (unresolvedNSs != null && !unresolvedNSs.isEmpty() && nsResolver != null) +// { +// for (int i = unresolvedNSs.size() - 1; i >= 0; i--) +// { +// String ns = (String)unresolvedNSs.get(i); +// if (ns.equals("")) +// { +// ns = XMLNS; +// } +// else +// { +// ns = XMLNS + ":" + ns; +// } +// if (nsResolver.containsKey(ns)) +// { +// //namespaces.remove(i); +// //namespaces.add(i, nsResolver.get(ns)); +// namespaces.put(ns, nsResolver.get(ns)); +// unresolvedNSs.remove(i); +// unresolvedNSs.add(i, nsResolver.get(ns)); +// } +// } +// } +// return namespaces; +// } + + /** + * This recursive method creates the schema String from the root Element. + * + * @param elem The root element of the schema. + * @param elements A list to be created of the elements in the schema in order. + * @param requiredNamespaces A list of required namespaces. + * @param reqNSDecl A hashtable of required namespace declarations. + * @param filelocation The uri of the file that contains this schema. + * @return A string representation of this schema. + */ + protected String createXSDStringRecursively( + Element elem, + List elements, + List requiredNamespaces, + Hashtable reqNSDecl, + String filelocation) + { + if (elem == null) + return ""; // just in case + + elements.add(elem); + + StringBuffer xsdString = new StringBuffer(); + String elementName = elem.getTagName(); + xsdString.append("<").append(elementName); + + boolean foundSchemaLocation = false; // flag if schemalocation is defined + String namespace = ""; // the namespace if we're checking an import or include + String namePrefix = ""; // the xmlns prefix used for the elements + // Get all of the attributes for this element and append them to the xsdString + NamedNodeMap atts = elem.getAttributes(); + for (int i = 0; i < atts.getLength(); i++) + { + Node n = atts.item(i); + xsdString.append(" ").append(n.getNodeName()).append("=\""); + String nodeName = n.getNodeName(); + if (nodeName.equalsIgnoreCase(SCHEMALOCATION) && filelocation != null) + { + foundSchemaLocation = true; + String relativePath = n.getNodeValue(); + xsdString.append(relativePath).append("\""); + } + else + { + String nodeValue = n.getNodeValue(); + if (nodeName.equalsIgnoreCase(NAMESPACE)) + { + namespace = nodeValue; + } + // get the name prefix for this schema to use in generating import statements + else if (nodeName.indexOf(XMLNS) != -1) + { + + if (nodeValue.equalsIgnoreCase(elem.getNamespaceURI())) + { + namePrefix = nodeName; + if (namePrefix.equalsIgnoreCase(XMLNS)) + { + namePrefix = ""; + } + else + { + namePrefix = namePrefix.substring(6) + ":"; + } + } + } + // Replace old schema namespaces with the new schema namespace. + if(nodeValue.equals(Constants.NS_URI_XSD_1999) || nodeValue.equals(Constants.NS_URI_XSD_2000)) + { + nodeValue = Constants.NS_URI_XSD_2001; + } + xsdString.append(nodeValue).append("\""); + } + } + if (elementName.equalsIgnoreCase("import") && !foundSchemaLocation) + { + xsdString.append(" ").append(SCHEMALOCATION).append("=\"").append(namespace).append("\""); + } + // add in any required NS declarations from parent elements + if (reqNSDecl != null) + { + Enumeration keys = reqNSDecl.keys(); + while (keys.hasMoreElements()) + { + String key = (String)keys.nextElement(); + String declNS = (String)reqNSDecl.get(key); + if(declNS.equals(Constants.NS_URI_XSD_1999) || declNS.equals(Constants.NS_URI_XSD_2000)) + { + declNS = Constants.NS_URI_XSD_2001; + } + xsdString.append(" ").append(key).append("=\"").append(declNS).append("\""); + } + + } + xsdString.append(">"); + if (requiredNamespaces != null) + { + Iterator iRequiredNamespaces = requiredNamespaces.iterator(); + while (iRequiredNamespaces.hasNext()) + { + String ns = (String)iRequiredNamespaces.next(); + + xsdString + .append("<") + .append(namePrefix) + .append(IMPORT) + .append(" ") + .append(NAMESPACE) + .append("=\"") + .append(ns) + .append("\" ") + .append(SCHEMALOCATION) + .append("=\"") + .append(ns) + .append("\"/>"); + } + + } + xsdString.append("\n"); + + // call the method recursively for each child element + NodeList childNodes = elem.getChildNodes(); + + for (int i = 0; i < childNodes.getLength() || i < 5; i++) + { + Node n = childNodes.item(i); + // we only want nodes that are Elements + if (n instanceof Element) + { + Element child = (Element)n; + xsdString.append(createXSDStringRecursively(child, elements, null, null, filelocation)); + } + } + + xsdString.append("</").append(elem.getTagName()).append(">"); + + return xsdString.toString(); + + } + /** + * Get a list of all the namespace prefixes that are used for elements or types in the schema. + * + * @param elem The root element of the schema to check for namespace prefixes. + * @return A list of namespace prefixes for the element and all its children. + */ + protected List getNamespacePrefixes(Element elem) + { + List namespace = new ArrayList(); + + // call the method recursively for each child element + // register all the child types first + NodeList childNodes = elem.getChildNodes(); + int numChildren = childNodes.getLength(); + for (int i = 0; i < numChildren; i++) + { + Node n = childNodes.item(i); + // we only want nodes that are Elements + if (n instanceof Element) + { + Element child = (Element)n; + List childns = getNamespacePrefixes(child); + for (int j = childns.size() - 1; j >= 0; j--) + { + String ns = (String)childns.get(j); + + if (!namespace.contains(ns)) + { + namespace.add(ns); + } + } + } + } + // Add the namespace of the current element + String elemNS = elem.getPrefix(); + // if there is no namespace prefix set it to the empty prefix. + if(elemNS == null) + { + elemNS = ""; + } + if (!namespace.contains(elemNS)) + { + namespace.add(elemNS); + } + // now add all of the current element's namespaces + // don't include import and schema elements + String localname = elem.getLocalName(); + if (!localname.equals(IMPORT) && !localname.equals(INCLUDE) && !localname.equals(SCHEMA)) + { + NamedNodeMap atts = elem.getAttributes(); + for (int i = 0; i < atts.getLength(); i++) + { + Node n = atts.item(i); + + String nodeName = n.getNodeName(); + // removed restriction that we're only looking at types + // if (nodeName.equalsIgnoreCase(TYPE)) + // { + // don't take namespace info from attributes defining namespaces. + // that includes xmlns, targetNamespace + if (nodeName.indexOf(XMLNS) != -1 || nodeName.equals(TARGETNAMESPACE) || nodeName.equals(NAME)) + { + continue; + } + // Grab namespace prefixes from attributes. + else + { + int colonIndex = nodeName.indexOf(":"); + if(colonIndex != -1 && (colonIndex + 1 < nodeName.length() && nodeName.charAt(colonIndex + 1) != '/')) + { + String prefix = nodeName.substring(0, colonIndex); + if (!namespace.contains(prefix)) + { + + namespace.add(prefix); + } + } + } + String nodeValue = n.getNodeValue(); + + + int colonIndex = nodeValue.indexOf(":"); + // Don't take namespace info from attributes with the default namespace, that is attributes + // that are not prefixed. (colonIndex == -1) + // If the colonIndex is followed by a / then it is a URI and not + // namespace qualified. + if (colonIndex == -1 || (colonIndex + 1 < nodeValue.length() && nodeValue.charAt(colonIndex + 1) == '/')) + { + continue; + } + // here we have found a colon delimiter so we need the namespace defined here + else + { + nodeValue = nodeValue.substring(0, colonIndex); + } + if (!namespace.contains(nodeValue)) + { + + namespace.add(nodeValue); + } + } + } + + return namespace; + + } + + /** + * Get a list of all the namespaces that have an import statement. + * + * @param elem The root element of the schema. + * @return A list of all the namespaces that are imported. + */ + protected List getImportNamespaces(Element elem) + { + List namespace = new Vector(); + + // call the method recursively for each child element + // register all the child types first + NodeList childNodes = elem.getChildNodes(); + + for (int i = 0; i < childNodes.getLength() || i < 5; i++) + { + Node n = childNodes.item(i); + // we only want nodes that are Elements + if (n instanceof Element) + { + Element child = (Element)n; + List childns = getImportNamespaces(child); + for (int j = childns.size() - 1; j >= 0; j--) + { + String ns = (String)childns.get(j); + if (!namespace.contains(ns)) + { + namespace.add(ns); + } + } + } + } + // if this is an import element get the namespace and add it to the list + if (elem.getLocalName().equalsIgnoreCase(IMPORT)) + { + NamedNodeMap atts = elem.getAttributes(); + for (int i = 0; i < atts.getLength(); i++) + { + Node n = atts.item(i); + + String nodeName = n.getNodeName(); + if (nodeName.equalsIgnoreCase(NAMESPACE)) + { + String nodeValue = n.getNodeValue(); + if (!namespace.contains(nodeValue)) + { + + namespace.add(nodeValue); + } + } + } + } + + return namespace; + + } + + /** + * Return a Hashtable with namespace prefixes as keys from the given element. + * + * @param elem The root element of the schema. + * @return A hashtable with namespace prefixes mapped to namespaces. + */ + protected Hashtable getNSResolver(Element elem) + { + Hashtable nsResolver = new Hashtable(); + + NamedNodeMap atts = elem.getAttributes(); + for (int i = 0; i < atts.getLength(); i++) + { + Node n = atts.item(i); + + String nodeName = n.getNodeName(); + if (nodeName.indexOf(XMLNS) != -1) + { + String nodeValue = n.getNodeValue(); + String namePrefix = nodeName; + + if (namePrefix.equalsIgnoreCase(XMLNS)) + { + namePrefix = ""; + } + else + { + namePrefix = namePrefix.substring(6); + } + nsResolver.put(namePrefix, nodeValue); + + } + } + return nsResolver; + + } + + /** + * Resolve the namespaces in the given namespaces list with the two namespace + * resolver hashtables provided. Return a list of all the namespace that need + * to be declared. + * First resolve against the local namespaces with nsResolver. + * Next resolve against the parent namespace with parentNSResolver. + * A side affect of this method is the namespaces list is left with only those + * namespaces that are resolved and the resolved entities are placed in the + * list instead of the original entries. + * For ex. If you provide a list such as {xsd, intf} and only xsd can be resolved + * you will end up with the list {http://www.w3.org/2001/XMLSchema} + * + * @param namespaces The list of namespaces to resolve. + * @param nsResolver The hashtable to be used as the local resolver. + * @param parentNSResolver The hashtable to be used as the parent namespace resolver. + * @return A Hashtable of namespaces that must be declared. + */ + protected Hashtable resolveNamespaces(List namespaces, Hashtable nsResolver, Hashtable parentNSResolver) + { + Hashtable reqNSDecl = new Hashtable(); + if (namespaces != null && !namespaces.isEmpty() && nsResolver != null) + { + for (int i = namespaces.size() - 1; i >= 0; i--) + { + String ns = (String)namespaces.get(i); + // Remove the namespace from the list. + namespaces.remove(i); + // First try to resolve against the local namespace resolver. + if (nsResolver.containsKey(ns)) + { + Object resolvedNS = nsResolver.get(ns); + // Only add the namespace if it's not already in the list. + if(!namespaces.contains(resolvedNS)) + { + namespaces.add(i, nsResolver.get(ns)); + } + } + // Next try to resolve against the parent namespace resolver. + else + { + if (ns.equals("")) + { + ns = XMLNS; + } + else + { + ns = XMLNS + ":" + ns; + } + if (parentNSResolver.containsKey(ns)) + { + Object resolvedNS = parentNSResolver.get(ns); + // Only add the namespace if it's not already in the list. + if(!namespaces.contains(resolvedNS)) + { + namespaces.add(i, resolvedNS); + } + // Still need to declare the namespace though. + reqNSDecl.put(ns, resolvedNS); + } + } + + } + } + return reqNSDecl; + } + + /** + * Remove any namespace from the namespaces list if it is in the import list. + * + * @param namespaces The namespaces list. + * @param importedNamespaces A list of imported namespaces. + * @return The list of namespaces without the imported namespaces. + */ + protected List removeImports(List namespaces, List importedNamespaces) + { + if (namespaces != null && importedNamespaces != null && !importedNamespaces.isEmpty()) + { + Iterator iImportedNS = importedNamespaces.iterator(); + while (iImportedNS.hasNext()) + { + String iNS = (String)iImportedNS.next(); + + namespaces.remove(iNS); + } + } + return namespaces; + } + + /** + * Remove the local namespace for the schema and the namespaces listed in the ignoreNamespaces + * list from the namespaces list provided. + * + * @param namespaces The list of local namespaces. + * @param elem The root element of the schema. + * @return The list of namespaces with the local namespaces removed. + */ + protected List removeLocalNamespaces(List namespaces, Element elem) + { + if (namespaces != null && elem != null) + { + String ns = elem.getAttribute(TARGETNAMESPACE); + namespaces.remove(ns); + + for (int i = ignoreNamespaces.length - 1; i >= 0; i--) + { + // keep removing the namespace until it is not in the list + if (namespaces.remove(ignoreNamespaces[i])) + { + i++; + } + } + } + return namespaces; + } + + /** + * Remove all the namespaces in the namespaces list that aren't contained in the + * validImportNSs set. + * + * @param namespaces A list of namespaces. + * @param validImportNSs A set of valid namespaces. + * @return A list of namespaces that does not contain any members which aren't in the validImportNSs set. + */ + protected List restrictImports(List namespaces, Set validImportNSs) + { + Iterator nsIter = namespaces.iterator(); + while(nsIter.hasNext()) + { + String ns = (String)nsIter.next(); + if(!validImportNSs.contains(ns)) + { + namespaces.remove(ns); + nsIter = namespaces.iterator(); + } + } + return namespaces; + } + + /** + * Returns true if the SOAP encoding namespace is in the list of required namespaces, + * false otherwise. + * + * @param reqns The list of namespaces to check for the SOAP encoding namespace. + * @return True if the SOAP encoding namespaces is in the list, false otherwise. + */ + protected boolean checkSOAPEncodingRequired(List reqns) + { + if (reqns.contains(SOAP_ENCODING_URI)) + { + return true; + } + return false; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/InlineSchemaValidator.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/InlineSchemaValidator.java new file mode 100644 index 000000000..5b58f211c --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/InlineSchemaValidator.java @@ -0,0 +1,300 @@ +/******************************************************************************* + * 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.xsd; + +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.TreeSet; + +import javax.wsdl.Definition; +import javax.wsdl.Types; +import javax.wsdl.extensions.UnknownExtensibilityElement; + +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xs.XSModel; +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.IWSDL11Validator; +import org.eclipse.wst.wsdl.validation.internal.wsdl11.IWSDL11ValidationInfo; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +import com.ibm.wsdl.Constants; + +/** + * Plugin validator for the WSDL Validation framework. Validates inline schema found in a WSDL document. + */ +public class InlineSchemaValidator implements IWSDL11Validator +{ + private final String _WARN_OLD_SCHEMA_NAMESPACE = "_WARN_OLD_SCHEMA_NAMESPACE"; + private final String _WARN_SOAPENC_IMPORTED_SCHEMA = "_WARN_SOAPENC_IMPORTED_SCHEMA"; + private final String EMPTY_STRING = ""; + private final String QUOTE = "'"; + MessageGenerator messagegenerator = null; + + /** + * @see org.eclipse.wst.wsdl.validation.internal.wsdl11.IWSDL11Validator#validate(java.lang.Object, java.util.List, org.eclipse.wsdl.validate.wsdl11.WSDL11ValidationInfo) + */ + public void validate(Object element, List parents, IWSDL11ValidationInfo valInfo) + { + List elements = new ArrayList(); + UnknownExtensibilityElement elem = (UnknownExtensibilityElement) element; + Definition wsdlDefinition = (Definition) parents.get(parents.size() - 1); + String baseLocation = wsdlDefinition.getDocumentBaseURI(); + // Add in the namespaces defined in the doc already that aren't defined locally in this schema. + // There is no need to check for namespaces other then in the defintions and types elements as + // inline schema can not have any other parents and must have there two parents. + // First take care of the definitions element + + // create the inline schema string + Element w3celement = elem.getElement(); + Hashtable parentnamespaces = getNamespaceDeclarationsFromParents(wsdlDefinition,w3celement); + String targetNamespace = w3celement.getAttribute(Constants.ATTR_TARGET_NAMESPACE); + // if the targetNamespace hasn't been defined for the schema use the + // targetNamespace of the definitions element + if(targetNamespace == null || targetNamespace.equals(EMPTY_STRING)) + { + targetNamespace = wsdlDefinition.getTargetNamespace(); + w3celement.setAttribute(Constants.ATTR_TARGET_NAMESPACE,targetNamespace); + } + + // If the namespace given is one of the old schema namespaces produce a warning. + String namespace = w3celement.getNamespaceURI(); + if(namespace.equals(Constants.NS_URI_XSD_1999) || namespace.equals(Constants.NS_URI_XSD_2000)) + { + valInfo.addWarning( + messagegenerator.getString(_WARN_OLD_SCHEMA_NAMESPACE, QUOTE + Constants.NS_URI_XSD_2001 + QUOTE), element); + } + + // now create and call the validator for the inline schema + XSDValidator schemav = new XSDValidator(); + + //String fileLocation = new URL(validatormanager.getFilename()).getPath(); + InlineXSDResolver inlineEntityResolver = + getEntityResolver(wsdlDefinition, (Types) parents.get(0), baseLocation, targetNamespace); + // add in the external XSD Catalog to resolve schemas offline + XMLEntityResolverChain entityResolverChain = new XMLEntityResolverChain(); + entityResolverChain.addEntityResolver(inlineEntityResolver); + entityResolverChain.addEntityResolver((XMLEntityResolver)valInfo.getURIResolver()); + //entityResolverChain.addEntityResolver(XMLCatalogResolver.getInstance()); + entityResolverChain.addEntityResolver(new FileEntityResolver()); + + // Create the string representation of the inline schema. + String xsd = InlineSchemaGenerator.createXSDString(w3celement, elements, baseLocation, parentnamespaces, inlineEntityResolver.getInlineSchemaNSs()); + + + schemav.validateInlineSchema(xsd, targetNamespace, baseLocation, entityResolverChain, inlineEntityResolver); + +// check if the SOAP Encoding namespace is required but not imported + if (InlineSchemaGenerator.soapEncodingRequiredNotImported(elem.getElement(), baseLocation, parentnamespaces)) + { + valInfo.addWarning(messagegenerator.getString(_WARN_SOAPENC_IMPORTED_SCHEMA), element); + } + + // If the schema isn't valid add the error messages produced to valinfo. + // Don't add the errors if they are located on another inline schema. These + // will be reported when the other schema is validated. + + if (!schemav.isValid()) + { + Iterator errors = schemav.getErrors().iterator(); + while (errors.hasNext()) + { + ErrorMessage err = (ErrorMessage) errors.next(); + String uri = err.getURI(); + int line = err.getErrorLine(); + String errmess = err.getErrorMessage(); + errmess = replaceNamespace(errmess, namespace); + if(line > 0) + { + if(uri == null || uri.equals(valInfo.getFileURI())) + { + valInfo.addError(errmess, getObjectAtLine(line - 1, elements)); + } + else if(!inlineEntityResolver.isInlineSchema(uri) && !uri.equals(valInfo.getFileURI() + InlineXSDResolver.INLINE_SCHEMA_ID)) + { + valInfo.addError(errmess, line, err.getErrorColumn(), uri); + } + } + else if(uri != null && !inlineEntityResolver.isInlineSchema(uri) && !uri.equals(valInfo.getFileURI() + InlineXSDResolver.INLINE_SCHEMA_ID)) + { + valInfo.addError(errmess, 0,0, uri); + } + } + } + // if the schema is valid, assign the model to the validatormanager + else + { + XSModel xsModel = schemav.getXSModel(); + valInfo.addSchema(xsModel); + } + } + + /** + * Get an entity resolver that will resolve inline schemas. Every inline schema is preregistered with + * the resolver. + * + * @param wsdlDefinition The WSDL definitions element. + * @param types The types element. + * @param referenceLocation The location of the file that contains this schema. + * @param targetNamespace The targetNamespace of the schema. + * @return An entity resolver that can resolve inline schemas. + */ + protected InlineXSDResolver getEntityResolver(Definition wsdlDefinition, Types types, String referenceLocation, String targetNamespace) + { + InlineXSDResolver entityResolver = new InlineXSDResolver(); +// entityResolver.setReferenceLocation(referenceLocation); + List schemas = types.getExtensibilityElements(); + if (schemas != null) + { + Iterator iSchemas = schemas.iterator(); + Set namespaces = new TreeSet(); + while (iSchemas.hasNext()) + { + UnknownExtensibilityElement extElem = (UnknownExtensibilityElement) iSchemas.next(); + String thisNamespace = extElem.getElement().getAttribute(Constants.ATTR_TARGET_NAMESPACE); + if(thisNamespace != null) + { + namespaces.add(thisNamespace); + } + } + iSchemas = schemas.iterator(); + + while (iSchemas.hasNext()) + { + UnknownExtensibilityElement extElem = (UnknownExtensibilityElement) iSchemas.next(); + String thisNamespace = extElem.getElement().getAttribute(Constants.ATTR_TARGET_NAMESPACE); + if (thisNamespace != null && !thisNamespace.equalsIgnoreCase(targetNamespace)) + { + + Element element = extElem.getElement(); + +// create the inline schema string + //Element w3celement = elem.getElement(); + Hashtable parentnamespaces = getNamespaceDeclarationsFromParents(wsdlDefinition,element); + String xsd = InlineSchemaGenerator.createXSDString(element, new ArrayList(), referenceLocation, parentnamespaces, namespaces); + //addNamespaceDeclarationsFromParents(wsdlDefinition,element); + entityResolver.add(thisNamespace, xsd); + } + + } + } + return entityResolver; + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.wsdl11.validator.IWSDL11Validator#setResourceBundle(java.util.ResourceBundle) + */ + public void setResourceBundle(ResourceBundle rb) + { + messagegenerator = new MessageGenerator(rb); + } + + public void setMessageGenerator(MessageGenerator messgen) + { + messagegenerator = messgen; + } + + /** + * Get the namespace declarations as in the form + * xmlns="somenamespace" + * from the definitions and types elements and add them to the schema element so the schema + * validator will have access to them. + * + * @param wsdlDefinition The WSDL definitions element. + * @param element The types element. + * @return A hashtable with the namespace elements from the elements provided. + */ + protected Hashtable getNamespaceDeclarationsFromParents(Definition wsdlDefinition, Element element) + { + Hashtable nss = new Hashtable(); + Iterator nameSpaces = wsdlDefinition.getNamespaces().keySet().iterator(); + + String XMLNS = Constants.ATTR_XMLNS; + + String schemaLocation = ""; + while (nameSpaces.hasNext()) + { + String nsprefix = XMLNS; + String ns = (String) nameSpaces.next(); + if (!ns.equalsIgnoreCase("")) + { + nsprefix += ":"; + } + if (!element.hasAttribute(nsprefix + ns)) + { + nss.put(nsprefix + ns, wsdlDefinition.getNamespace(ns)); +// element.setAttribute(nsprefix + ns, wsdlDefinition.getNamespace(ns)); + } + + } + // Next handle the parent types element + NamedNodeMap atts = element.getParentNode().getAttributes(); + int attslength = atts.getLength(); + for (int i = 0; i < attslength; i++) + { + Node tempnode = atts.item(i); + String nodename = tempnode.getNodeName(); + // if this is a namespace attribute + if (nodename.indexOf(XMLNS) != -1) + { + nss.put(nodename, tempnode.getNodeValue()); + //element.setAttribute(nodename, tempnode.getNodeValue()); + } + } + return nss; + } + + /** + * Given a line number for the schema returns the element found on that line. + * Useful for obtaining elements from schema Strings. + * + * @param line The line number for the schema. + * @param elements The list of elements to check. + * @return The object located at the line or at line 0 if the line is invalid. + */ + protected Object getObjectAtLine(int line, List elements) + { + if(line < 0 || line >= elements.size()) + { + line = 0; + } + return elements.get(line); + } + + /** + * Replace any instance of the 2001 schema namespace in the given message with + * the given namespace. + * + * @param message The message to replace the namespace in. + * @param namespace The namespace used for replacement. + * @return The message with the 2001 schema namespace replaced by the given namespace. + */ + private String replaceNamespace(String message, String namespace) + { + String xsd2001 = Constants.NS_URI_XSD_2001; + int start = message.indexOf(xsd2001); + int end = start + xsd2001.length(); + if(start < 0) + { + return message; + } + String startString = message.substring(0,start); + String endString = message.substring(end,message.length()); + return startString + namespace + endString; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/InlineXSDResolver.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/InlineXSDResolver.java new file mode 100644 index 000000000..5f87b3951 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/InlineXSDResolver.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * 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.xsd; + +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.util.Hashtable; +import java.util.Set; + +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLInputSource; + +/** + * An XMLEntityResolver that allows inline schemas to resolve each other through imports. + */ +public class InlineXSDResolver implements XMLEntityResolver +{ + public static final String INLINE_SCHEMA_ID = "#inlineschema"; + protected final String FILE_PREFIX = "file:"; + protected final String XMLNS = "xmlns"; + protected Hashtable entities = new Hashtable(); +// protected String refLocation = null; + protected XMLEntityResolver externalResolver = null; + protected XMLInputSource referringSchemaInputSource = null; + protected String referringSchemaNamespace = null; + + /** + * Constuctor. + */ + public InlineXSDResolver() + { + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.parser.XMLEntityResolver#resolveEntity(org.apache.xerces.xni.XMLResourceIdentifier) + */ + public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) + throws XNIException, IOException { + String systemId = resourceIdentifier.getExpandedSystemId(); + String publicId = resourceIdentifier.getPublicId(); + String namespace = resourceIdentifier.getNamespace(); + XMLInputSource is = null; + Reader reader = null; + String schema = null; + if (systemId == null) + { + if(publicId == null) + { + if(namespace == null) + { + return null; + } + else + { + systemId = namespace; + } + } + else + { + systemId = publicId; + } + } + + if(referringSchemaNamespace != null && referringSchemaNamespace.equals(systemId)) + { + if(referringSchemaInputSource!=null) + { + return referringSchemaInputSource; + } + } + else if ((schema = (String) entities.get(systemId)) != null && !schema.equals("")) + { + is = new XMLInputSource(publicId, referringSchemaInputSource.getSystemId() + INLINE_SCHEMA_ID, null, new StringReader(schema),null); + } + + //if(is == null) + //{ + // throw new IOException(); + //} + return is; + } + + /** + * Add an inline schema. + * + * @param targetNamespace - the target namespace of the schema + * @param schema - a string representation of the schema + */ + public void add(String targetNamespace, String schema) + { + entities.put(targetNamespace, schema); + } + + /** + * Add the referring inline schema. + * + * @param inputSource - a representation of the inline schema + * @param namespace - the namespace of the inline schema + */ + public void addReferringSchema(XMLInputSource inputSource, String namespace) + { + referringSchemaInputSource = inputSource; + referringSchemaNamespace = namespace; + } + + /** + * Return true if the namespace corresponds to an inline schema, false otherwise. + * + * @param namespace The namespace of the schema. + * @return True if the namespace corresponds to an inline schema, false otherwise. + */ + public boolean isInlineSchema(String namespace) + { + return entities.containsKey(namespace); + } + + /** + * Get the set of the inline schema namespaces. + * + * @return The set of the inline schema namespaces. + */ + public Set getInlineSchemaNSs() + { + return entities.keySet(); + } + +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/SchemaAttributeTable.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/SchemaAttributeTable.java new file mode 100644 index 000000000..fe43e121c --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/SchemaAttributeTable.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * 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.xsd; + +import org.apache.xerces.impl.xs.SchemaSymbols; +import org.apache.xerces.util.SymbolTable; +/** + * This class will allow the calling code to see if the attribute is defined in schema. + * This serves as schema for schema. + */ +public class SchemaAttributeTable extends SymbolTable +{ + + /** + * Constructor. + */ + public SchemaAttributeTable() + { + // add all of the sybols to the table. SchemaSymbols probably should have + // a SymbolTable for these but it doesn't + + super.addSymbol(SchemaSymbols.ATTVAL_TWOPOUNDANY); + super.addSymbol(SchemaSymbols.ATTVAL_TWOPOUNDLOCAL); + super.addSymbol(SchemaSymbols.ATTVAL_TWOPOUNDOTHER); + super.addSymbol(SchemaSymbols.ATTVAL_TWOPOUNDTARGETNS); + super.addSymbol(SchemaSymbols.ATTVAL_POUNDALL); + super.addSymbol(SchemaSymbols.ATTVAL_FALSE_0); + super.addSymbol(SchemaSymbols.ATTVAL_TRUE_1); + super.addSymbol(SchemaSymbols.ATTVAL_ANYSIMPLETYPE); + super.addSymbol(SchemaSymbols.ATTVAL_ANYTYPE); + super.addSymbol(SchemaSymbols.ATTVAL_ANYURI); + super.addSymbol(SchemaSymbols.ATTVAL_BASE64BINARY); + super.addSymbol(SchemaSymbols.ATTVAL_BOOLEAN); + super.addSymbol(SchemaSymbols.ATTVAL_BYTE); + super.addSymbol(SchemaSymbols.ATTVAL_COLLAPSE); + super.addSymbol(SchemaSymbols.ATTVAL_DATE); + super.addSymbol(SchemaSymbols.ATTVAL_DATETIME); + super.addSymbol(SchemaSymbols.ATTVAL_DAY); + super.addSymbol(SchemaSymbols.ATTVAL_DECIMAL); + super.addSymbol(SchemaSymbols.ATTVAL_DOUBLE); + super.addSymbol(SchemaSymbols.ATTVAL_DURATION); + super.addSymbol(SchemaSymbols.ATTVAL_ENTITY); + super.addSymbol(SchemaSymbols.ATTVAL_ENTITIES); + super.addSymbol(SchemaSymbols.ATTVAL_EXTENSION); + super.addSymbol(SchemaSymbols.ATTVAL_FALSE); + super.addSymbol(SchemaSymbols.ATTVAL_FLOAT); + super.addSymbol(SchemaSymbols.ATTVAL_HEXBINARY); + super.addSymbol(SchemaSymbols.ATTVAL_ID); + super.addSymbol(SchemaSymbols.ATTVAL_IDREF); + super.addSymbol(SchemaSymbols.ATTVAL_IDREFS); + super.addSymbol(SchemaSymbols.ATTVAL_INT); + super.addSymbol(SchemaSymbols.ATTVAL_INTEGER); + super.addSymbol(SchemaSymbols.ATTVAL_LANGUAGE); + super.addSymbol(SchemaSymbols.ATTVAL_LAX); + super.addSymbol(SchemaSymbols.ATTVAL_LIST); + super.addSymbol(SchemaSymbols.ATTVAL_LONG); + super.addSymbol(SchemaSymbols.ATTVAL_NAME); + super.addSymbol(SchemaSymbols.ATTVAL_NEGATIVEINTEGER); + super.addSymbol(SchemaSymbols.ATTVAL_MONTH); + super.addSymbol(SchemaSymbols.ATTVAL_MONTHDAY); + super.addSymbol(SchemaSymbols.ATTVAL_NCNAME); + super.addSymbol(SchemaSymbols.ATTVAL_NMTOKEN); + super.addSymbol(SchemaSymbols.ATTVAL_NMTOKENS); + super.addSymbol(SchemaSymbols.ATTVAL_NONNEGATIVEINTEGER); + super.addSymbol(SchemaSymbols.ATTVAL_NONPOSITIVEINTEGER); + super.addSymbol(SchemaSymbols.ATTVAL_NORMALIZEDSTRING); + super.addSymbol(SchemaSymbols.ATTVAL_NOTATION); + super.addSymbol(SchemaSymbols.ATTVAL_OPTIONAL); + super.addSymbol(SchemaSymbols.ATTVAL_POSITIVEINTEGER); + super.addSymbol(SchemaSymbols.ATTVAL_PRESERVE); + super.addSymbol(SchemaSymbols.ATTVAL_PROHIBITED); + super.addSymbol(SchemaSymbols.ATTVAL_QNAME); + super.addSymbol(SchemaSymbols.ATTVAL_QUALIFIED); + super.addSymbol(SchemaSymbols.ATTVAL_REPLACE); + super.addSymbol(SchemaSymbols.ATTVAL_REQUIRED); + super.addSymbol(SchemaSymbols.ATTVAL_RESTRICTION); + super.addSymbol(SchemaSymbols.ATTVAL_SHORT); + super.addSymbol(SchemaSymbols.ATTVAL_SKIP); + super.addSymbol(SchemaSymbols.ATTVAL_STRICT); + super.addSymbol(SchemaSymbols.ATTVAL_STRING); + super.addSymbol(SchemaSymbols.ATTVAL_SUBSTITUTION); + super.addSymbol(SchemaSymbols.ATTVAL_TIME); + super.addSymbol(SchemaSymbols.ATTVAL_TOKEN); + super.addSymbol(SchemaSymbols.ATTVAL_TRUE); + super.addSymbol(SchemaSymbols.ATTVAL_UNBOUNDED); + super.addSymbol(SchemaSymbols.ATTVAL_UNION); + super.addSymbol(SchemaSymbols.ATTVAL_UNQUALIFIED); + super.addSymbol(SchemaSymbols.ATTVAL_UNSIGNEDBYTE); + super.addSymbol(SchemaSymbols.ATTVAL_UNSIGNEDINT); + super.addSymbol(SchemaSymbols.ATTVAL_UNSIGNEDLONG); + super.addSymbol(SchemaSymbols.ATTVAL_UNSIGNEDSHORT); + super.addSymbol(SchemaSymbols.ATTVAL_YEAR); + super.addSymbol(SchemaSymbols.ATTVAL_YEARMONTH); + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/ValidateErrorHandler.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/ValidateErrorHandler.java new file mode 100644 index 000000000..fda40a4d9 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/ValidateErrorHandler.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * 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.xsd; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLErrorHandler; +import org.apache.xerces.xni.parser.XMLParseException; +import org.eclipse.wst.wsdl.validation.internal.util.ErrorMessage; + +/** + * An implementation of XMLErrorHandler that captures error from Xerces. + */ +public class ValidateErrorHandler implements XMLErrorHandler +{ + ArrayList errorList = new ArrayList(); + + + + /** + * Get the error messages created by Xerces. + * + * @return The errors list. + */ + public List getErrorMessages() + { + return errorList; + } + + /** + * Create a validation message from the exception and severity. + * + * @param error The error. + * @param severity The severity. + * @return An error message. + */ + protected ErrorMessage createValidationMessageForException(XMLParseException error, int severity) + { + String uri = error.getLiteralSystemId(); + if(uri == null) + { + uri = error.getPublicId(); + } + ErrorMessage errorMessage = new ErrorMessage(); + errorMessage.setErrorLine(error.getLineNumber()); + errorMessage.setErrorMessage(error.getMessage()); + errorMessage.setErrorColumn(error.getColumnNumber()); + errorMessage.setURI(uri); + errorMessage.setSeverity(severity); + return errorMessage; + } + + /** + * @see org.apache.xerces.xni.parser.XMLErrorHandler#error(java.lang.String, java.lang.String, org.apache.xerces.xni.parser.XMLParseException) + */ + public void error(String arg0, String arg1, XMLParseException exception) throws XNIException + { + errorList.add(createValidationMessageForException(exception, DOMError.SEVERITY_ERROR)); + } + + /** + * @see org.apache.xerces.xni.parser.XMLErrorHandler#fatalError(java.lang.String, java.lang.String, org.apache.xerces.xni.parser.XMLParseException) + */ + public void fatalError(String arg0, String arg1, XMLParseException exception) throws XNIException + { + errorList.add(createValidationMessageForException(exception, DOMError.SEVERITY_FATAL_ERROR)); + } + + /** + * @see org.apache.xerces.xni.parser.XMLErrorHandler#warning(java.lang.String, java.lang.String, org.apache.xerces.xni.parser.XMLParseException) + */ + public void warning(String arg0, String arg1, XMLParseException exception) throws XNIException + { + errorList.add(createValidationMessageForException(exception, DOMError.SEVERITY_WARNING)); + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/XMLEntityResolverChain.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/XMLEntityResolverChain.java new file mode 100644 index 000000000..cf936152a --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/XMLEntityResolverChain.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * 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.xsd; + +import java.io.IOException; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLInputSource; + +/** + * Handle a chain of entity resolvers. + */ +public class XMLEntityResolverChain implements XMLEntityResolver +{ + private List entityResolvers = new Vector(); + + /** + * @see org.apache.xerces.xni.parser.XMLEntityResolver#resolveEntity(org.apache.xerces.xni.XMLResourceIdentifier) + */ + public XMLInputSource resolveEntity(XMLResourceIdentifier xmlResourceIdentifier) throws XNIException, IOException + { + XMLInputSource is = null; + Iterator entityResolverIter = entityResolvers.iterator(); + while (entityResolverIter.hasNext()) + { + XMLEntityResolver entityResolver = (XMLEntityResolver)entityResolverIter.next(); + try + { + is = entityResolver.resolveEntity(xmlResourceIdentifier); + } + catch (XNIException e) + { + } + catch (IOException e) + { + } + if (is != null) + { + break; + } + } + // Throw and IOException if the file isn't found + if (is == null) + { + throw new IOException("Unable to locate file"); + } + return is; + } + + /** + * Add an entity resolver to this chain. + * + * @param entityResolver The resolver to add to the chain. + */ + public void addEntityResolver(XMLEntityResolver entityResolver) + { + entityResolvers.add(entityResolver); + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/XSDValidator.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/XSDValidator.java new file mode 100644 index 000000000..1ed97f647 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl11/xsd/XSDValidator.java @@ -0,0 +1,206 @@ +/******************************************************************************* + * 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.xsd; + +import java.io.Reader; +import java.io.StringReader; +import java.util.List; + +import org.apache.xerces.parsers.XMLGrammarPreparser; +import org.apache.xerces.util.XMLGrammarPoolImpl; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.grammars.XMLGrammarLoader; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.grammars.XSGrammar; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xs.XSModel; + + +/** + * Validate schemas from files or String. + */ +public class XSDValidator +{ + protected final String NAMESPACES_FEATURE_ID = "http://xml.org/sax/features/namespaces"; + protected final String VALIDATION_FEATURE_ID = "http://xml.org/sax/features/validation"; + protected final String SCHEMA_VALIDATION_FEATURE_ID = "http://apache.org/xml/features/validation/schema"; + protected final String SCHEMA_FULL_CHECKING_FEATURE_ID = + "http://apache.org/xml/features/validation/schema-full-checking"; + protected final String CONTINUE_AFTER_FATAL_ERROR_ID = "http://apache.org/xml/features/continue-after-fatal-error"; + protected final String FILE_PREFIX = "file:"; + protected final String XMLNS = "xmlns"; + protected final String TARGETNAMESPACE = "targetNamespace"; + protected final String NAMESPACE = "namespace"; + protected final String IMPORT = "import"; + protected final String SCHEMALOCATION = "schemaLocation"; + protected final String TYPE = "type"; + protected final String[] ignoreNamespaces = + { "http://www.w3.org/2001/XMLSchema", "http://www.w3.org/1999/XMLSchema" }; + + protected XSModel xsModel; + protected boolean isValidXSD; + protected List errors; + protected String filelocation; + + /** + * Constructor. + */ + public XSDValidator() + { + xsModel = null; + isValidXSD = false; + errors = null; + } + /** + * Validate an inline schema. + * + * @param schema A schema represented as a string. + * @param targetNamespace The target namespace of the schema. + * @param fileloc The uri of the file that contains the schema. + */ + public void validateInlineSchema(String schema, String targetNamespace, String fileloc) + { + validateInlineSchema(schema, targetNamespace, fileloc, null, null); + } + + /** + * Validate an inline schema and specify an entity resolver. + * + * @param schema This schema represented as a string. + * @param targetNamespace The target namespace of the schema. + * @param fileloc The uri of the file that contains this schema. + * @param entityResolverChain The entity resolver chain. + * @param inlineSchemaEntityResolver An inline schema resolver for this schema. + */ + public void validateInlineSchema( + String schema, + String targetNamespace, + String fileloc, + XMLEntityResolver entityResolverChain, + XMLEntityResolver inlineSchemaEntityResolver) + { + filelocation = fileloc; + + validateXSD(schema, true, entityResolverChain,targetNamespace, inlineSchemaEntityResolver); + } + + /** + * Validate the file located at the uri specified with the given entity resolver. + * + * @param uri An absolute uri for the schema location. + * @param entityResolver An entity resolver to be used. + */ + public void validate(String uri, XMLEntityResolver entityResolver) + { + validateXSD(uri, false, entityResolver, null, null); + } + + /** + * Validate the schema. + * + * @param schema The schema or it's location. + * @param inlineXSD True if an inline schema, false otherwise. + * @param entityResolver An entity resolver to use. + * @param targetNamespace The target namespace of the schema being validated. + * @param inlineSchemaEntityResolver An inline schema entity resolver. + */ + protected void validateXSD(String schema, boolean inlineXSD, XMLEntityResolver entityResolver, String targetNamespace, XMLEntityResolver inlineSchemaEntityResolver) + { + ValidateErrorHandler errorHandler = new ValidateErrorHandler(); + errorHandler.getErrorMessages().clear(); + try + { + XMLGrammarPreparser grammarPreparser = new XMLGrammarPreparser(); + XMLGrammarPool grammarPool = new XMLGrammarPoolImpl(); + grammarPreparser.setGrammarPool(grammarPool); + + grammarPreparser.setErrorHandler(errorHandler); + if (entityResolver != null) + { + grammarPreparser.setEntityResolver(entityResolver); + } + + try + { + XMLInputSource is = null; + // this allows support for the inline schema in WSDL documents + if (inlineXSD) + { + + Reader reader = new StringReader(schema); + is = new XMLInputSource(null,filelocation,filelocation,reader,null); + + ((InlineXSDResolver)inlineSchemaEntityResolver).addReferringSchema(is,targetNamespace); + + } + // get the input source for an external schema file + else + { + is = new XMLInputSource(null,schema,schema); + } + + grammarPreparser.registerPreparser(XMLGrammarDescription.XML_SCHEMA,null/*schemaLoader*/); + XMLGrammarLoader schemaLoader = grammarPreparser.getLoader(XMLGrammarDescription.XML_SCHEMA); + + XSGrammar grammar = (XSGrammar)grammarPreparser.preparseGrammar(XMLGrammarDescription.XML_SCHEMA,is); + xsModel = grammar.toXSModel(); + } + catch (Exception e) + { + //parser will return null pointer exception if the document is structurally invalid + //TODO: log error message + System.out.println(e); + } + + errors = errorHandler.getErrorMessages(); + } + catch (Exception e) + { + System.out.println(e); + } + if (errors.isEmpty()) + { + isValidXSD = true; + } + } + + /** + * Returns the XSModel created. + * + * @return The XSModel created. + */ + + public XSModel getXSModel() + { + return xsModel; + } + /** + * Returns true if the schema is valid, false otherwise. + * + * @return True if the schema is valid, false otherwise. + */ + public boolean isValid() + { + return isValidXSD; + } + + /** + * Return the error list. + * + * @return A list of error from the schema. + */ + public List getErrors() + { + return errors; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl20/IWSDL20Validator.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl20/IWSDL20Validator.java new file mode 100644 index 000000000..bfc792d72 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl20/IWSDL20Validator.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * 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.wsdl20; + +import java.util.List; +import java.util.ResourceBundle; + +import org.eclipse.wst.wsdl.validation.internal.IValidationInfo; + +/** + * Interface for a validator plugged into the WSDL 2.0 validator. + */ +public interface IWSDL20Validator +{ + /** + * Validate the given element. + * + * @param element The element to validate. + * @param parents A list of parents of this element. + * @param valInfo The validation info for the current validation. + */ + public void validate(Object element, List parents, IValidationInfo valInfo); + + /** + * Set the resource bundle of the validator. + * + * @param rb The resource bundle to set. + */ + public void setResourceBundle(ResourceBundle rb); + +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl20/ValidatorRegistry.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl20/ValidatorRegistry.java new file mode 100644 index 000000000..f983bd96d --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl20/ValidatorRegistry.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * 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.wsdl20; + +import java.util.Hashtable; +import java.util.Map; + + +/** + * A registry to hold all the WSDL 2.0 validators. + */ +public class ValidatorRegistry +{ + + protected static ValidatorRegistry verInstance; + + protected Map validatorReg = new Hashtable(); + + /** + * Constructor. + */ + protected ValidatorRegistry() + { + } + + /** + * Returns the instance of this registry. + * + * @return The instance of this registry. + */ + public static ValidatorRegistry getInstance() + { + if (verInstance == null) + { + verInstance = new ValidatorRegistry(); + } + return verInstance; + } + + /** + * Register this validator delegate with the given namespace. + * + * @param namespace The namespace the validator is associated with. + * @param valDelegate The validator delegate to register. + */ + public void registerValidator(String namespace, WSDL20ValidatorDelegate valDelegate) + { + // allow the null namespace but make it the empty string + if (namespace == null) + { + namespace = ""; + } + + // add the validator to the hashtable + validatorReg.put(namespace, valDelegate); + } + + /** + * Ask for the validator associated with this namespace. If none is found + * return null. + * + * @param namespace The namespace of the validator. + * @return The WSDL 1.1 validator for the given namespace. + */ + public IWSDL20Validator queryValidatorRegistry(String namespace) + { + // if the namespace is null allow it and treat it as the empty string + if (namespace == null) + { + namespace = ""; + } + WSDL20ValidatorDelegate delegate = (WSDL20ValidatorDelegate)validatorReg.get(namespace); + if(delegate != null) + { + return delegate.getValidator(); + } + return null; + } + + /** + * Convenience method that tells whether a validator for a given namespace is registered. + * + * @param namespace The namespace to check. + * @return True if there is a validator registered, false otherwise. + */ + public boolean hasRegisteredValidator(String namespace) + { + if (queryValidatorRegistry(namespace) != null) + { + return true; + } + return false; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl20/WSDL20BasicValidator.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl20/WSDL20BasicValidator.java new file mode 100644 index 000000000..fa38c9944 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl20/WSDL20BasicValidator.java @@ -0,0 +1,242 @@ +/******************************************************************************* + * 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.wsdl20; + +import java.util.List; +import java.util.ResourceBundle; + +import org.eclipse.wst.wsdl.validation.internal.IValidationInfo; +import org.eclipse.wst.wsdl.validation.internal.util.MessageGenerator; +/** + * Validate the elements defined in a WSDL 1.1 Document. + */ +public class WSDL20BasicValidator implements IWSDL20Validator +{ + protected final String NAMESPACES_FEATURE_ID = "http://xml.org/sax/features/namespaces"; + protected final String VALIDATION_FEATURE_ID = "http://xml.org/sax/features/validation"; + protected final String SCHEMA_VALIDATION_FEATURE_ID = "http://apache.org/xml/features/validation/schema"; + protected final String SCHEMA_FULL_CHECKING_FEATURE_ID = + "http://apache.org/xml/features/validation/schema-full-checking"; + protected final String CONTINUE_AFTER_FATAL_ERROR_ID = "http://apache.org/xml/features/continue-after-fatal-error"; + protected final String SOAP_ENCODING_URI = "http://schemas.xmlsoap.org/soap/encoding/"; + + protected final int ELEMENT = 0; + protected final int TYPE = 1; + + //protected WSDL20ValidatorController validatorcontroller; + protected MessageGenerator messagegenerator; + + /** + * Constructor. + */ + public WSDL20BasicValidator() + { + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.wsdl11.validator.IWSDL11Validator#validate(java.lang.Object, java.util.List, org.eclipse.wsdl.validate.IValidationInfo) + */ + public void validate(Object element, List parents, IValidationInfo valInfo) + { + //this.validatorcontroller = validatorcontroller; + //setDefaultResourceBundleIfNeeded(validatorcontroller); + +// Definitions wsdlDefinitions = (Definitions)element; +// validateTypes(wsdlDefinitions, valInfo); +// validateServices(wsdlDefinitions, valInfo); +// validateBindings(wsdlDefinitions, valInfo); +// validateInterfaces(wsdlDefinitions, valInfo); + + } + + /** + * Takes a list of ExtensibilityElements and checks if there's a validator + * associated with each element and if so calls the validator. + * + * @param parents The list of parents of the elements. + * @param extensibilityElements The list of elements to validate. + * @param validatorcontroller The validator controller. + * @param wsdlDefinition The defnintions element for this document. + */ +// protected void validateExtensibilityElementList( +// List parents, +// ElementInfoItem[] extensibilityElements, +// ValidationInfo valInfo, +// Definitions wsdlDefinitions) +// { +// //TODO: get the validation controller statically to get the extensibility validator +//// ValidatorRegistry ver = ValidatorRegistry.getInstance(); +//// Iterator extElems = extensibilityElements.iterator(); +//// while (extElems.hasNext()) +//// { +//// ElementInfoItem element = (ExtensibilityElement)extElems.next(); +//// // if (ver.hasRegisteredValidator(element.getElementType().getNamespaceURI())) +//// // { +//// validatorcontroller.validateWSDLElement(element.getElementType().getNamespaceURI(), element, parents); +//// //ver.queryValidatorRegistry(element.getElementType().getNamespaceURI()).validate(element, parents, validatormanager); +//// // } +//// } +// } + + /** + * If the resourcebundle hasn't been set, set it to the one registered with the ValidatorController. + * + * @param validatorcontroller The validator controller to get the resource bundle from. + */ +// protected void setDefaultResourceBundleIfNeeded(WSDL20ValidatorController validatorcontroller) +// { +// if (messagegenerator == null) +// { +// setResourceBundle(validatorcontroller.getResourceBundle()); +// } +// } + /** + * Set the resourcebundle to the one specified. + * + * @param rb The resource bundle to set. + */ + public void setResourceBundle(ResourceBundle rb) + { + messagegenerator = new MessageGenerator(rb); + } + + /** + * Ensure that the Types element is correct. + * + * @param wsdlDefinition The definitions element from the current document. + */ + +// protected void validateTypes(Definitions wsdlDefinitions, ValidationInfo valInfo) +// { +// Types types = wsdlDefinitions.getTypes(); +// // ensure that types is defined +// if (types != null) +// { +// List parents = new Vector(); +// parents.add(wsdlDefinitions); +// ElementInfoItem elementInfoItems[] = types.getElementInfoItems(); +// parents.add(0, types); +// validateExtensibilityElementList(parents, elementInfoItems, valInfo, wsdlDefinitions); +// parents.remove(0); +// } +// } + + /** + * Validates all of the declared services for the definition. + * + * @param wsdlDefinitions The WSDL definitions element. + * @param valInfo Validation info for the current validation. + */ +// protected void validateServices(Definitions wsdlDefinitions, ValidationInfo valInfo) +// { +// +// } + + /** + * Checks that the bindings refer to valid interfaces and all of the operations + * in a given binding refer to a defined operation within the corresponding + * interfaces. + * + * @param wsdlDefinitions The WSDL definitions element. + * @param valInfo Validation info for the current validation. + */ +// protected void validateBindings(Definitions wsdlDefinitions, ValidationInfo valInfo) +// { +// +// } + + /** + * Check that all of the Interfaces have valid messages associated with their + * operation input, output, infault and outfault types. + * + * @param wsdlDefinitions The WSDL definitions element. + * @param valInfo Validation info for the current validation. + */ +// private void validateInterfaces(Definitions wsdlDefinitions, ValidationInfo valInfo) +// { +// +// } + + /** + * Checks whether the given name is defined in the namespace for the part. A part is an + * ELEMENT in WSDL 2.0. + * + * @param namespace The namespace to check. + * @param name The name to check. + * @param valInfo Validation info for the current validation. + * @return True if the part element is defined, false otherwise. + */ + protected boolean checkMessage(String namespace, String name, IValidationInfo valInfo) + { + + boolean partvalid = false; +// // first take care of the situation where it's schema for schema +// if (namespace.equalsIgnoreCase(SchemaSymbols.URI_SCHEMAFORSCHEMA)) +// { +// SchemaAttributeTable xsdTable = new SchemaAttributeTable(); +// if (xsdTable.containsSymbol(name)) +// { +// partvalid = true; +// } +// } +// // check inline and imported schema +// else +// { +// List schemas = validatorcontroller.getSchemas(); +// Iterator schemasIter = schemas.iterator(); +// while (schemasIter.hasNext()) +// { +// XSModel schema = (XSModel)schemasIter.next(); +// if (schema != null) +// { +// if (schema.getElementDeclaration(name, namespace) != null) +// { +// partvalid = true; +// break; +// } +// +// } +// } +// } + // If the SOAP encoding namespace hasn't been explicitly imported do so now. + // Allow the SOAP encoding namespace to be automatically imported but mark it as a warning. +// if (!partvalid && namespace.equals(SOAP_ENCODING_URI)) +// { +// try +// { +// XSDValidator xsdVal = new XSDValidator(); +// xsdVal.validate(XMLCatalog.getInstance().resolveEntityLocation(SOAP_ENCODING_URI, null), null); +// // sanity check in case something goes wrong +// if (xsdVal.isValid()) +// { +// XSModel xsModel = xsdVal.getXSModel(); +// +// if (xsModel.getElementDeclaration(name, namespace) != null) +// { +// partvalid = true; +// } +// +// validatorcontroller.addWarningMessage( +// partObject, +// messagegenerator.getString("_WARN_SOAPENC_IMPORTED_PART", "'" + name + "'")); +// } +// } +// catch (Exception e) +// { +// //TODO: log the error message +// //System.out.println(e); +// } +// } + return partvalid; + } + +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl20/WSDL20ValidatorController.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl20/WSDL20ValidatorController.java new file mode 100644 index 000000000..b8175cf47 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl20/WSDL20ValidatorController.java @@ -0,0 +1,322 @@ +/******************************************************************************* + * 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.wsdl20; + +import java.util.Hashtable; +import java.util.List; +import java.util.ResourceBundle; +import java.util.Vector; + +import org.eclipse.wst.wsdl.validation.internal.IWSDLValidator; +import org.eclipse.wst.wsdl.validation.internal.IValidationInfo; +import org.eclipse.wst.wsdl.validation.internal.exception.ValidateWSDLException; +import org.eclipse.wst.wsdl.validation.internal.util.MessageGenerator; +import org.w3c.dom.Document; + +/** + * The validator controller is the head of validation. Has methods for getting + * extension validators. + */ +public class WSDL20ValidatorController implements IWSDLValidator +{ + protected final String _WARN_NO_VALDIATOR = "_WARN_NO_VALDIATOR"; + protected final int ERROR_MESSAGE = 0; + protected final int WARNING_MESSAGE = 1; + protected String fileURI; + protected List schemas = new Vector(); +// protected Definitions wsdlDefinition; + protected Hashtable elementLocations = null; + protected ResourceBundle resourcebundle; + protected MessageGenerator messagegenerator = null; + //protected ValidationController validationController; + protected ValidatorRegistry ver = ValidatorRegistry.getInstance(); + protected boolean errors = false; + + /** + * Constructor. + * + * @param rb The resource bundle to set for this controller. + */ + public WSDL20ValidatorController(ResourceBundle rb) + { + setResourceBundle(rb); + } + + /* (non-Javadoc) + * @see org.eclipse.wsdl.validate.IWSDLValidator#validate(org.w3c.dom.Document, org.eclipse.wsdl.validate.ValidationInfo) + */ + public void validate(Document domModel, IValidationInfo valInfo) throws ValidateWSDLException + { + // reset the variables + //reset(); + fileURI = valInfo.getFileURI(); + //this.validationController = validationcontroller; + + +// List readerErrors = readWSDLDocument(domModel, fileURI, getMessageGenerator()); + // handle any reader errors +// if (readerErrors != null) +// { +// Iterator readerErrorsI = readerErrors.iterator(); +// while (readerErrorsI.hasNext()) +// { +// ReaderError re = (ReaderError)readerErrorsI.next(); +// valInfo.addError(re.getMessage(), re.getLine(), re.getColumn(), re.getFileURI()); +// } +// } +// validateWSDLElement(Constants.NS_URI_WSDL, wsdlDefinition, new Vector(), valInfo); + } + + /** + * Read in the WSDL document and set the model and imported schemas. + * + * @param domModel A DOM document model of the file to be read. + * @param file The file to read. + * @param messagegenerator The messagegenerator the reader should use for any messages produced. + * @throws ValidateWSDLException + * @return A list of reader errors. + */ +// protected List readWSDLDocument(Document domModel, String file, MessageGenerator messagegenerator) throws ValidateWSDLException +// { +// List readerErrors = null; +// try +// { +// +// WSDLReaderImpl wsdlReader = new WSDLReaderImpl(); +// wsdlDefinition = wsdlReader.readWSDL(file, domModel); +// +// readerErrors = wsdlReader.getReaderErrors(); +// +// } +// catch (WSDLException e) +// { +// throw new ValidateWSDLException(e.getMessage() /*+ " " + e.getFaultCode()*/); +// } +// +// catch (Exception e) +// { +// throw new ValidateWSDLException("unable to read file" + e.getMessage() + " " + e.toString()); +// } +// return readerErrors; +// } + + /** + * Given a WSDL element, call ValidateElement for it. + * + * @param namespace The namespace of the element to validate. + * @param element The element to validate. + * @param parents The list of parents for this element. + */ + public void validateWSDLElement(String namespace, Object element, List parents, IValidationInfo valInfo) + { + IWSDL20Validator val = ver.queryValidatorRegistry(namespace); + if (val != null) + { + val.validate(element, parents, valInfo); + } + else + { + //valInfo.addWarning(messagegenerator.getString(_WARN_NO_VALDIATOR, namespace), element); + } + } + + /** + * Add a schema to the list of schemas. + * + * @param xsModel The schema to add. + */ +// public void addSchema(XSModel xsModel) +// { +// if (xsModel != null) +// { +// schemas.add(xsModel); +// } +// } + + /** + * Return the list containing the schemas. + * + * @return The list of schemas. + */ +// public List getSchemas() +// { +// return schemas; +// } + + /** + * Get the ResourceBundle for this ValidatorManager. + * + * @return The resource bundle registered for this controller. + * @see #setResourceBundle + */ + public ResourceBundle getResourceBundle() + { + return resourcebundle; + } + + /** + * Set the ResourceBundle for this ValidatorManager. + * + * @param rb The resource bundle to set. + * @see #getResourceBundle + */ + public void setResourceBundle(ResourceBundle rb) + { + if (rb != null) + { + resourcebundle = rb; + messagegenerator = new MessageGenerator(rb); + } + + } + + /** + * Get the message generator registered for this controller. + * + * @return The message generator registered for this controller. + */ + public MessageGenerator getMessageGenerator() + { + return messagegenerator; + } + + /** + * Return the filename for the file currently being validated. Some validators require this. + * + * @return The filename for the file being validated. + */ +// public String getFilename() +// { +// return fileURI; +// } + + /** + * Convenience method for extensibly validators to add error messages. + * + * @param object The object to add the error for. + * @param error The error to add. + */ +// public void addErrorMessage(Object object, String error) +// { +// addValidationMessage(ERROR_MESSAGE, object, error); +// errors = true; +// } + + /** + * Method for extensibly validators to add error messages when they know + * line and column numbers. + * + * @param line The line where the error message is located. + * @param column The column where the error message is located. + * @param error The error message. + */ +// public void addErrorMessage(int line, int column, String error) +// { +// addValidationMessage(ERROR_MESSAGE, line, column, error); +// errors = true; +// } + + /** + * Convenience method for extensibly validators to add warning messages. + * + * @param object The object to add the warning message. + * @param warning The warning message. + */ +// public void addWarningMessage(Object object, String warning) +// { +// addValidationMessage(WARNING_MESSAGE, object, warning); +// } + + /** + * Method for extensibly validators to add warning messages when they know + * line and column numbers. + * + * @param line The line where the error message is located. + * @param column The column where the error message is located. + * @param warning The warning message. + */ +// public void addWarningMessage(int line, int column, String warning) +// { +// addValidationMessage(WARNING_MESSAGE, line, column, warning); +// } + + /** + * If you have an object read in by the reader for this + * validatorcontroller the object can be passed in here and the line and column + * information will be abstracted from it. + * + * @param type The type of message to add. + * @param o The object that has the error (used to get the location). + * @param message The message to add. + */ +// protected void addValidationMessage(int type, Object o, String message) +// { +// ValidatableElement ve = (ValidatableElement)o; +//// int[] location; +//// if (elementLocations.containsKey(o)) +//// { +//// location = (int[])elementLocations.get(o); +//// } +//// // if we give it an element that hasn't been defined we'll set the location +//// // at (0,0) so the error shows up but no line marker in the editor +//// else +//// { +//// location = new int[] { 0, 0 }; +//// } +// addValidationMessage(type, ve.getLine(), ve.getColumn(), message); +// } + + /** + * Creates a validation message of the specified type. + * + * @param type The type of validation message to add. + * @param line The line where the error message is located. + * @param column The line where the column message is located. + * @param message The message to add. + */ +// protected void addValidationMessage(int type, int line, int column, String message) +// { +// if (message != null) +// { +// if (type == ERROR_MESSAGE) +// { +// validationController.addErrorMessage(line, column, message); +// } +// else if (type == WARNING_MESSAGE) +// { +// validationController.addWarningMessage(line, column, message); +// } +// } +// } + + /** + * @see org.eclipse.wst.wsdl.validation.controller.IWSDLValidator#isValid() + */ + public boolean isValid() + { + return !errors; + } + + /** + * Reset the validator controller. + */ +// protected void reset() +// { +// schemas = new Vector(); +// fileURI = ""; +// wsdlDefinition = null; +// elementLocations = null; +// resourcebundle = null; +// //validationController = null; +// errors = false; +// } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl20/WSDL20ValidatorDelegate.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl20/WSDL20ValidatorDelegate.java new file mode 100644 index 000000000..7661f7de5 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/wsdl20/WSDL20ValidatorDelegate.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * 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.wsdl20; + +import java.util.Locale; +import java.util.ResourceBundle; + + +/** + * The WSDL 1.1 validator delegate holds a reference to a validator to be instantiated at + * a later point. + */ +public class WSDL20ValidatorDelegate +{ + private String validatorClassname = null; + private String resourceBundle = null; + private ClassLoader classLoader = null; + private IWSDL20Validator validator = null; + + /** + * Create a delegate for a validator by its class name and resource bundle name. + * + * @param validatorClassname The name of the validator class. + * @param resourceBundle The name of the validator base resource bundle. + */ + public WSDL20ValidatorDelegate(String validatorClassname, String resourceBundle) + { + this.validatorClassname = validatorClassname; + this.resourceBundle = resourceBundle; + } + + /** + * Create a delegate for a validator by its class name, resource bundle name and + * a class loader to load the validator and bundle. + * + * @param validatorClassname The name of the validator class. + * @param resourceBundle The name of the validator base resource bundle. + * @param classLoader The class loader to use to load the validator and bundle. + */ + public WSDL20ValidatorDelegate(String validatorClassname, String resourceBundle, ClassLoader classLoader) + { + this(validatorClassname, resourceBundle); + this.classLoader = classLoader; + } + + /** + * Get the validator specified in this delegate. + * + * @return The WSDL 1.1 validator specified by this delegate. + */ + public IWSDL20Validator getValidator() + { + if (validator == null) + { + if(classLoader == null) + { + classLoader = getClass().getClassLoader(); + } + try + { + Class validatorClass = + classLoader != null ? classLoader.loadClass(validatorClassname) : Class.forName(validatorClassname); + + validator = (IWSDL20Validator)validatorClass.newInstance(); + if (resourceBundle != null) + { + ResourceBundle validatorBundle = ResourceBundle.getBundle(resourceBundle, Locale.getDefault(), classLoader); + validator.setResourceBundle(validatorBundle); + } + } + catch (ClassNotFoundException e) + { + // TODO: add logging + System.err.println(e); + } + catch (IllegalAccessException e) + { + // TODO: add logging + System.err.println(e); + } + catch (InstantiationException e) + { + // TODO: add logging + System.err.println(e); + } + } + return validator; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/AbstractXMLConformanceFactory.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/AbstractXMLConformanceFactory.java new file mode 100644 index 000000000..d7cb52e10 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/AbstractXMLConformanceFactory.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * 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.xml; + +/** + * Factory for generating objects needed for XML Conformance validation. + */ +public abstract class AbstractXMLConformanceFactory +{ + protected static AbstractXMLConformanceFactory instance; + + /** + * Returns the instance of this factory. + * + * @return the instance of this factory + */ + public static AbstractXMLConformanceFactory getInstance() + { + if (instance == null) + { + instance = new DefaultXMLConformanceFactory(); + } + return instance; + } + + /** + * Set the implementation for this factory to use. + * + * @param factory - the implementation this factory will use + */ + public static void setImplementation(AbstractXMLConformanceFactory factory) + { + instance = factory; + } + + /** + * Return an XML validator. + * + * @return an XML validator + */ + abstract public IXMLValidator getXMLValidator(); +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/DefaultXMLConformanceFactory.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/DefaultXMLConformanceFactory.java new file mode 100644 index 000000000..1e4e15c4d --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/DefaultXMLConformanceFactory.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * 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.xml; + + +/** + * The default implementation of AbstractXMLConformanceFactory. + */ +public class DefaultXMLConformanceFactory extends AbstractXMLConformanceFactory +{ + + /** + * Constructor. + */ + public DefaultXMLConformanceFactory() + { + } + + /** + * @see org.eclipse.wst.wsdl.validation.internal.xml.AbstractXMLConformanceFactory#getXMLValidator() + */ + public IXMLValidator getXMLValidator() + { + return new DefaultXMLValidator(); + } + +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/DefaultXMLValidator.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/DefaultXMLValidator.java new file mode 100644 index 000000000..ba8a0c1de --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/DefaultXMLValidator.java @@ -0,0 +1,561 @@ +/******************************************************************************* + * 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.xml; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringReader; +import java.net.URL; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; + +import javax.xml.parsers.FactoryConfigurationError; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParserFactory; + +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.jaxp.SAXParserFactoryImpl; +import org.apache.xerces.parsers.SAXParser; +import org.apache.xerces.parsers.StandardParserConfiguration; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.eclipse.core.resources.IFile; +import org.eclipse.wst.wsdl.validation.internal.ValidationMessageImpl; +import org.eclipse.wst.wsdl.validation.internal.resolver.IURIResolutionResult; +import org.eclipse.wst.wsdl.validation.internal.resolver.URIResolver; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.DefaultHandler; + +import com.ibm.wsdl.Constants; + +/** + * The default implementation of IXMLValidator. + */ +public class DefaultXMLValidator implements IXMLValidator +{ + private final String _APACHE_FEATURE_CONTINUE_AFTER_FATAL_ERROR = + "http://apache.org/xml/features/continue-after-fatal-error"; + private final String _APACHE_FEATURE_NAMESPACE_PREFIXES = "http://xml.org/sax/features/namespace-prefixes"; + private final String _APACHE_FEATURE_NAMESPACES = "http://xml.org/sax/features/namespaces"; + private final String _APACHE_FEATURE_VALIDATION = "http://xml.org/sax/features/validation"; + private final String _APACHE_FEATURE_VALIDATION_SCHEMA = "http://apache.org/xml/features/validation/schema"; + private final String _APACHE_PROPERTY_EXTERNAL_SCHEMALOCATION = + "http://apache.org/xml/properties/schema/external-schemaLocation"; + private final String DEFINITIONS = "definitions"; + + protected static final String IGNORE_ALWAYS = "IGNORE_ALWAYS"; + protected static final String PREMATURE_EOF = "PrematureEOF"; + + protected Hashtable ingoredErrorKeyTable = new Hashtable(); + + protected String uri; + protected URIResolver uriResolver = null; + protected List errors = new ArrayList(); + protected StringBuffer schemaLocationString = new StringBuffer(); + protected List ignoredNamespaceList = new ArrayList(); + + protected InputStream inputStream = null; + + protected String currentErrorKey = null; + protected Object[] currentMessageArguments = null; + + protected boolean isChildOfDoc = false; +// protected String wsdlNamespace = null; + + + + +/** + * Constructor. + */ + public DefaultXMLValidator() + { + super(); + + ignoredNamespaceList.add(Constants.NS_URI_XSD_1999); + ignoredNamespaceList.add(Constants.NS_URI_XSD_2000); + ignoredNamespaceList.add(Constants.NS_URI_XSD_2001); + + ingoredErrorKeyTable.put(PREMATURE_EOF, IGNORE_ALWAYS); + } + + /** + * @see org.eclipse.validate.wsdl.xmlconformance.IXMLValidatorAction#setFile(IFile) + */ + public void setFile(String uri) + { + this.uri = uri; + } + + public void setURIResolver(URIResolver uriResolver) + { + this.uriResolver = uriResolver; + } + + /** + * @see org.eclipse.validate.wsdl.xmlconformance.IXMLValidatorAction#run() + */ + public void run() + { + // Validate the XML file. + try + { + Reader reader1 = null; // Used for the preparse. + Reader reader2 = null; // Used for validation parse. + + InputSource validateInputSource; + + + if (this.inputStream != null) + { + + + String string = createStringForInputStream(inputStream); + reader1 = new StringReader(string); + reader2 = new StringReader(string); + + validateInputSource = new InputSource(inputStream); + validateInputSource.setCharacterStream(reader2); + } else + { validateInputSource = new InputSource(uri); + } + + preparse(uri, reader1); + + SAXParser saxparser = createSAXParser(); + XMLConformanceDefaultHandler handler = new XMLConformanceDefaultHandler(); + + saxparser.setErrorHandler(handler); + saxparser.setEntityResolver(handler); + saxparser.setContentHandler(handler); + + saxparser.parse(validateInputSource); +// wsdlNamespace = handler.getWSDLNamespace(); + } + catch (SAXParseException e) + { + addError(e.getMessage(), e.getLineNumber(), e.getColumnNumber(), uri); + } + catch (IOException e) + { + } + catch (Exception e) + { + //System.out.println(e); + } + } + + /** + * Create and configure a SAX parser. + * + * @return The new SAX parser. + */ + protected SAXParser createSAXParser() + { + SAXParser saxParser = null; + try + { + //SAXParserFactory parserfactory = new SAXParserFactoryImpl(); + try + { MyStandardParserConfiguration configuration = new MyStandardParserConfiguration(); + saxParser = new org.apache.xerces.parsers.SAXParser(configuration); + saxParser.setFeature(_APACHE_FEATURE_CONTINUE_AFTER_FATAL_ERROR, true); + saxParser.setFeature(_APACHE_FEATURE_NAMESPACE_PREFIXES, true); + saxParser.setFeature(_APACHE_FEATURE_NAMESPACES, true); + saxParser.setFeature(_APACHE_FEATURE_VALIDATION, true); + saxParser.setFeature(_APACHE_FEATURE_VALIDATION_SCHEMA, true); + } + catch (SAXNotRecognizedException e) + { + } + catch (SAXNotSupportedException e) + { + } + if (schemaLocationString.length() > 0) + { + saxParser.setProperty(_APACHE_PROPERTY_EXTERNAL_SCHEMALOCATION, schemaLocationString.toString()); + } + } + catch (FactoryConfigurationError e) + { + } + catch (SAXNotRecognizedException e) + { + } + catch (SAXNotSupportedException e) + { + } +// catch (SAXException e) +// { +// } + return saxParser; + } + + + final String createStringForInputStream(InputStream inputStream) + { + // Here we are reading the file and storing to a stringbuffer. + StringBuffer fileString = new StringBuffer(); + try + { + InputStreamReader inputReader = new InputStreamReader(inputStream); + BufferedReader reader = new BufferedReader(inputReader); + char[] chars = new char[1024]; + int numberRead = reader.read(chars); + while (numberRead != -1) + { + fileString.append(chars, 0, numberRead); + numberRead = reader.read(chars); + } + } + catch (Exception e) + { + //TODO: log error message + //e.printStackTrace(); + } + return fileString.toString(); + } + + /** + * Preparse the file to find all of the namespaces that are defined in order + * to specify the schemalocation. + * + * @param uri The uri of the file to parse. + */ + protected void preparse(String uri, Reader characterStream) + { + javax.xml.parsers.SAXParser saxParser = null; + try + { + + InputSource inputSource; + + if (characterStream != null) + { + inputSource = new InputSource(uri); + inputSource.setCharacterStream(characterStream); + } + else + { + inputSource = new InputSource(uri); + } + + SAXParserFactory parserfactory = new SAXParserFactoryImpl(); + + parserfactory.setFeature(_APACHE_FEATURE_NAMESPACE_PREFIXES, true); + parserfactory.setFeature(_APACHE_FEATURE_NAMESPACES, true); + + saxParser = parserfactory.newSAXParser(); + SchemaStringHandler handler = new SchemaStringHandler(uri); + + saxParser.parse(inputSource, handler); + } + catch (FactoryConfigurationError e) + { + } + catch (SAXNotRecognizedException e) + { + } + catch (ParserConfigurationException e) + { + } + catch (SAXNotSupportedException e) + { + } + catch (SAXException e) + { + } + catch (IOException e) + { + } + } + + /** + * @see org.eclipse.validate.wsdl.xmlconformance.IXMLValidatorAction#hasErrors() + */ + public boolean hasErrors() + { + return !errors.isEmpty(); + } + + /** + * @see org.eclipse.validate.wsdl.xmlconformance.IXMLValidatorAction#getErrorList() + */ + public List getErrors() + { + return errors; + } + + /** + * Add an error message. + * + * @param error The error message to add. + * @param line The line location of the error. + * @param column The column location of the error. + * @param uri The URI of the file containing the error. + */ + protected void addError(String error, int line, int column, String uri) + { + errors.add(new ValidationMessageImpl(error, line, column, ValidationMessageImpl.SEV_ERROR, uri, currentErrorKey, currentMessageArguments)); + } + + /** + * The handler for the SAX parser. This handler will obtain the WSDL + * namespace, handle errors and resolve entities. + */ + protected class XMLConformanceDefaultHandler extends DefaultHandler + { + /** + * @see org.xml.sax.ErrorHandler#error(SAXParseException) + */ + public void error(SAXParseException arg0) throws SAXException + { + String tempURI = arg0.getSystemId(); + if (inputStream!= null && arg0.getSystemId() == null) + { + //mh: In this case we are validating a stream so the URI may be null in this exception + tempURI = uri; + } + addError(arg0.getMessage(), arg0.getLineNumber(), arg0.getColumnNumber(), tempURI); + } + + /** + * @see org.xml.sax.ErrorHandler#fatalError(SAXParseException) + */ + public void fatalError(SAXParseException arg0) throws SAXException + { + addError(arg0.getMessage(), arg0.getLineNumber(), arg0.getColumnNumber(), arg0.getSystemId()); + } + + /** + * @see org.xml.sax.ErrorHandler#warning(SAXParseException) + */ + public void warning(SAXParseException arg0) throws SAXException + { + addError(arg0.getMessage(), arg0.getLineNumber(), arg0.getColumnNumber(), arg0.getSystemId()); + } + + /** + * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String) + */ + public void endElement(String uri, String localName, String qName) + throws SAXException { + if(localName.equals("documentation") && (uri.equals(Constants.NS_URI_WSDL) || uri.equals(Constants.NS_URI_XSD_2001)|| uri.equals(Constants.NS_URI_XSD_1999) || uri.equals(Constants.NS_URI_XSD_2000))) + { + isChildOfDoc = false; + } + super.endElement(uri, localName, qName); + } + /** + * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes) + */ + public void startElement(String uri, String localName, String qName, + Attributes atts) throws SAXException { + if(localName.equals("documentation") && (uri.equals(Constants.NS_URI_WSDL) || uri.equals(Constants.NS_URI_XSD_2001)|| uri.equals(Constants.NS_URI_XSD_1999) || uri.equals(Constants.NS_URI_XSD_2000))) + { + isChildOfDoc = true; + } + super.startElement(uri, localName, qName, atts); + } + + /** + * @see org.xml.sax.EntityResolver#resolveEntity(java.lang.String, + * java.lang.String) + */ + public InputSource resolveEntity(String publicId, String systemId) throws SAXException + { + // If we're currently examining a subelement of the + // WSDL or schema documentation element we don't want to resolve it + // as anything is allowed as a child of documentation. + if(isChildOfDoc) + { + return new InputSource(); + } + if(publicId == null) + { + publicId = systemId; + } + + IURIResolutionResult result = uriResolver.resolve(null, publicId, systemId); + String uri = result.getPhysicalLocation(); + if (uri != null && !uri.equals("")) + { + try + { +// String entity = systemId; +// if(publicId != null) +// { +// entity = publicId; +// } + URL entityURL = new URL(uri); + InputSource is = new InputSource(result.getLogicalLocation()); + is.setByteStream(entityURL.openStream()); + if (is != null) + { + return is; + } + } + catch(Exception e) + { + // Do nothing. + } + } + // This try/catch block with the IOException is here to handle a difference + // between different versions of the EntityResolver interface. + try + { + InputSource is = super.resolveEntity(publicId, systemId); + if(is == null) + { + throw new IOException(); + } + return is; + } + catch(IOException e) + { + } + return null; + } + + } + + /** + * @see org.eclipse.validate.wsdl.xmlconformance.IXMLValidator#setSchemaLocation(String, + * String) + */ + public void setSchemaLocation(String namespace, String location) + { + if (namespace != null && location != null && !namespace.equalsIgnoreCase("") && !location.equalsIgnoreCase("")) + { + schemaLocationString.append(" ").append(namespace).append(" ").append(formatURI(location)); + } + } + + + /** + * @param inputStream - set the inputStream to validate + */ + public void setInputStream(InputStream inputStream) + { + this.inputStream = inputStream; + } + + /** + * Remove space characters from a String and replace them with %20. + * + * @param uri - + * the uri to format + * @return the formatted string + */ + protected String formatURI(String uri) + { + String space = "%20"; + StringBuffer newUri = new StringBuffer(uri); + int newUriLength = newUri.length(); + + // work backwards through the stringbuffer in case it grows to the + // point + // where the last space would be missed. + for (int i = newUriLength - 1; i >= 0; i--) + { + if (newUri.charAt(i) == ' ') + { + newUri.replace(i, i + 1, space); + } + } + + return newUri.toString(); + } + + /** + * A handler used in preparsing to get the schemaLocation string. + */ + protected class SchemaStringHandler extends DefaultHandler + { + private final String XMLNS = "xmlns"; + private final String TARGETNAMESPACE = "targetNamespace"; + private String baselocation = null; + + public SchemaStringHandler(String baselocation) + { + this.baselocation = baselocation; + } + /** + * @see org.xml.sax.ContentHandler#startElement(java.lang.String, + * java.lang.String, java.lang.String, org.xml.sax.Attributes) + */ + public void startElement(String uri, String localname, String arg2, Attributes attributes) throws SAXException + { + if (localname.equals(DEFINITIONS)) + { + String targetNamespace = attributes.getValue(TARGETNAMESPACE); + int numAtts = attributes.getLength(); + for (int i = 0; i < numAtts; i++) + { + + String attname = attributes.getQName(i); + if (attname.startsWith(XMLNS)) + { + String namespace = attributes.getValue(i); + if(!(namespace.equals(targetNamespace) || ignoredNamespaceList.contains(namespace))) + { + String resolvedURI = namespace; + setSchemaLocation(namespace, resolvedURI); + } + } + } + + } + super.startElement(uri, localname, arg2, attributes); + + } + } + + + protected class MyStandardParserConfiguration extends StandardParserConfiguration + { + public MyStandardParserConfiguration() + { + } + + /* (non-Javadoc) + * @see org.apache.xerces.parsers.DTDConfiguration#createErrorReporter() + */ + protected XMLErrorReporter createErrorReporter() + { + return new XMLErrorReporter() + { + /* (non-Javadoc) + * @see org.apache.xerces.impl.XMLErrorReporter#reportError(java.lang.String, java.lang.String, java.lang.Object[], short) + */ + public void reportError(String domain, String key, Object[] arguments, + short severity) throws XNIException + { + currentErrorKey = key; + currentMessageArguments = arguments; + super.reportError(domain, key, arguments, severity); + } + }; + } + } + + +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/ElementLocation.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/ElementLocation.java new file mode 100644 index 000000000..57d9a3abe --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/ElementLocation.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * 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.xml; + +/** + * Holds the location information for an element in the model. + */ +public class ElementLocation +{ + public static final String ID = "location"; + protected int line; + protected int column; + /** + * Constructor. + * + * @param line - the line location of the element + * @param column - the column location of the element + */ + public ElementLocation(int line, int column) + { + this.line = line; + this.column = column; + } + + /** + * Return the line number for this element. + * + * @return the line number for this element + */ + public int getLineNumber() + { + return line; + } + + /** + * Return the column number for this element. + * + * @return the column number for this element + */ + public int getColumnNumber() + { + return column; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/IXMLCatalog.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/IXMLCatalog.java new file mode 100644 index 000000000..43f456e45 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/IXMLCatalog.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * 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.xml; + +/** + * An interface for an XML catalog. + */ +public interface IXMLCatalog +{ + + /** + * Add a public id and a location to the catalog. + * + * @param publicId - + * the public id of the entry + * @param systemId - + * the system id of the entry + */ + public abstract void addEntryToCatalog(String publicId, String systemId); + + /** + * Resolve the location of an entity given public and system ids. + * + * @param publicId - + * the public id of the entity to be resolved + * @param systemId - + * the system id of the entity to be resolved + * @return the location of the entity + */ + public abstract String resolveEntityLocation(String publicId, String systemId); +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/IXMLValidator.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/IXMLValidator.java new file mode 100644 index 000000000..b4cadfe03 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/IXMLValidator.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * 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.xml; + +import java.util.List; + +import org.eclipse.wst.wsdl.validation.internal.resolver.URIResolver; + +/** + * An interface for an XML validator. + */ +public interface IXMLValidator +{ + /** + * Set the file to be validated. + * + * @param uri - the uri of the file to be validated + */ + public void setFile(String uri); + + /** + * Validate the file. + */ + public void run(); + + /** + * Returns true if there were validation errors, false otherwise. + * + * @return true if there were validation errors, false otherwise + */ + public boolean hasErrors(); + + /** + * Returns the list of errors. + * + * @return the list of errors + */ + public List getErrors(); + + /** + * Add a schema location to be schema locatino string used by the XML parser. + * + * @param namespace - the namespaces of the schema + * @param location - the location of the schema + */ + public void setSchemaLocation(String namespace, String location); + + /** + * Set the URI resolver to use. + * + * @param uriResolver The URI resolver to use. + */ + public void setURIResolver(URIResolver uriResolver); +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/LineNumberDOMParser.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/LineNumberDOMParser.java new file mode 100644 index 000000000..0ade3673c --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/LineNumberDOMParser.java @@ -0,0 +1,153 @@ +/******************************************************************************* + * 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.xml; + +import org.apache.xerces.dom.ElementImpl; +import org.apache.xerces.parsers.DOMParser; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLParserConfiguration; +import org.w3c.dom.Element; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; + +import com.ibm.wsdl.Constants; + +/** + * A DOM parser that will register location information with the elements in the model. + */ +public class LineNumberDOMParser extends DOMParser +{ + XMLLocator locator = null; + + /** + * Constructor. + */ + public LineNumberDOMParser() + { + super(); + try + { + setFeature(DEFER_NODE_EXPANSION, false); + } + catch (SAXNotSupportedException e) + { + System.out.println(e); + } + catch (SAXNotRecognizedException e) + { + System.out.println(e); + } + } + + /** + * Constuctor. + * + * @param arg0 The parser configuration. + */ + public LineNumberDOMParser(XMLParserConfiguration arg0) + { + super(arg0); + try + { + setFeature(DEFER_NODE_EXPANSION, false); + } + catch (SAXNotSupportedException e) + { + System.out.println(e); + } + catch (SAXNotRecognizedException e) + { + System.out.println(e); + } + } + + /** + * Constructor. + * + * @param arg0 A symbol table for the parser. + */ + public LineNumberDOMParser(SymbolTable arg0) + { + super(arg0); + } + + /** + * Constructor. + * + * @param arg0 A symbol table for the parser. + * @param arg1 A grammar pool for the parser. + */ + public LineNumberDOMParser(SymbolTable arg0, XMLGrammarPool arg1) + { + super(arg0, arg1); + } + + /** + * @see org.apache.xerces.xni.XMLDocumentHandler#startElement(org.apache.xerces.xni.QName, org.apache.xerces.xni.XMLAttributes, org.apache.xerces.xni.Augmentations) + */ + public void startElement(QName arg0, XMLAttributes arg1, Augmentations arg2) throws XNIException + { + Element element; + // For elements from the Schema namespace we want to preserve them + // the way they were entered. Revert the values to the non-normalized values. + String ns = arg0.uri; + if(ns != null && (ns.equals(Constants.NS_URI_XSD_2001) || ns.equals(Constants.NS_URI_XSD_1999) || ns.equals(Constants.NS_URI_XSD_2000))) + { + int numatts = arg1.getLength(); + for(int i = 0; i < numatts; i++) + { + String nonNormalizedValue = arg1.getNonNormalizedValue(i); + arg1.setValue(i, nonNormalizedValue); + } + } + super.startElement(arg0, arg1, arg2); + try + { + element = (Element)getProperty(CURRENT_ELEMENT_NODE); + ElementImpl elementImpl = (ElementImpl)element; + // Setting the user data with an identifier such as ElementLocation.KEY_NAME + // may be a long term good idea. The setUserData method with no id is used + // to support JVMs with alternate versions of Xerces. + elementImpl.setUserData(new ElementLocation(locator.getLineNumber(), locator.getColumnNumber())); + } + // catch SAXNotRecognizedException and SAXNotSupportedException if can't get element + catch (ClassCastException e) + { + //System.out.println(e); + } + catch (SAXNotRecognizedException e) + { + //System.out.println(e); + } + catch (SAXNotSupportedException e) + { + //System.out.println(e); + } + } + + /** + * @see org.apache.xerces.xni.XMLDocumentHandler#startDocument(org.apache.xerces.xni.XMLLocator, java.lang.String, org.apache.xerces.xni.NamespaceContext, org.apache.xerces.xni.Augmentations) + */ + public void startDocument(XMLLocator arg0, String arg1, NamespaceContext arg2, Augmentations arg3) + throws XNIException + { + locator = arg0; + super.startDocument(arg0, arg1, arg2, arg3); + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/XMLCatalog.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/XMLCatalog.java new file mode 100644 index 000000000..0a6cfaf70 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/XMLCatalog.java @@ -0,0 +1,364 @@ +/******************************************************************************* + * 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.xml; + +import java.io.File; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.xml.parsers.FactoryConfigurationError; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.apache.xerces.jaxp.SAXParserFactoryImpl; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * XMLCatalog This class can be used to register, obtain and delete an instance + * of an XML catalog. Method definitions are provided for the catalog to set a + * location in the catalog and resolve an entity from the catalog. + */ +public class XMLCatalog implements IXMLCatalog +{ + private final static String _APACHE_FEATURE_CONTINUE_AFTER_FATAL_ERROR = "http://apache.org/xml/features/continue-after-fatal-error"; + + private final static String _APACHE_FEATURE_NAMESPACE_PREFIXES = "http://xml.org/sax/features/namespace-prefixes"; + + private final static String _APACHE_FEATURE_NAMESPACES = "http://xml.org/sax/features/namespaces"; + + private final static String _APACHE_FEATURE_VALIDATION = "http://xml.org/sax/features/validation"; + + private final static String _APACHE_FEATURE_VALIDATION_SCHEMA = "http://apache.org/xml/features/validation/schema"; + + private final static String FILE_PROTOCOL = "file:///"; + + private static IXMLCatalog instance = null; + + private static String extxmlcatalogclass = null; + + private static ClassLoader extclassLoader = null; + + private static IXMLCatalog extXMLCatalogInstance = null; + + private static List schemadirs = new ArrayList(); + + private static List entities = new ArrayList(); + + /** + * A hashtable to hold the XML catalog entries. + */ + protected Map catalog = new Hashtable(); + + /** + * Return an instance of the XML catalog. Assigns all registered schemas to + * the XML catalog. + * + * @return The instance of the XML catalog. + */ + public static IXMLCatalog getInstance() + { + if (instance == null) + { + instance = new XMLCatalog(); + + // Add the registered entities to the catalog. + Iterator entityIter = entities.iterator(); + while (entityIter.hasNext()) + { + XMLCatalogEntityHolder entity = (XMLCatalogEntityHolder) entityIter.next(); + instance.addEntryToCatalog(entity.getPublicId(), entity.getSystemId()); + } + + // Add the schemas in the schema directories to the catalog. + if (schemadirs.size() > 0) + { + SAXParser saxParser = null; + try + { + SAXParserFactory parserfactory = new SAXParserFactoryImpl(); + parserfactory.setFeature(_APACHE_FEATURE_NAMESPACE_PREFIXES, true); + parserfactory.setFeature(_APACHE_FEATURE_NAMESPACES, true); + saxParser = parserfactory.newSAXParser(); + } + catch (FactoryConfigurationError e) + { + } + catch (SAXNotRecognizedException e) + { + } + catch (ParserConfigurationException e) + { + } + catch (SAXNotSupportedException e) + { + } + catch (SAXException e) + { + } + Iterator schemadirIter = schemadirs.iterator(); + SchemaNamespaceHandler handler = ((XMLCatalog) instance).new SchemaNamespaceHandler(); + while (schemadirIter.hasNext()) + { + String schemadir = (String) schemadirIter.next(); + registerSchemasForDir(instance, schemadir, saxParser, handler); + } + } + } + return instance; + } + + /** + * Register the schemas in the given directory and all subdirectories with the + * XML catalog. + * + * @param catalog + * The catalog to register the schemas with. + * @param schemadir + * The schema directory to search for schema files. + * @param parser + * The SAXParser to use to parse the schemas for their + * targetNamespace. + * @param handler + * The handler to use to get the targetNamespace. + */ + private static void registerSchemasForDir(IXMLCatalog catalog, String schemadir, SAXParser parser, + SchemaNamespaceHandler handler) + { + // Remove file: and file:/ from beginning of file location if they are present. + if(schemadir.startsWith("file:")) + { + schemadir = schemadir.substring(5); + } + while(schemadir.startsWith("//")) + { + schemadir = schemadir.substring(1); + } + + File dir = new File(schemadir); + if (dir.isDirectory()) + { + File[] files = dir.listFiles(); + int numfiles = files.length; + for (int i = 0; i < numfiles; i++) + { + File tempfile = files[i]; + String tempfilepath = tempfile.getAbsolutePath(); + tempfilepath = tempfilepath.replace('\\','/'); + while(tempfilepath.startsWith("/")) + { + tempfilepath = tempfilepath.substring(1); + } + tempfilepath = FILE_PROTOCOL + tempfilepath; + if (tempfile.isDirectory()) + { + registerSchemasForDir(catalog, tempfilepath, parser, handler); + } else + { + handler.reset(); + try + { + parser.parse(tempfilepath, handler); + } + catch (Exception e) + { + // TODO: log error. + } + String targetNamespace = handler.getTargetNamespace(); + if (targetNamespace != null) + { + catalog.addEntryToCatalog(targetNamespace, tempfilepath); + } + } + } + } + } + + /** + * Get the instance of the extension XML catalog. Returns the instance if one + * is registered and can be created, null otherwise. + * + * @return The instance of the extension XML catalog if one is registered, + * null otherwise. + */ + public static IXMLCatalog getExtensionCatalogInstance() + { + if (extXMLCatalogInstance == null) + { + if (extxmlcatalogclass != null && extclassLoader != null) + { + try + { + Class catalogClass = extclassLoader != null ? extclassLoader.loadClass(extxmlcatalogclass) : Class + .forName(extxmlcatalogclass); + extXMLCatalogInstance = (IXMLCatalog) catalogClass.newInstance(); + } + catch (Exception e) + { + //TODO: Log error + } + } + } + return extXMLCatalogInstance; + } + + /** + * Set the class of the XML catalog to be used. + * + * @param xmlcatalog + * The class of the XML catalog to be used. + * @param classloader + * The classloader to use to load the catalog. + */ + public static void setExtensionXMLCatalog(String xmlcatalog, ClassLoader classloader) + { + extxmlcatalogclass = xmlcatalog; + extclassLoader = classloader; + } + + /** + * Resets the instance of the XML catalog to null. For deleting the catalog if + * necessary. + */ + public static void reset() + { + instance = null; + extxmlcatalogclass = null; + extclassLoader = null; + extXMLCatalogInstance = null; + entities = new ArrayList(); + schemadirs = new ArrayList(); + } + + /** + * Add a schema directory to be checked for schemas to register in the + * catalog. + * + * @param schemadir + * The directory to check for schemas. + */ + public static void addSchemaDir(String schemadir) + { + schemadirs.add(schemadir); + } + + /** + * Add an entity to the catalog. + * + * @param entity + * The entity to add to the catalog. + */ + public static void addEntity(XMLCatalogEntityHolder entity) + { + entities.add(entity); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wsdl.validate.internal.xml.IXMLCatalog#addEntryToCatalog(java.lang.String, + * java.lang.String) + */ + public void addEntryToCatalog(String publicId, String systemId) + { + catalog.put(publicId, systemId); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wsdl.validate.internal.xml.IXMLCatalog#resolveEntityLocation(java.lang.String, + * java.lang.String) + */ + public String resolveEntityLocation(String publicId, String systemId) + { + String resolvedlocation = null; + // First try to resolve using the ext catalog. + IXMLCatalog extcatalog = getExtensionCatalogInstance(); + if (extcatalog != null) + { + resolvedlocation = extcatalog.resolveEntityLocation(publicId, systemId); + } + if (resolvedlocation == null) + { + // if there's no system id use the public id + if (systemId == null || systemId.equals("")) + { + systemId = publicId; + } + resolvedlocation = (String) catalog.get(systemId); + } + return resolvedlocation; + } + + /** + * A handler used in parsing to get the targetNamespace string of a schema. + */ + protected class SchemaNamespaceHandler extends DefaultHandler + { + private final String TARGET_NAMESPACE = "targetNamespace"; + + private final String SCHEMA = "schema"; + + private String targetNamespace = null; + + /** + * @see org.xml.sax.ContentHandler#startElement(java.lang.String, + * java.lang.String, java.lang.String, org.xml.sax.Attributes) + */ + public void startElement(String uri, String localname, String arg2, Attributes attributes) throws SAXException + { + if (localname.equals(SCHEMA)) + { + + int numAtts = attributes.getLength(); + for (int i = 0; i < numAtts; i++) + { + + String attname = attributes.getQName(i); + if (attname.equals(TARGET_NAMESPACE)) + { + targetNamespace = attributes.getValue(i); + } + } + + } + super.startElement(uri, localname, arg2, attributes); + } + + /** + * Return the targetNamespace found by parsing the file. + * + * @return The targetNamespace found by parsing the file. + */ + public String getTargetNamespace() + { + return targetNamespace; + } + + /** + * Reset the state of the handler so it can be reused. + */ + public void reset() + { + targetNamespace = null; + } + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/XMLCatalogEntityHolder.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/XMLCatalogEntityHolder.java new file mode 100644 index 000000000..5eca6ac92 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/XMLCatalogEntityHolder.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * 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.xml; + +/** + * A container to hold the entity information until an XML catalog is + * to be initialized. + */ +public class XMLCatalogEntityHolder +{ + private String publicId; + private String systemId; + + /** + * Constructor. + * + * @param publicId The public id of the entity. + * @param systemId The system id of the entity. + */ + public XMLCatalogEntityHolder(String publicId, String systemId) + { + this.publicId = publicId; + this.systemId = systemId; + } + + /** + * Returns the public id of the entity. + * @return The public id of the entity. + */ + public String getPublicId() + { + return publicId; + } + + /** + * Returns the system id of the entity. + * @return The system id of the entity. + */ + public String getSystemId() + { + return systemId; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/XMLCatalogResolver.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/XMLCatalogResolver.java new file mode 100644 index 000000000..0e850c0e5 --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/XMLCatalogResolver.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * 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.xml; + +import java.io.IOException; + +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.eclipse.wst.wsdl.validation.internal.util.LazyURLInputStream; + +/** + * A resolver to resolver entities from the XML catalog. + */ +public class XMLCatalogResolver implements XMLEntityResolver +{ + protected static XMLCatalogResolver xmlCatalog; + + /** + * Constructor. + */ + protected XMLCatalogResolver() + { + } + + /** + * Get the instance of this resolver. + * + * @return the instance of this resolver + */ + public static XMLCatalogResolver getInstance() + { + if (xmlCatalog == null) + { + xmlCatalog = new XMLCatalogResolver(); + } + return xmlCatalog; + } + + /** + * @see org.xml.sax.EntityResolver#resolveEntity(java.lang.String, java.lang.String) + */ + public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) throws XNIException, IOException + { + String publicId = resourceIdentifier.getPublicId(); + if(publicId == null) + { + publicId = resourceIdentifier.getNamespace(); + } + String systemId = resourceIdentifier.getLiteralSystemId(); + String location = XMLCatalog.getInstance().resolveEntityLocation(publicId, systemId); + if (location != null) + { + LazyURLInputStream is = new LazyURLInputStream(location); + XMLInputSource inputSource = new XMLInputSource(publicId, systemId, systemId, is, null); + return inputSource; + } + // otherwise return null to tell the parser to locate the systemId as a URI + return null; + } +} diff --git a/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/XMLMessageInfoHelper.java b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/XMLMessageInfoHelper.java new file mode 100644 index 000000000..443ab84ae --- /dev/null +++ b/bundles/org.eclipse.wst.wsdl.validation/src/org/eclipse/wst/wsdl/validation/internal/xml/XMLMessageInfoHelper.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2005 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.xml; + +public class XMLMessageInfoHelper +{ + + //see org.eclipse.wst.xml.ui.reconcile.DelegatingSourceValidator + protected static final String ALL_ATTRIBUTES = "ALL_ATTRIBUTES"; + protected static final String ATTRIBUTE_NAME ="ATTRIBUTE_NAME"; + protected static final String ATTRIBUTE_VALUE = "ATTRIBUTE_VALUE"; + protected static final String START_TAG = "START_TAG"; + protected static final String TEXT = "TEXT"; + protected static final String FIRST_NON_WHITESPACE_TEXT = "FIRST_NON_WHITESPACE_TEXT"; + protected static final String TEXT_ENTITY_REFERENCE = "TEXT_ENTITY_REFERENCE"; + protected static final String VALUE_OF_ATTRIBUTE_WITH_GIVEN_VALUE = "VALUE_OF_ATTRIBUTE_WITH_GIVEN_VALUE"; + + + public XMLMessageInfoHelper() + { + super(); + } + + /** + * returns an array containing information about what should be underlined with the red "squiggles" + * using the errorKey, and the messageArguments + * <br>Position 0 of the array returned contains the selection Strategy,or what DOM Element to underline. + * For example "ATTRIBUTE_NAME" + * <br>Position 1 contains the name or value to squiggle. + * <p>For example, if we wanted to squiggle the attribute name of an attribute name + * foo this method would return {"ATTRIBUTE_NAME", "foo"} + * </p> + * @param errorKey the error key given by the Xerces parser + * @param messageArguments the arguments used by Xerces to "fill in the blanks" of their messages + * @return an array containing the squiggle information + * @see org.eclipse.wst.xml.ui.reconcile.DelegatingReconcileValidator + * + */ + public String[] createMessageInfo(String errorKey, Object[] messageArguments) + { + String selectionStrategy = null; + String nameOrValue = null; + + //XML Errors + if (errorKey.equals("cvc-complex-type.2.4.a") || errorKey.equals("cvc-complex-type.2.4.d") || errorKey.equals("cvc-complex-type.2.4.b") || errorKey.equals("MSG_CONTENT_INVALID") + | errorKey.equals("MSG_CONTENT_INCOMPLETE") || errorKey.equals("MSG_REQUIRED_ATTRIBUTE_NOT_SPECIFIED") || errorKey.equals("cvc-complex-type.4")) + { + selectionStrategy = START_TAG; + } + else if (errorKey.equals("cvc-type.3.1.3")) + { + selectionStrategy = TEXT; + } + else if (errorKey.equals("cvc-complex-type.2.3")) + { + selectionStrategy = FIRST_NON_WHITESPACE_TEXT; + } + else if (errorKey.equals("cvc-type.3.1.1")) + { + selectionStrategy = ALL_ATTRIBUTES; + } + else if (errorKey.equals("cvc-complex-type.3.2.2") || errorKey.equals("MSG_ATTRIBUTE_NOT_DECLARED")) + { + selectionStrategy = ATTRIBUTE_NAME; + //in this case we need nameOrValue to be the name of the attribute to underline + nameOrValue = (String)messageArguments[1]; + } + else if (errorKey.equals("cvc-attribute.3") || errorKey.equals("MSG_ATTRIBUTE_VALUE_NOT_IN_LIST")) + { + selectionStrategy = ATTRIBUTE_VALUE; + //in this case we need nameOrValue to be the name of the Attribute + if (errorKey.equals("cvc-attribute.3")) + { nameOrValue = (String)messageArguments[1]; + } + else if (errorKey.equals("MSG_ATTRIBUTE_VALUE_NOT_IN_LIST")) + { nameOrValue = (String)messageArguments[0]; + } + } + else if (errorKey.equals("cvc-elt.4.2")) + { selectionStrategy=VALUE_OF_ATTRIBUTE_WITH_GIVEN_VALUE; + //in this case we need nameOrValue to be the value of the attribute we want to unerline + nameOrValue = (String)messageArguments[1]; + } + else if (errorKey.equals("EntityNotDeclared")) + { selectionStrategy=TEXT_ENTITY_REFERENCE; + } + + + //WSDL Errors + else if (errorKey.equals("_MESSAGE_UNDEFINED_FOR_OUTPUT") || + errorKey.equals("_MESSAGE_UNDEFINED_FOR_INPUT") || + errorKey.equals("_MESSAGE_UNDEFINED_FOR_FAULT")) + { + selectionStrategy=ATTRIBUTE_VALUE; + nameOrValue= "message"; + } + else if (errorKey.equals("_PORTTYPE_UNDEFINED_FOR_BINDING")) + { + selectionStrategy=ATTRIBUTE_VALUE; + nameOrValue="type"; + } + else if (errorKey.equals("_OPERATION_UNDEFINED_FOR_PORTTYPE")) + { + selectionStrategy=ATTRIBUTE_VALUE; + nameOrValue="name"; + } + else if (errorKey.equals("_PART_INVALID_ELEMENT")) + { + selectionStrategy=ATTRIBUTE_VALUE; + nameOrValue="element"; + } + else if (errorKey.equals("_NO_BINDING_FOR_PORT")) + { + selectionStrategy=ATTRIBUTE_VALUE; + nameOrValue="binding"; + } + + String messageInfo[] = new String[2]; + messageInfo[0] = selectionStrategy; + messageInfo[1] = nameOrValue; + return messageInfo; + } +} |