org.jboss.tools.ws.jaxrs.ui.internal.validation.ValidationUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.tools.ws.jaxrs.ui.internal.validation.ValidationUtils.java

Source

/******************************************************************************* 
 * Copyright (c) 2013 - 2014 Red Hat, Inc. and others. 
 * Distributed under license by Red Hat, Inc. All rights reserved. 
 * This program is 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: 
 * Xavier Coulon - Initial API and implementation 
 ******************************************************************************/
package org.jboss.tools.ws.jaxrs.ui.internal.validation;

import static org.jboss.tools.ws.jaxrs.core.validation.IJaxrsValidation.JAXRS_PROBLEM_MARKER_ID;
import static org.junit.Assert.fail;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.IAnnotation;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.internal.ui.text.correction.ProblemLocation;
import org.eclipse.jdt.ui.text.java.IInvocationContext;
import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
import org.eclipse.jdt.ui.text.java.IProblemLocation;
import org.eclipse.jface.text.IDocument;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.texteditor.DocumentProviderRegistry;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.wst.validation.internal.provisional.core.IMessage;
import org.eclipse.wst.validation.internal.provisional.core.IReporter;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.jboss.tools.common.validation.ValidationErrorManager;
import org.jboss.tools.ws.jaxrs.core.internal.metamodel.domain.JaxrsBaseElement;
import org.jboss.tools.ws.jaxrs.core.internal.metamodel.domain.JaxrsJavaElement;
import org.jboss.tools.ws.jaxrs.core.internal.metamodel.domain.JaxrsMetamodel;
import org.jboss.tools.ws.jaxrs.core.internal.metamodel.domain.JaxrsParameterAggregator;
import org.jboss.tools.ws.jaxrs.core.internal.metamodel.domain.JaxrsResource;
import org.jboss.tools.ws.jaxrs.core.jdt.Annotation;
import org.jboss.tools.ws.jaxrs.core.jdt.JdtUtils;
import org.jboss.tools.ws.jaxrs.core.jdt.RangeUtils;
import org.jboss.tools.ws.jaxrs.core.metamodel.domain.IJaxrsElement;
import org.jboss.tools.ws.jaxrs.core.metamodel.domain.IJaxrsEndpoint;
import org.jboss.tools.ws.jaxrs.core.metamodel.domain.IJaxrsMetamodel;
import org.jboss.tools.ws.jaxrs.core.metamodel.domain.IJaxrsParameterAggregatorField;
import org.jboss.tools.ws.jaxrs.core.metamodel.domain.IJaxrsParameterAggregatorProperty;
import org.jboss.tools.ws.jaxrs.core.metamodel.domain.IJaxrsResourceField;
import org.jboss.tools.ws.jaxrs.core.metamodel.domain.IJaxrsResourceMethod;
import org.jboss.tools.ws.jaxrs.core.metamodel.domain.IJaxrsResourceProperty;
import org.jboss.tools.ws.jaxrs.ui.internal.utils.TestLogger;
import org.jboss.tools.ws.jaxrs.ui.quickfix.JaxrsMarkerResolutionGenerator;
import org.junit.Assert;

/**
 * @author Xavier Coulon The class name says it all.
 */
@SuppressWarnings("restriction")
public class ValidationUtils {

    /**
     * Converts the given {@link IResource} elements into a set of {@link IFile}
     * s
     * 
     * @param elements
     * @return the set containing the given elements
     */
    public static Set<IFile> toSet(final IResource... elements) {
        final Set<IFile> result = new HashSet<IFile>();
        for (IResource element : elements) {
            if (element == null) {
                continue;
            }
            result.add((IFile) element);
        }
        return result;
    }

