org.jboss.tools.ws.jaxrs.ui.navigation.JaxrsNameBindingHyperlinkDetector.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.tools.ws.jaxrs.ui.navigation.JaxrsNameBindingHyperlinkDetector.java

Source

/******************************************************************************* 
 * Copyright (c) 2014 - 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.navigation;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.ICodeAssist;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
import org.eclipse.jdt.internal.ui.text.JavaWordFinder;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.hyperlink.AbstractHyperlinkDetector;
import org.eclipse.jface.text.hyperlink.IHyperlink;
import org.eclipse.ui.texteditor.ITextEditor;
import org.jboss.tools.ws.jaxrs.core.internal.metamodel.domain.JaxrsMetamodel;
import org.jboss.tools.ws.jaxrs.core.internal.metamodel.domain.JaxrsNameBinding;
import org.jboss.tools.ws.jaxrs.core.metamodel.domain.EnumElementKind;
import org.jboss.tools.ws.jaxrs.core.metamodel.domain.IJaxrsElement;
import org.jboss.tools.ws.jaxrs.core.metamodel.domain.IJaxrsJavaElement;
import org.jboss.tools.ws.jaxrs.core.metamodel.domain.JaxrsMetamodelLocator;
import org.jboss.tools.ws.jaxrs.ui.internal.utils.Logger;

/**
 * @author xcoulon
 *
 */
@SuppressWarnings("restriction")
public class JaxrsNameBindingHyperlinkDetector extends AbstractHyperlinkDetector {
    /**
     * Default Constructor
     */
    public JaxrsNameBindingHyperlinkDetector() {
    }

    /**
     * (non-Javadoc)
     * 
     * @see org.eclipse.jface.text.hyperlink.IHyperlinkDetector#detectHyperlinks(org.eclipse.jface.text.ITextViewer,
     *      org.eclipse.jface.text.IRegion, boolean)
     */
    @Override
    public IHyperlink[] detectHyperlinks(final ITextViewer textViewer, final IRegion region,
            final boolean canShowMultipleHyperlinks) {
        final ITextEditor textEditor = (ITextEditor) getAdapter(ITextEditor.class);
        if (region == null || !(textEditor instanceof JavaEditor)) {
            return null;
        }
        final int offset = region.getOffset();
        final IJavaElement input = EditorUtility.getActiveEditorJavaInput();
        if (input == null) {
            return null;
        }
        final JaxrsMetamodel metamodel = getMetamodel(input);
        if (metamodel == null) {
            return null;
        }
        final IRegion wordRegion = getCurrentWordRegion(textEditor, offset);
        if (wordRegion == null || wordRegion.getLength() == 0) {
            return null;
        }
        final IJavaElement[] selectedJavaElements = getSelectedElements(input, wordRegion);

        final List<IJaxrsJavaElement> targets = findTargets(metamodel, selectedJavaElements,
                (ICompilationUnit) input.getAncestor(IJavaElement.COMPILATION_UNIT));
        if (targets != null && !targets.isEmpty()) {
            final IHyperlink[] result = new IHyperlink[targets.size()];
            for (int i = 0; i < targets.size(); i++) {
                result[i] = new JaxrsNameBindingAnnotationHyperlink(targets.get(i), wordRegion);
            }
            return result;
        }
        return null;

    }

    /**
     * 
     * @param input
     *            the current {@link IJavaElement}
     * @param wordRegion
     *            the selected {@link IRegion} in the {@link ITextEditor}
     * @return an array of {@link IJavaElement} matching the selection or an
     *         empty array if none was found or if an error occurred.
     */
    private IJavaElement[] getSelectedElements(final IJavaElement input, final IRegion wordRegion) {
        try {
            return ((ICodeAssist) input).codeSelect(wordRegion.getOffset(), wordRegion.getLength());
        } catch (JavaModelException e) {
            // element does not exist or wordRegion was out of range.
            // We should silently ignore such a case, in which case, no navigation hyperlink shall be provided.
            Logger.debug("Failed to retrieve the selected Java Elements in the editor for" + input.getElementName(),
                    e);
            return new IJavaElement[0];
        }
    }

    /**
     * If the given selectedJavaElement match a custom Name Binding annotation
     * defined in the given {@link JaxrsMetamodel}, then return the list of
     * associated elements with this name binding.
     * 
     * @param metamodel
     *            the JAX-RS Metamodel associated with the given element in the
     *            current text editor
     * @param selectedJavaElements
     *            the selected java elements
     * @param currentCompilationUnit
     *            the {@link ICompilationUnit} opened in the current text editor
     * @return the list of target {@link IJavaElement} or empty list if none
     *         match.
     */
    private List<IJaxrsJavaElement> findTargets(final JaxrsMetamodel metamodel,
            final IJavaElement[] selectedJavaElements, final ICompilationUnit currentCompilationUnit) {
        final List<IJaxrsJavaElement> targetElements = new ArrayList<IJaxrsJavaElement>();
        for (IJavaElement selectedJavaElement : selectedJavaElements) {
            final IJaxrsElement associatedJaxrsElement = metamodel.findElement(selectedJavaElement);
            if (associatedJaxrsElement != null
                    && associatedJaxrsElement.getElementKind() == EnumElementKind.NAME_BINDING) {
                final JaxrsNameBinding nameBinding = (JaxrsNameBinding) associatedJaxrsElement;
                final Collection<IJaxrsElement> matchingElements = metamodel
                        .findElementsByAnnotation(nameBinding.getJavaClassName());
                for (IJaxrsElement matchingElement : matchingElements) {
                    final IJavaElement matchingJavaElement = ((IJaxrsJavaElement) matchingElement).getJavaElement();
                    // skip if the matching/target Java element is part of the current compilation unit
                    if (!matchingJavaElement.getAncestor(IJavaElement.COMPILATION_UNIT)
                            .equals(currentCompilationUnit)) {
                        targetElements.add((IJaxrsJavaElement) matchingElement);
                    }
                }
            }
        }
        return targetElements;
    }

    /**
     * @return the selected {@link IRegion}
     * @param textEditor the current {@link ITextEditor}
     * @param offset the position in the text editor
     */
    private IRegion getCurrentWordRegion(final ITextEditor textEditor, final int offset) {
        final IDocument document = textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput());
        final IRegion wordRegion = JavaWordFinder.findWord(document, offset);
        return wordRegion;
    }

    /**
     * @param input the current {@link IJavaElement}
     * @return the {@link JaxrsMetamodel} associated with the given element or {@code null} if none exists (or if an exception was thrown).
     */
    private JaxrsMetamodel getMetamodel(final IJavaElement input) {
        try {
            return JaxrsMetamodelLocator.get(input.getJavaProject());
        } catch (CoreException e) {
            Logger.error("Failed to retrieve JAX-RS Metamodel for " + input.getElementName(), e);
            return null;
        }
    }

}