| /******************************************************************************* |
| * 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; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.validation.IValidationContext; |
| import org.eclipse.emf.validation.model.ConstraintStatus; |
| import org.eclipse.xsd.XSDAttributeDeclaration; |
| import org.eclipse.xsd.XSDConcreteComponent; |
| import org.eclipse.xsd.XSDDiagnostic; |
| import org.eclipse.xsd.XSDElementDeclaration; |
| import org.eclipse.xsd.XSDMaxExclusiveFacet; |
| import org.eclipse.xsd.XSDMaxInclusiveFacet; |
| import org.eclipse.xsd.XSDMinExclusiveFacet; |
| import org.eclipse.xsd.XSDMinInclusiveFacet; |
| import org.eclipse.xsd.XSDPackage; |
| import org.eclipse.xsd.XSDSchema; |
| import org.eclipse.xsd.XSDSimpleTypeDefinition; |
| import org.w3c.dom.Node; |
| |
| import org.eclipse.wst.sse.sieditor.model.i18n.Messages; |
| import org.eclipse.wst.sse.sieditor.model.utils.EmfXsdUtils; |
| |
| public class ValidXSDEntity extends AbstractConstraint { |
| |
| private Set<EClass> featureClasses = new HashSet<EClass>(); |
| |
| private IStatus convertDiagnosticsToStatus(final IValidationContext ctx, final List<XSDDiagnostic> diagnostics, |
| XSDSchema schema) { |
| final List<IStatus> statusList = new ArrayList<IStatus>(); |
| statusList.add(ConstraintStatus.createSuccessStatus(ctx, schema, null)); |
| if (diagnostics.size() == 0) { |
| final EObject target = ctx.getTarget(); |
| if (target instanceof XSDDiagnostic) { |
| final XSDDiagnostic diagnostic = (XSDDiagnostic) target; |
| diagnostic.getPrimaryComponent().getDiagnostics().add(diagnostic); |
| } |
| statusList.add(ConstraintStatus.createSuccessStatus(ctx, target, null)); |
| } |
| |
| for (XSDDiagnostic diagnostic : new LinkedList<XSDDiagnostic>(diagnostics)) { |
| int severity = IStatus.INFO; |
| switch (diagnostic.getSeverity()) { |
| case FATAL_LITERAL: |
| case ERROR_LITERAL: |
| severity = IStatus.ERROR; |
| break; |
| case WARNING_LITERAL: |
| severity = IStatus.WARNING; |
| } |
| |
| Collection<EObject> resultLocus = new ArrayList<EObject>(); |
| |
| // add the feature to the result locus |
| // IValidationContext#getFeature() does not work the way it is |
| // supposed to |
| EStructuralFeature feature = findFailedConstraintTrigger(diagnostic); |
| |
| if (feature != null) { |
| resultLocus.add(feature); |
| } |
| |
| // add other components to result locus |
| resultLocus.addAll(diagnostic.getComponents()); |
| |
| diagnostic.getPrimaryComponent().getDiagnostics().add(diagnostic); |
| statusList.add(ConstraintStatus.createStatus(ctx, diagnostic, resultLocus, diagnostic.getMessage(), severity, |
| diagnostic.getSubstitutions())); |
| } |
| |
| return createStatus(ctx, statusList); |
| } |
| |
| public ValidXSDEntity() { |
| super(); |
| featureClasses.add(XSDPackage.Literals.XSD_NAMED_COMPONENT); |
| featureClasses.add(XSDPackage.Literals.XSD_TOTAL_DIGITS_FACET); |
| featureClasses.add(XSDPackage.Literals.XSD_MIN_LENGTH_FACET); |
| featureClasses.add(XSDPackage.Literals.XSD_MAX_LENGTH_FACET); |
| featureClasses.add(XSDPackage.Literals.XSD_LENGTH_FACET); |
| featureClasses.add(XSDPackage.Literals.XSD_ENUMERATION_FACET); |
| featureClasses.add(XSDPackage.Literals.XSD_WHITE_SPACE_FACET); |
| |
| } |
| |
| @Override |
| protected IStatus doValidate(IValidationContext ctx) { |
| final XSDSchema schema = ((XSDConcreteComponent) ctx.getTarget()).getSchema(); |
| // without this check the XSD API throws NPEs everywhere |
| if (EmfXsdUtils.isSchemaElementMissing(schema)) { |
| return ConstraintStatus.createStatus(ctx, schema, ctx.getResultLocus(), |
| Messages.ValidXSDEntity_Missing_Schema_Element0, IStatus.ERROR); |
| } |
| if (EmfXsdUtils.isSchemaForSchemaMissing(schema)) { |
| return ConstraintStatus.createStatus(ctx, schema, ctx.getResultLocus(), Messages.EmfXsdUtils_MissingSchemaForSchema1, |
| IStatus.ERROR); |
| } |
| schema.clearDiagnostics(); |
| schema.validate(); |
| |
| return convertDiagnosticsToStatus(ctx, schema.getAllDiagnostics(), schema); |
| } |
| |
| @Override |
| protected boolean shouldExecute(IValidationContext ctx) { |
| EObject target = ctx.getTarget(); |
| if (isBatchValidation(ctx)) { |
| return (target instanceof XSDSchema); |
| } |
| |
| return !(target instanceof XSDDiagnostic); |
| } |
| |
| /** |
| * Tries to find the particular feature which triggered the constraint |
| */ |
| public EStructuralFeature findFailedConstraintTrigger(XSDDiagnostic diagnostic) { |
| |
| // First check if the constraint failed in an attribute and try to find |
| // the feature which corresponds to this attribute |
| Node node = diagnostic.getNode(); |
| EStructuralFeature feature = null; |
| if (node.getNodeType() == Node.ATTRIBUTE_NODE) { |
| String nodeName = node.getNodeName(); |
| feature = diagnostic.getContainer().eClass().getEStructuralFeature(nodeName); |
| if (feature != null) { |
| EClass eClass = feature.getEContainingClass(); |
| // this is done because for example xsd min exclusive and xsd |
| // min exclusive have both the same feature class |
| // - XSD_MIN_FACET and cannot be distinguished |
| if (featureClasses.contains(eClass)) { |
| return feature; |
| } |
| } |
| |
| } |
| // Now try to find the feature by examining the primary component in |
| // which the constraint failed |
| XSDConcreteComponent component = diagnostic.getPrimaryComponent(); |
| |
| if (component instanceof XSDMinExclusiveFacet) { |
| return XSDPackage.Literals.XSD_MIN_FACET__EXCLUSIVE; |
| |
| } else if (component instanceof XSDMinInclusiveFacet) { |
| return XSDPackage.Literals.XSD_MIN_FACET__INCLUSIVE; |
| |
| } else if (component instanceof XSDMaxInclusiveFacet) { |
| return XSDPackage.Literals.XSD_MAX_FACET__INCLUSIVE; |
| |
| } else if (component instanceof XSDMaxExclusiveFacet) { |
| return XSDPackage.Literals.XSD_MAX_FACET__EXCLUSIVE; |
| |
| } |
| // if the component was none of the above check again if the constrained |
| // failed in an attribute; if it was not an attribute |
| // we can assume the following 2 cases to be true |
| if (feature != null) { |
| return feature; |
| } |
| // if the constraint failed in the simple type definition and not in one |
| // of its attributes it must be in its base type |
| else if (component instanceof XSDSimpleTypeDefinition) { |
| return XSDPackage.Literals.XSD_TYPE_DEFINITION__BASE_TYPE; |
| } |
| // if the constraint failed in the element or attribute |
| // declaration and not in one of its attributes it must be in its type; |
| // Use the XSD_TYPE_DEFINITION__ANNOTATION constant |
| // to mark it since there is no constant combining simple and |
| // complex types |
| else if (component instanceof XSDElementDeclaration || component instanceof XSDAttributeDeclaration) { |
| return XSDPackage.Literals.XSD_TYPE_DEFINITION__ANNOTATION; |
| |
| } |
| |
| return null; |
| } |
| } |