    /**
     * find JAX-RS Markers on the given resources.
     * 
     * @param element
     * @return
     * @throws CoreException
     */
    public static IMarker[] findJaxrsMarkers(final IJaxrsElement... elements) throws CoreException {
        final List<IMarker> markers = new ArrayList<IMarker>();
        for (IJaxrsElement element : elements) {
            if (element.getResource() == null) {
                continue;
            }
            final IMarker[] elementMarkers = element.getResource().findMarkers(JAXRS_PROBLEM_MARKER_ID, true,
                    IResource.DEPTH_INFINITE);
            switch (element.getElementKind().getCategory()) {
            case APPLICATION:
            case HTTP_METHOD:
            case NAME_BINDING:
            case PROVIDER:
            case PARAM_CONVERTER_PROVIDER:
            case PARAMETER_AGGREGATOR:
            case RESOURCE:
                for (IMarker marker : elementMarkers) {
                    markers.add(marker);
                }
                break;
            case RESOURCE_METHOD:
            case RESOURCE_FIELD:
            case RESOURCE_PROPERTY:
            case PARAMETER_AGGREGATOR_FIELD:
            case PARAMETER_AGGREGATOR_PROPERTY:
                final ISourceRange methodSourceRange = ((JaxrsJavaElement<?>) element).getJavaElement()
                        .getSourceRange();
                for (IMarker marker : elementMarkers) {
                    final int markerCharStart = marker.getAttribute(IMarker.CHAR_START, -1);
                    if (markerCharStart >= methodSourceRange.getOffset()
                            && markerCharStart <= (methodSourceRange.getOffset() + methodSourceRange.getLength())) {
                        markers.add(marker);
                    }
                }
                break;
            default:
                break;
            }
        }
        printMarkers(markers);
        return markers.toArray(new IMarker[markers.size()]);
    }

    public static IMessage[] findJaxrsMessages(final IReporter reporter, final IJaxrsElement... elements) {
        @SuppressWarnings("unchecked")
        final List<IMessage> messages = reporter.getMessages();

        return messages.toArray(new IMessage[messages.size()]);
    }

    /**
     * Finds JAX-RS Markers <strong>at the project level only</strong>, not on
     * the children resources of this project !
     * 
     * @param project
     * @return
     * @throws CoreException
     */
    public static IMarker[] findJaxrsMarkers(IProject project) throws CoreException {
        return project.findMarkers(JAXRS_PROBLEM_MARKER_ID, false, 0);
    }

    /**
     * @param element
     * @throws CoreException
     */
    public static void deleteJaxrsMarkers(final JaxrsBaseElement element) throws CoreException {
        if (element.getResource() == null) {
            return;
        }
        element.getResource().deleteMarkers(JAXRS_PROBLEM_MARKER_ID, false, IResource.DEPTH_INFINITE);
    }

    /**
     * @param element
     * @throws CoreException
     */
    public static void deleteJaxrsMarkers(final IResource resource) throws CoreException {
        resource.deleteMarkers(JAXRS_PROBLEM_MARKER_ID, false, IResource.DEPTH_INFINITE);
    }

    /**
     * Reset JAX-RS Markers on the given {@link IJaxrsMetamodel} and all its
     * children elements.
     * 
     * @param metamodel
     *            the metamodel to clean
     * @throws CoreException
     */
    public static void deleteJaxrsMarkers(final JaxrsMetamodel metamodel) throws CoreException {
        metamodel.getProject().deleteMarkers(JAXRS_PROBLEM_MARKER_ID, false, IResource.DEPTH_INFINITE);
        metamodel.resetProblemLevel();
        final List<IJaxrsElement> allElements = metamodel.getAllElements();
        for (IJaxrsElement element : allElements) {
            ((JaxrsBaseElement) element).resetProblemLevel();
        }
    }

    public static Matcher<IMarker[]> havePreferenceKey(final String expectedProblemType) {
        return new BaseMatcher<IMarker[]>() {
            @Override
            public boolean matches(Object item) {
                if (item instanceof IMarker[]) {
                    for (IMarker marker : (IMarker[]) item) {
                        final String preferenceKey = marker
                                .getAttribute(ValidationErrorManager.PREFERENCE_KEY_ATTRIBUTE_NAME, "");
                        if (preferenceKey.equals(expectedProblemType)) {
                            return true;
                        }
                    }
                }
                return false;
            }

            @Override
            public void describeTo(Description description) {
                description.appendText(
                        "marker contains preference_key (\"" + expectedProblemType + "\" problem type)");
            }
        };
    }

