org.eclipse.jst.jsp.ui.internal.hyperlink.XMLJavaHyperlinkDetector.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jst.jsp.ui.internal.hyperlink.XMLJavaHyperlinkDetector.java

Source

/*******************************************************************************
 * Copyright (c) 2008, 2013 IBM Corporation 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jst.jsp.ui.internal.hyperlink;

import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.ITextFileBuffer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.ui.JavaElementLabels;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.hyperlink.AbstractHyperlinkDetector;
import org.eclipse.jface.text.hyperlink.IHyperlink;
import org.eclipse.jst.jsp.core.internal.Logger;
import org.eclipse.jst.jsp.core.internal.java.IJSPTranslation;
import org.eclipse.jst.jsp.core.internal.java.JSPTranslation;
import org.eclipse.jst.jsp.core.internal.java.JSPTranslationAdapter;
import org.eclipse.jst.jsp.ui.internal.JSPUIMessages;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ui.PartInitException;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.core.utils.StringUtils;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;

/**
 * Detects hyper-links to type names
 */
public class XMLJavaHyperlinkDetector extends AbstractHyperlinkDetector {

    private static final String JAR_FILE_PROTOCOL = "jar:file:"; //$NON-NLS-1$

    /**
     * Based on org.eclipse.jdt.internal.ui.javaeditor.JavaElementHyperlink
     */
    static class JavaElementHyperlink implements IHyperlink {

        private final IJavaElement fElement;
        private final IRegion fRegion;

        /**
         * Creates a new Java element hyperlink.
         * 
         * @param region
         *            the region of the link
         * @param element
         *            the java element to open
         * @param qualify
         *            <code>true</code> if the hyper-link text should show a
         *            qualified name for element.
         */
        JavaElementHyperlink(IRegion region, IJavaElement element) {
            fRegion = region;
            fElement = element;
        }

        public IRegion getHyperlinkRegion() {
            return fRegion;
        }

        public String getHyperlinkText() {
            String elementLabel = JavaElementLabels.getElementLabel(fElement, JavaElementLabels.ALL_POST_QUALIFIED);
            return NLS.bind(JSPUIMessages.Open, elementLabel);
        }

        public String getTypeLabel() {
            return null;
        }

        public void open() {
            try {
                JavaUI.openInEditor(fElement);
            } catch (PartInitException e) {
            } catch (JavaModelException e) {
            }
        }
    }

    private IHyperlink createHyperlink(String elementName, IRegion region, IDocument document) {
        // try file buffers
        ITextFileBuffer textFileBuffer = FileBuffers.getTextFileBufferManager().getTextFileBuffer(document);
        if (textFileBuffer != null) {
            IPath basePath = textFileBuffer.getLocation();
            if (basePath != null && !basePath.isEmpty()) {
                IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(basePath.segment(0));
                try {
                    if (basePath.segmentCount() > 1 && project.isAccessible()
                            && project.hasNature(JavaCore.NATURE_ID)) {
                        return createJavaElementHyperlink(JavaCore.create(project), elementName, region);
                    }
                } catch (CoreException e) {
                    Logger.logException(e);
                }
            }
        }

        // fallback to SSE-specific knowledge
        IStructuredModel model = null;
        try {
            model = StructuredModelManager.getModelManager().getExistingModelForRead(document);
            if (model != null) {
                String baseLocation = model.getBaseLocation();
                // URL fixup from the taglib index record
                if (baseLocation.startsWith("jar:/file:")) { //$NON-NLS-1$
                    baseLocation = StringUtils.replace(baseLocation, "jar:/", "jar:"); //$NON-NLS-1$ //$NON-NLS-2$
                }
                /*
                 * Handle opened TLD files from JARs on the Java Build Path by
                 * finding a package fragment root for the same .jar file and
                 * opening the class from there. Note that this might be from
                 * a different Java project's build path than the TLD.
                 */
                if (baseLocation.startsWith(JAR_FILE_PROTOCOL)
                        && baseLocation.indexOf('!') > JAR_FILE_PROTOCOL.length()) {
                    String baseFile = baseLocation.substring(JAR_FILE_PROTOCOL.length(), baseLocation.indexOf('!'));
                    IPath basePath = new Path(baseFile);
                    IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
                    for (int i = 0; i < projects.length; i++) {
                        try {
                            if (projects[i].isAccessible() && projects[i].hasNature(JavaCore.NATURE_ID)) {
                                IJavaProject javaProject = JavaCore.create(projects[i]);
                                if (javaProject.exists()) {
                                    IPackageFragmentRoot root = javaProject.findPackageFragmentRoot(basePath);
                                    if (root != null) {
                                        return createJavaElementHyperlink(javaProject, elementName, region);
                                    }
                                }
                            }
                        } catch (CoreException e) {
                            Logger.logException(e);
                        }
                    }
                } else {
                    IPath basePath = new Path(baseLocation);
                    if (basePath.segmentCount() > 1) {
                        return createJavaElementHyperlink(
                                JavaCore.create(
                                        ResourcesPlugin.getWorkspace().getRoot().getProject(basePath.segment(0))),
                                elementName, region);
                    }
                }
            }
        } finally {
            if (model != null)
                model.releaseFromRead();
        }
        return null;
    }

