/******************************************************************************* * Copyright (c) 2010 SAP AG. * 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: * Emil Simeonov - initial API and implementation. * Dimitar Donchev - initial API and implementation. * Dimitar Tenev - initial API and implementation. * Nevena Manova - initial API and implementation. * Georgi Konstantinov - initial API and implementation. *******************************************************************************/ package org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability; import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.NAMESPACE_FOR_IMPORTED_SCHEMA_MUST_NOT_BE_RELATIVE; import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.THE_DOCUMENT_DOESNOT_HAVE_APPROPRIATE_VERSION_AND_ENCODING; import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.UTF_16; import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.UTF_8; import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.VERSION; import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.XML; import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.XML_NAMESPACE_SHOULD_NOT_BE_CONTAINED_IN_DESCRIPTION; import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.versionAttribute; import java.net.URI; import java.net.URISyntaxException; import java.util.Collection; import java.util.HashSet; import org.eclipse.core.runtime.IStatus; import org.eclipse.emf.validation.IValidationContext; import org.eclipse.emf.validation.model.ConstraintStatus; import org.eclipse.wst.wsdl.util.WSDLConstants; import org.eclipse.xsd.XSDConcreteComponent; import org.eclipse.xsd.XSDImport; import org.eclipse.xsd.XSDSchema; import org.eclipse.xsd.XSDSchemaContent; import org.eclipse.xsd.impl.XSDImportImpl; import org.eclipse.xsd.util.XSDConstants; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.eclipse.wst.sse.sieditor.model.validation.constraints.AbstractConstraint; public class WSISchemaCompliant extends AbstractConstraint { private XSDSchema schema; @Override protected IStatus doValidate(IValidationContext validationContext) { this.schema = (XSDSchema) validationContext.getTarget(); final Collection<IStatus> statuses = new HashSet<IStatus>(); checkWhetherXMLNamespaceAppear(validationContext, statuses); Collection<XSDSchema> schemasForChecking = getImportedSchemasAndCheckForAbsolutePath(this.schema.getContents(), statuses, validationContext); checkEncodingAndVersionOfAllUsedSchemas(validationContext, statuses, schemasForChecking); if (statuses.isEmpty()) { return ConstraintStatus.createSuccessStatus(validationContext, this.schema, null); } else { return ConstraintStatus.createMultiStatus(validationContext, statuses); } } /** * R1034 A DESCRIPTION SHOULD NOT contain the namespace declaration * xmlns:xml="http://www.w3.org/XML/1998/namespace". * * @param validationContext * is the parameter from the doValidate(..) method * @param statuses * is the list of statuses which will be returned from the * doValidate(..) method */ private void checkWhetherXMLNamespaceAppear(IValidationContext validationContext, final Collection<IStatus> statuses) { String xmlnsAttributeValue = this.schema.getElement().getAttributeNS(XSDConstants.XMLNS_URI_2000, XML); if (XSDConstants.XML_NAMESPACE_URI_1998.equals(xmlnsAttributeValue)) { statuses.add(ConstraintStatus.createStatus(validationContext, this.schema, null, XML_NAMESPACE_SHOULD_NOT_BE_CONTAINED_IN_DESCRIPTION, XML_NAMESPACE_SHOULD_NOT_BE_CONTAINED_IN_DESCRIPTION)); } } /** * R2010 An XML Schema directly or indirectly imported by a DESCRIPTION MUST * use either UTF-8 or UTF-16 encoding. * * R2011 An XML Schema directly or indirectly imported by a DESCRIPTION MUST * use version 1.0 of the eXtensible Markup Language W3C Recommendation. * * R4004 A DESCRIPTION MUST use version 1.0 of the eXtensible Markup * Language W3C Recommendation. * * @param validationContext * is the parameter from the doValidate(..) method * @param statuses * is the list of statuses which will be returned from the * doValidate(..) method * * @param schemasForChecking * is a Collection of all imported schemas in the this.schema */ private void checkEncodingAndVersionOfAllUsedSchemas(IValidationContext validationContext, final Collection<IStatus> statuses, Collection<XSDSchema> schemasForChecking) { for (XSDSchema currentXsdSchema : schemasForChecking) { if (currentXsdSchema == null) { continue; } Document document = currentXsdSchema.getDocument(); if (document == null) { continue; } Node node = document.getFirstChild(); if (node != null) { statuses.add(getStatusAccordingToXMLEncodingAndVersion(validationContext, currentXsdSchema, node .getOwnerDocument())); } else { statuses.add(createStatusForInappropriateXMLVersionOrEncoding(validationContext)); } } } private IStatus getStatusAccordingToXMLEncodingAndVersion(IValidationContext validationContext, XSDSchema currentXsdSchema, Document ownerDocument) { if (ownerDocument == null) { return createStatusForInappropriateXMLVersionOrEncoding(validationContext); } String encoding = null; try { encoding = ownerDocument.getXmlEncoding(); } catch (DOMException exception) { IStatus status = handleDomException(validationContext, ownerDocument); return status; } if (encoding == null || !(encoding.equalsIgnoreCase(UTF_8) || encoding.equalsIgnoreCase(UTF_16))) { return createStatusForInappropriateXMLVersionOrEncoding(validationContext); } String actualXMLVersion = null; try { actualXMLVersion = ownerDocument.getXmlVersion(); } catch (DOMException exception) { IStatus status = handleDomException(validationContext, ownerDocument); return status; } if (actualXMLVersion == null || !actualXMLVersion.equalsIgnoreCase(VERSION)) { return createStatusForInappropriateXMLVersionOrEncoding(validationContext); } return ConstraintStatus.createSuccessStatus(validationContext, this.schema, null); } private IStatus handleDomException(IValidationContext validationContext, Document ownerDocument) { Node node = ownerDocument.getFirstChild(); if (node != null) { return statusForEncodingAndVersion(node.getNodeValue(), validationContext); } else { return ConstraintStatus.createSuccessStatus(validationContext, this.schema, null); } } private IStatus statusForEncodingAndVersion(String aValueOfXMLProcessInstruction, IValidationContext validationContext) { if (aValueOfXMLProcessInstruction == null) { return createStatusForInappropriateXMLVersionOrEncoding(validationContext); } if (!((aValueOfXMLProcessInstruction.contains(WSDLConstants.ENCODING_ATTRIBUTE) && (aValueOfXMLProcessInstruction .contains(UTF_8) || aValueOfXMLProcessInstruction.contains(UTF_16))))) { return createStatusForInappropriateXMLVersionOrEncoding(validationContext); } if (!(aValueOfXMLProcessInstruction.contains(versionAttribute) && aValueOfXMLProcessInstruction.contains(VERSION))) { return createStatusForInappropriateXMLVersionOrEncoding(validationContext); } return ConstraintStatus.createSuccessStatus(validationContext, this.schema, null); } private IStatus createStatusForInappropriateXMLVersionOrEncoding(IValidationContext validationContext) { return ConstraintStatus.createStatus(validationContext, this.schema, null, THE_DOCUMENT_DOESNOT_HAVE_APPROPRIATE_VERSION_AND_ENCODING, THE_DOCUMENT_DOESNOT_HAVE_APPROPRIATE_VERSION_AND_ENCODING); } public static final Collection<XSDSchema> getImportedSchemasAndCheckForAbsolutePath( final Collection<? extends XSDSchemaContent> components, final Collection<IStatus> statuses, IValidationContext validationContext) { final Collection<XSDSchema> importedSchemas = new HashSet<XSDSchema>(); for (final XSDConcreteComponent component : components) { if (!(component instanceof XSDImportImpl)) { continue; } XSDImportImpl xsdImport = (XSDImportImpl) component; checkWhetherTheNamespaceAttributeHasAbsolutePath(statuses, validationContext, xsdImport); if (xsdImport.getSchemaLocation() != null) { importedSchemas.add(xsdImport.importSchema()); } } return importedSchemas; } /** * The namespace attribute of the xsd:import MUST NOT be a relative URI * * @param validationContext * is the parameter from the doValidate(..) method * @param statuses * is the list of statuses which will be returned from the * doValidate(..) method * @param xsdImport * is a not null xsd:import EMF object */ private static void checkWhetherTheNamespaceAttributeHasAbsolutePath(final Collection<IStatus> statuses, IValidationContext validationContext, XSDImport xsdImport) { try { String namespace = xsdImport.getNamespace(); if (namespace == null) { return; } URI uri = new URI(namespace); if (!uri.isAbsolute()) { createStatusForNonAbsoluteNamespaceAttribute(statuses, validationContext, xsdImport); } } catch (URISyntaxException e) { createStatusForNonAbsoluteNamespaceAttribute(statuses, validationContext, xsdImport); } } private static void createStatusForNonAbsoluteNamespaceAttribute(final Collection<IStatus> statuses, IValidationContext validationContext, XSDImport xsdImport) { statuses.add(ConstraintStatus.createStatus(validationContext, xsdImport, null, NAMESPACE_FOR_IMPORTED_SCHEMA_MUST_NOT_BE_RELATIVE, NAMESPACE_FOR_IMPORTED_SCHEMA_MUST_NOT_BE_RELATIVE)); } @Override protected boolean shouldExecute(IValidationContext ctx) { return true; } }