    public static Matcher<IMarker> hasPreferenceKey(final String expectedProblemType) {
        return new BaseMatcher<IMarker>() {
            @Override
            public boolean matches(Object item) {
                if (item instanceof IMarker) {
                    final IMarker marker = (IMarker) item;
                    final String preferenceKey = marker
                            .getAttribute(ValidationErrorManager.PREFERENCE_KEY_ATTRIBUTE_NAME, "");
                    if (preferenceKey.equals(expectedProblemType)) {
                        return true;
                    }
                }
                return false;
            }

            @Override
            public void describeTo(Description description) {
                description.appendText(
                        "marker contains preference_key (\"" + expectedProblemType + "\" problem type)");
            }
        };
    }

    public static Matcher<IMarker> matchesLocation(final ISourceRange range) {
        return new BaseMatcher<IMarker>() {

            @Override
            public boolean matches(Object item) {
                if (item instanceof IMarker) {
                    final IMarker marker = (IMarker) item;
                    final int markerStart = marker.getAttribute(IMarker.CHAR_START, 0);
                    final int markerEnd = marker.getAttribute(IMarker.CHAR_END, 0);
                    return (markerStart == range.getOffset()
                            && markerEnd == (range.getOffset() + range.getLength()));
                }
                return false;
            }

            @Override
            public void describeTo(Description description) {
                description.appendText("marker location:" + range);
            }

        };
    }

    public static void printMarkers(final List<IMarker> markers) {
        TestLogger.debug("Found {} markers", markers.size());
        for (IMarker marker : markers) {
            TestLogger.debug(" Marker with severity={}: {}", marker.getAttribute(IMarker.SEVERITY, 0),
                    marker.getAttribute(IMarker.MESSAGE, ""));
        }
    }

    /**
     * @param annotation
     * @return
     * @throws JavaModelException
     * @throws CoreException
     */
    public static IJavaCompletionProposal[] getJavaCompletionProposals(final Annotation annotation)
            throws JavaModelException, CoreException {
        final IAnnotation javaAnnotation = annotation.getJavaAnnotation();
        final ICompilationUnit compilationUnit = (ICompilationUnit) javaAnnotation
                .getAncestor(IJavaElement.COMPILATION_UNIT);
        final ISourceRange sourceRange = javaAnnotation.getSourceRange();
        final IInvocationContext invocationContext = getInvocationContext(compilationUnit, sourceRange.getOffset(),
                sourceRange.getLength());
        final IProblemLocation[] problemLocations = getProblemLocations(javaAnnotation);
        final IJavaCompletionProposal[] proposals = new JaxrsMarkerResolutionGenerator()
                .getCorrections(invocationContext, problemLocations);
        return proposals;
    }

    private static IInvocationContext getInvocationContext(final ICompilationUnit compilationUnit, final int offset,
            final int length) {
        return new IInvocationContext() {

            @Override
            public int getSelectionOffset() {
                return offset;
            }

            @Override
            public int getSelectionLength() {
                return length;
            }

            @Override
            public ASTNode getCoveringNode() {
                return null;
            }

            @Override
            public ASTNode getCoveredNode() {
                return null;
            }

            @Override
            public ICompilationUnit getCompilationUnit() {
                return compilationUnit;
            }

            @Override
            public CompilationUnit getASTRoot() {
                try {
                    return JdtUtils.parse(compilationUnit, null);
                } catch (JavaModelException e) {
                    Assert.fail("Failed to parse the compilationUnit");
                }
                return null;
            }
        };
    }

    private static IProblemLocation[] getProblemLocations(final IAnnotation annotation) throws JavaModelException {
        final CompilationUnit ast = JdtUtils.parse(annotation.getAncestor(IJavaElement.COMPILATION_UNIT), null);
        final IProblem[] problems = ast.getProblems();
        for (IProblem problem : problems) {
            if ((problem.getSourceStart() >= annotation.getSourceRange().getOffset())
                    && (problem.getSourceStart() <= (annotation.getSourceRange().getLength()
                            + annotation.getSourceRange().getOffset()))) {
                return new IProblemLocation[] { new ProblemLocation(problem) };
            }
        }
        return null;
    }

