/******************************************************************************* * Copyright (c) 2011, 2015 Willink Transformations 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: * E.D.Willink - initial API and implementation *******************************************************************************/ package org.eclipse.ocl.xtext.base.utilities; import java.util.Collections; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; import org.eclipse.emf.common.util.BasicDiagnostic; import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.util.Diagnostician; import org.eclipse.emf.ecore.util.EObjectValidator; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.ocl.pivot.utilities.LabelUtil; import org.eclipse.ocl.xtext.base.cs2as.CS2AS; import org.eclipse.xtext.diagnostics.Severity; import org.eclipse.xtext.resource.XtextResource; import org.eclipse.xtext.util.CancelIndicator; import org.eclipse.xtext.util.IAcceptor; import org.eclipse.xtext.validation.AbstractInjectableValidator; import org.eclipse.xtext.validation.CancelableDiagnostician; import org.eclipse.xtext.validation.CheckMode; import org.eclipse.xtext.validation.CheckType; import org.eclipse.xtext.validation.Issue; import org.eclipse.xtext.validation.ResourceValidatorImpl; import org.eclipse.xtext.validation.impl.ConcreteSyntaxEValidator; import com.google.common.collect.Lists; /** * PivotResourceValidator extends CS Resource validation to the referenced Pivot resources and attempts * to indicate Pivot validation problems in the appropriate CS context. */ public class PivotResourceValidator extends ResourceValidatorImpl { public static class ValidationDiagnostic extends BasicDiagnostic implements Resource.Diagnostic { private ValidationDiagnostic() { super(EObjectValidator.DIAGNOSTIC_SOURCE, 0, "", null); } @Override public int getColumn() { return 0; // This could be computed from the CS } @Override public int getLine() { return 0; // This could be computed from the CS } @Override public String getLocation() { return null; // This could be computed from the CS } public Integer getOffset() { return null; // This could be computed from the CS } public Integer getLength() { return 10; // This could be computed from the CS } } private static final Logger log = Logger.getLogger(PivotResourceValidator.class); public static final String HAS_SYNTAX_ERRORS = "has_syntax_errors"; protected ValidationDiagnostic createDefaultDiagnostic(Diagnostician diagnostician, EObject pivotObject) { // Object objectLabel = diagnostician.getObjectLabel(pivotObject); // return new ValidationDiagnostic(EcorePlugin.INSTANCE.getString("_UI_DiagnosticRoot_diagnostic", // new Object[] { objectLabel }), new Object[] { pivotObject }); return new ValidationDiagnostic(); } protected void issueFromDiagnostics(IAcceptor<Issue> acceptor, ValidationDiagnostic diagnostic) { for (Diagnostic childDiagnostic : diagnostic.getChildren()) { // System.out.println(" issueFromEValidatorDiagnostic " + childDiagnostic); issueFromEValidatorDiagnostic(childDiagnostic, acceptor); } } protected void performValidation(IAcceptor<Issue> acceptor, Resource asResource, CancelIndicator monitor) { // System.out.println(Thread.currentThread().getName() + " performValidation " + NameUtil.debugSimpleName(asResource)); Diagnostician diagnostician = getDiagnostician(); Map<Object, Object> context = LabelUtil.createDefaultContext(diagnostician); // List<Resource> resources = asResource.getResourceSet().getResources(); // for (int i = 0; i < resources.size(); i++) { Resource pResource = asResource; //resources.get(i); // if (PivotConstants.ORPHANAGE_URI.equals(String.valueOf(pResource.getURI()))) { // continue; // GC may not have eliminated all the dangling references // } // System.out.println(" performValidation " + pResource.getURI() + " on " + Thread.currentThread().getName()); removeValidationDiagnostics(pResource.getErrors()); removeValidationDiagnostics(pResource.getWarnings()); List<EObject> contents = pResource.getContents(); for (int j = 0; j < contents.size(); j++) { // Beware concurrent unload try { if (monitor.isCanceled()) return; EObject pObject = contents.get(j); ValidationDiagnostic diagnostic = createDefaultDiagnostic(diagnostician, pObject); diagnostician.validate(pObject, diagnostic, context); if (!diagnostic.getChildren().isEmpty()) { if (diagnostic.getSeverity() == Diagnostic.ERROR) { pResource.getErrors().add(diagnostic); } else if (diagnostic.getSeverity() == Diagnostic.WARNING) { pResource.getWarnings().add(diagnostic); } issueFromDiagnostics(acceptor, diagnostic); } } catch (RuntimeException e) { if (!monitor.isCanceled()) { log.error(e.getMessage(), e); } } } // } } protected void removeValidationDiagnostics(List<Resource.Diagnostic> diagnostics) { // System.out.println(Thread.currentThread().getName() + " removeValidationDiagnostics "); for (int i = diagnostics.size()-1; i >= 0; i--) { Resource.Diagnostic diagnostic = diagnostics.get(i); if (diagnostic instanceof ValidationDiagnostic) { diagnostics.remove(i); } } } /* protected void reuseValidation(IAcceptor<Issue> acceptor, Resource asResource, CancelIndicator monitor) { // System.out.println(Thread.currentThread().getName() + " reuseValidation " + NameUtil.debugSimpleName(asResource)); ResourceSet resourceSet = asResource.getResourceSet(); if (resourceSet != null) { for (Resource pResource : resourceSet.getResources()) { // System.out.println(" reuseValidation " + pResource.getURI() + " on " + Thread.currentThread().getName()); for (Resource.Diagnostic diagnostic : pResource.getErrors()) { if (diagnostic instanceof ValidationDiagnostic) { issueFromDiagnostics(acceptor, (ValidationDiagnostic)diagnostic); } } for (Resource.Diagnostic diagnostic : pResource.getWarnings()) { if (diagnostic instanceof ValidationDiagnostic) { issueFromDiagnostics(acceptor, (ValidationDiagnostic)diagnostic); } } } } } */ // FIXME BUG 389675 Remove duplication with respect to inherited method @Override public List<Issue> validate(Resource resource, final CheckMode mode, CancelIndicator mon) { // System.out.println(Thread.currentThread().getName() + " validate start " + NameUtil.debugSimpleName(resource)); // System.out.println(new Date() + " Validate " + mode + " : " + csResource.getURI() + " on " + Thread.currentThread().getName()); final CancelIndicator monitor = mon == null ? CancelIndicator.NullImpl : mon; resolveProxies(resource, monitor); if (monitor.isCanceled()) return Collections.emptyList(); final List<Issue> result = Lists.newArrayListWithExpectedSize(resource.getErrors().size() + resource.getWarnings().size()); try { IAcceptor<Issue> acceptor = createAcceptor(result); // Syntactical and linking errors // Collect EMF Resource Diagnostics if (mode.shouldCheck(CheckType.FAST)) { for (int i = 0; i < resource.getErrors().size(); i++) { if (monitor.isCanceled()) return Collections.emptyList(); issueFromXtextResourceDiagnostic(resource.getErrors().get(i), Severity.ERROR, acceptor); } for (int i = 0; i < resource.getWarnings().size(); i++) { if (monitor.isCanceled()) return Collections.emptyList(); issueFromXtextResourceDiagnostic(resource.getWarnings().get(i), Severity.WARNING, acceptor); } } if (monitor.isCanceled()) return Collections.emptyList(); boolean syntaxDiagFail = !result.isEmpty(); logCheckStatus(resource, syntaxDiagFail, "Syntax"); // Validation errors // Collect validator Diagnostics for (EObject ele : resource.getContents()) { try { if (monitor.isCanceled()) return Collections.emptyList(); Diagnostician diagnostician = getDiagnostician(); Map<Object, Object> options = LabelUtil.createDefaultContext(diagnostician); options.put(CheckMode.KEY, mode); options.put(CancelableDiagnostician.CANCEL_INDICATOR, monitor); // disable concrete syntax validation, since a semantic model that has been parsed // from the concrete syntax always complies with it - otherwise there are parse errors. options.put(ConcreteSyntaxEValidator.DISABLE_CONCRETE_SYNTAX_EVALIDATOR, Boolean.TRUE); // see EObjectValidator.getRootEValidator(Map<Object, Object>) boolean hasSyntaxError = false; if (resource instanceof XtextResource) { options.put(AbstractInjectableValidator.CURRENT_LANGUAGE_NAME, ((XtextResource) resource).getLanguageName()); if (resource instanceof BaseCSResource) { BaseCSResource csResource = (BaseCSResource)resource; @SuppressWarnings("null") @NonNull List<Resource.Diagnostic> errors = csResource.getErrors(); hasSyntaxError = ElementUtil.hasSyntaxError(errors); if (hasSyntaxError) { options.put(PivotResourceValidator.HAS_SYNTAX_ERRORS, Boolean.TRUE); } } } if (!hasSyntaxError) { Diagnostic diagnostic = getDiagnostician().validate(ele, options); if (!diagnostic.getChildren().isEmpty()) { for (Diagnostic childDiagnostic : diagnostic.getChildren()) { issueFromEValidatorDiagnostic(childDiagnostic, acceptor); } } else { issueFromEValidatorDiagnostic(diagnostic, acceptor); } } } catch (RuntimeException e) { if (!monitor.isCanceled()) { // Fix Bug 462544 working around Xtext Bug 461764 log.error(e.getMessage(), e); } } } } catch (RuntimeException e) { log.error(e.getMessage(), e); } if (monitor.isCanceled()) return Collections.emptyList(); if (resource instanceof BaseCSResource) { BaseCSResource csResource = (BaseCSResource)resource; CS2AS cs2as = csResource.findCS2AS(); if (cs2as != null) { Resource asResource = cs2as.getASResource(); IAcceptor<Issue> acceptor = createAcceptor(result); // if (mode.shouldCheck(CheckType.EXPENSIVE)) { performValidation(acceptor, asResource, monitor); // } // else { // reuseValidation(acceptor, asResource, monitor); // } } } // System.out.println(Thread.currentThread().getName() + " validate end " + NameUtil.debugSimpleName(resource)); return result; } private void logCheckStatus(final Resource resource, boolean parserDiagFail, String string) { if (log.isDebugEnabled()) { log.debug(string + " check " + (parserDiagFail ? "FAIL" : "OK") + "! Resource: " + resource.getURI()); } } }