org.eclipse.xtext.validation.ResourceValidatorImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.xtext.validation.ResourceValidatorImpl.java

Source

/*******************************************************************************
 * Copyright (c) 2008 itemis AG (http://www.itemis.eu) 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
 *
 *******************************************************************************/
package org.eclipse.xtext.validation;

import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EValidator;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.diagnostics.Severity;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.service.OperationCanceledError;
import org.eclipse.xtext.service.OperationCanceledManager;
import org.eclipse.xtext.util.CancelIndicator;
import org.eclipse.xtext.util.IAcceptor;
import org.eclipse.xtext.util.internal.Stopwatches;
import org.eclipse.xtext.util.internal.Stopwatches.StoppedTask;
import org.eclipse.xtext.validation.impl.ConcreteSyntaxEValidator;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Inject;

/**
 * @author Dennis Hbner - Initial contribution and API
 */
public class ResourceValidatorImpl implements IResourceValidator {

    /**
     * @author Sebastian Zarnekow - Initial contribution and API
     */
    protected static class ListBasedMarkerAcceptor implements IAcceptor<Issue> {
        private final List<Issue> result;

        protected ListBasedMarkerAcceptor(List<Issue> result) {
            this.result = result;
        }

        @Override
        public void accept(Issue issue) {
            if (issue != null)
                result.add(issue);
        }
    }

    private static final Logger log = Logger.getLogger(ResourceValidatorImpl.class);

    @Inject
    private Diagnostician diagnostician;

    @Inject
    private IDiagnosticConverter converter;

    @Inject
    private OperationCanceledManager operationCanceledManager;

    @Override
    public List<Issue> validate(Resource resource, final CheckMode mode, CancelIndicator mon)
            throws OperationCanceledError {
        StoppedTask task = Stopwatches.forTask("ResourceValidatorImpl.validation");
        try {
            task.start();
            final CancelIndicator monitor = mon == null ? CancelIndicator.NullImpl : mon;
            resolveProxies(resource, monitor);
            operationCanceledManager.checkCanceled(monitor);

            final List<Issue> result = Lists
                    .newArrayListWithExpectedSize(resource.getErrors().size() + resource.getWarnings().size());
            try {
                IAcceptor<Issue> acceptor = createAcceptor(result);

                if (mode.shouldCheck(CheckType.FAST)) {
                    collectResourceDiagnostics(resource, monitor, acceptor);
                }

                operationCanceledManager.checkCanceled(monitor);
                boolean syntaxDiagFail = !result.isEmpty();
                logCheckStatus(resource, syntaxDiagFail, "Syntax");

                validate(resource, mode, monitor, acceptor);
                operationCanceledManager.checkCanceled(monitor);
            } catch (RuntimeException e) {
                operationCanceledManager.propagateAsErrorIfCancelException(e);
                log.error(e.getMessage(), e);
            }
            return result;
        } finally {
            task.stop();
        }
    }

    /**
     * @since 2.7
     */
    protected void collectResourceDiagnostics(Resource resource, final CancelIndicator monitor,
            IAcceptor<Issue> acceptor) {
        for (int i = 0; i < resource.getErrors().size(); i++) {
            operationCanceledManager.checkCanceled(monitor);
            issueFromXtextResourceDiagnostic(resource.getErrors().get(i), Severity.ERROR, acceptor);
        }

        for (int i = 0; i < resource.getWarnings().size(); i++) {
            operationCanceledManager.checkCanceled(monitor);
            issueFromXtextResourceDiagnostic(resource.getWarnings().get(i), Severity.WARNING, acceptor);
        }
    }

    /**
     * @since 2.4
     */
    protected void validate(Resource resource, final CheckMode mode, final CancelIndicator monitor,
            IAcceptor<Issue> acceptor) {
        for (EObject ele : resource.getContents()) {
            operationCanceledManager.checkCanceled(monitor);
            validate(resource, ele, mode, monitor, acceptor);
        }
    }

    /**
     * @since 2.4
     */
    protected void validate(Resource resource, EObject element, final CheckMode mode, final CancelIndicator monitor,
            IAcceptor<Issue> acceptor) {
        try {
            Map<Object, Object> options = Maps.newHashMap();
            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>)
            options.put(EValidator.class, diagnostician);
            if (resource instanceof XtextResource) {
                options.put(AbstractInjectableValidator.CURRENT_LANGUAGE_NAME,
                        ((XtextResource) resource).getLanguageName());
            }
            Diagnostic diagnostic = diagnostician.validate(element, options);
            if (!diagnostic.getChildren().isEmpty()) {
                for (Diagnostic childDiagnostic : diagnostic.getChildren()) {
                    issueFromEValidatorDiagnostic(childDiagnostic, acceptor);
                }
            } else {
                issueFromEValidatorDiagnostic(diagnostic, acceptor);
            }
        } catch (RuntimeException e) {
            operationCanceledManager.propagateAsErrorIfCancelException(e);
            log.error(e.getMessage(), e);
        }
    }

    protected void resolveProxies(final Resource resource, final CancelIndicator monitor) {
        EcoreUtil2.resolveLazyCrossReferences(resource, monitor);
    }

    protected IAcceptor<Issue> createAcceptor(final List<Issue> result) {
        return new ListBasedMarkerAcceptor(result);
    }

    private void logCheckStatus(final Resource resource, boolean parserDiagFail, String string) {
        if (log.isDebugEnabled()) {
            log.debug(string + " check " + (parserDiagFail ? "FAIL" : "OK") + "! Resource: " + resource.getURI());
        }
    }

    protected void issueFromXtextResourceDiagnostic(org.eclipse.emf.ecore.resource.Resource.Diagnostic diagnostic,
            Severity severity, IAcceptor<Issue> acceptor) {
        converter.convertResourceDiagnostic(diagnostic, severity, acceptor);
    }

    protected void issueFromEValidatorDiagnostic(Diagnostic diagnostic, IAcceptor<Issue> acceptor) {
        converter.convertValidatorDiagnostic(diagnostic, acceptor);
    }

    public void setDiagnostician(Diagnostician diagnostician) {
        this.diagnostician = diagnostician;
    }

    public Diagnostician getDiagnostician() {
        return diagnostician;
    }

    public void setDiagnosticConverter(IDiagnosticConverter converter) {
        this.converter = converter;
    }

    public IDiagnosticConverter getDiagnosticConverter() {
        return converter;
    }

    /**
     * @since 2.9
     */
    protected OperationCanceledManager getOperationCanceledManager() {
        return operationCanceledManager;
    }

}