    public static void applyProposals(final IJaxrsElement jaxrsElement, final IJavaCompletionProposal[] proposals)
            throws CoreException {
        final FileEditorInput input = new FileEditorInput((IFile) jaxrsElement.getResource());
        final IDocumentProvider provider = DocumentProviderRegistry.getDefault().getDocumentProvider(input);
        try {
            provider.connect(input);
        } catch (CoreException e) {
            fail("Failed to connect provider to input:" + e.getMessage());
        }
        final IDocument document = provider.getDocument(input);
        for (IJavaCompletionProposal proposal : proposals) {
            proposal.apply(document);
        }
        provider.saveDocument(new NullProgressMonitor(), input, document, true);
    }

    public static IProblem[] findJavaProblems(final IResource resource) throws JavaModelException {
        final CompilationUnit ast = JdtUtils.parse(JavaCore.create(resource), null);
        final IProblem[] problems = ast.getProblems();
        // only care about errors
        final List<IProblem> errors = new ArrayList<IProblem>();
        for (IProblem problem : problems) {
            if (problem.isError()) {
                errors.add(problem);
            }
        }
        return errors.toArray(new IProblem[errors.size()]);
    }

    /**
     * @param markers
     * @param metamodel
     * @return a set of {@link IJaxrsEndpoint} whose underlying {@link IJaxrsElement} have one of the given {@link IMarker}s
     * @throws JavaModelException 
     */
    public static List<IJaxrsEndpoint> findEndpointsByMarkers(final IMarker[] markers,
            final JaxrsMetamodel metamodel) throws JavaModelException {
        final Set<IJaxrsEndpoint> endpoints = new HashSet<IJaxrsEndpoint>();
        for (IMarker marker : markers) {
            final Set<IJaxrsElement> elements = metamodel.findElements(marker.getResource());
            for (IJaxrsElement element : elements) {
                switch (element.getElementKind().getCategory()) {
                case RESOURCE:
                    final JaxrsResource resource = (JaxrsResource) element;
                    for (IJaxrsResourceField resourceField : resource.getAllFields()) {
                        if (matchesLocation(marker, resourceField)) {
                            endpoints.addAll(metamodel.findEndpoints(resourceField));
                        }
                    }
                    for (IJaxrsResourceProperty resourceProperty : resource.getAllProperties()) {
                        if (matchesLocation(marker, resourceProperty)) {
                            endpoints.addAll(metamodel.findEndpoints(resourceProperty));
                        }
                    }
                    for (IJaxrsResourceMethod resourceMethod : resource.getAllMethods()) {
                        if (matchesLocation(marker, resourceMethod)) {
                            endpoints.addAll(metamodel.findEndpoints(resourceMethod));
                        }
                    }
                    break;
                case PARAMETER_AGGREGATOR:
                    final JaxrsParameterAggregator parameterAggregator = (JaxrsParameterAggregator) element;
                    for (IJaxrsParameterAggregatorField parameterAggregatorField : parameterAggregator
                            .getAllFields()) {
                        if (matchesLocation(marker, parameterAggregatorField)) {
                            endpoints.addAll(metamodel.findEndpoints(parameterAggregatorField));
                        }
                    }
                    for (IJaxrsParameterAggregatorProperty parameterAggregatorProperty : parameterAggregator
                            .getAllProperties()) {
                        if (matchesLocation(marker, parameterAggregatorProperty)) {
                            endpoints.addAll(metamodel.findEndpoints(parameterAggregatorProperty));
                        }
                    }
                    continue;
                default:
                    if (matchesLocation(marker, element)) {
                        endpoints.addAll(metamodel.findEndpoints(element));
                    }
                }
            }
        }

        return new ArrayList<IJaxrsEndpoint>(endpoints);
    }

    /**
     * @return {@code true} if the given {@link IMarker} is located in the underlying {@link IJavaElement} of the given {@link IJaxrsElement}, {@code false} otherwise.
     * 
     * @param marker
     * @param element
     * @throws JavaModelException
     */
    private static boolean matchesLocation(IMarker marker, IJaxrsElement element) throws JavaModelException {
        if (element instanceof JaxrsJavaElement<?>) {
            final ISourceRange sourceRange = ((JaxrsJavaElement<?>) element).getJavaElement().getSourceRange();
            final int markerStartPosition = marker.getAttribute(IMarker.CHAR_START, 0);
            if (RangeUtils.matches(sourceRange, markerStartPosition)) {
                return true;
            }
        }
        return false;
    }
}