    private boolean isJspJavaContent(IDocument document, IRegion region) {
        JSPTranslation translation = null;
        IStructuredModel model = null;
        try {
            model = StructuredModelManager.getModelManager().getExistingModelForRead(document);
            if (model instanceof IDOMModel) {
                IDOMModel xmlModel = (IDOMModel) model;
                if (xmlModel != null) {
                    final IDOMDocument xmlDoc = xmlModel.getDocument();
                    final JSPTranslationAdapter adapter = (JSPTranslationAdapter) xmlDoc
                            .getAdapterFor(IJSPTranslation.class);
                    if (adapter != null) {
                        translation = adapter.getJSPTranslation();
                        if (translation != null) {
                            int javaOffset = translation.getJavaOffset(region.getOffset());
                            if (javaOffset > -1) {
                                return true;
                            }
                        }
                    }
                }
            }
        } finally {
            if (model != null) {
                model.releaseFromRead();
            }
        }

        return false;
    }

    private IHyperlink createJavaElementHyperlink(IJavaProject javaProject, String elementName, IRegion region) {
        if (javaProject != null && javaProject.exists()) {
            try {
                IJavaElement element = javaProject.findType(elementName);
                if (element != null && element.exists()) {
                    return new JavaElementHyperlink(region, element);
                }
            } catch (JavaModelException e) {
                // bad name, no link
            }
        }
        return null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.eclipse.jface.text.hyperlink.IHyperlinkDetector#detectHyperlinks
     * (org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion,
     * boolean)
     */
    public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region,
            boolean canShowMultipleHyperlinks) {
        if (region != null && textViewer != null) {
            IDocument document = textViewer.getDocument();
            // find hyperlink range for Java element
            IRegion hyperlinkRegion = region.getLength() > 0 ? region
                    : selectQualifiedName(document, region.getOffset());
            if (isJspJavaContent(document, hyperlinkRegion)) { // Handled by JSPJavaHyperlinkDetector
                return null;
            }
            String name = null;
            try {
                name = document.get(hyperlinkRegion.getOffset(), hyperlinkRegion.getLength()).trim();
            } catch (BadLocationException e) {
            }
            if (name != null) {
                IHyperlink link = createHyperlink(name, hyperlinkRegion, document);
                if (link != null)
                    return new IHyperlink[] { link };
            }
        }

        return null;
    }

    /**
     * Java always selects word when defining region
     * 
     * @param document
     * @param anchor
     * @return IRegion
     */
    private IRegion selectQualifiedName(IDocument document, int anchor) {

        try {
            int offset = anchor;
            char c;

            while (offset >= 0) {
                c = document.getChar(offset);
                if (!Character.isJavaIdentifierPart(c) && c != '.')
                    break;
                --offset;
            }

            int start = offset;

            offset = anchor;
            int length = document.getLength();

            while (offset < length) {
                c = document.getChar(offset);
                if (!Character.isJavaIdentifierPart(c) && c != '.')
                    break;
                ++offset;
            }

            int end = offset;

            if (start == end)
                return new Region(start, 0);

            return new Region(start + 1, end - start - 1);

        } catch (BadLocationException x) {
            return null;
        }
    }
}