org.eclipse.mylyn.internal.pde.ui.XmlJavaRelationProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.mylyn.internal.pde.ui.XmlJavaRelationProvider.java

Source

/*******************************************************************************
 * Copyright (c) 2004, 2008 Tasktop Technologies 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:
 *     Tasktop Technologies - initial API and implementation
 *******************************************************************************/

package org.eclipse.mylyn.internal.pde.ui;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.internal.resources.File;
import org.eclipse.core.internal.resources.Workspace;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.mylyn.commons.core.StatusHandler;
import org.eclipse.mylyn.context.core.AbstractContextStructureBridge;
import org.eclipse.mylyn.context.core.ContextCore;
import org.eclipse.mylyn.context.core.IInteractionElement;
import org.eclipse.mylyn.internal.context.core.AbstractRelationProvider;
import org.eclipse.mylyn.internal.context.core.ContextCorePlugin;
import org.eclipse.mylyn.internal.context.core.DegreeOfSeparation;
import org.eclipse.mylyn.internal.context.core.IActiveSearchListener;
import org.eclipse.mylyn.internal.context.core.IActiveSearchOperation;
import org.eclipse.mylyn.internal.context.core.IDegreeOfSeparation;
import org.eclipse.mylyn.internal.ide.ui.XmlNodeHelper;
import org.eclipse.mylyn.internal.java.ui.search.XmlActiveSearchUpdater;
import org.eclipse.mylyn.internal.resources.ui.ResourcesUiBridgePlugin;
import org.eclipse.search.core.text.TextSearchScope;
import org.eclipse.search.internal.ui.text.FileSearchQuery;
import org.eclipse.search.internal.ui.text.FileSearchResult;
import org.eclipse.search.ui.ISearchResult;
import org.eclipse.search.ui.text.FileTextSearchScope;
import org.eclipse.search.ui.text.Match;

/**
 * @author Shawn Minto
 * @author Mik Kersten
 */
@SuppressWarnings("restriction")
public class XmlJavaRelationProvider extends AbstractRelationProvider {

    public static final String SOURCE_ID = "org.eclipse.mylyn.xml.search.references"; //$NON-NLS-1$

    public static final String NAME = "referenced by"; //$NON-NLS-1$

    public static final int DEFAULT_DEGREE = 3;

    public static final List<Job> runningJobs = new ArrayList<Job>();

    public static final Map<Match, XmlNodeHelper> nodeMap = new HashMap<Match, XmlNodeHelper>();

    public XmlJavaRelationProvider() {
        // TODO: should this be a generic XML extension?
        super(PdeStructureBridge.CONTENT_TYPE, SOURCE_ID);
    }

    @Override
    public List<IDegreeOfSeparation> getDegreesOfSeparation() {
        List<IDegreeOfSeparation> separations = new ArrayList<IDegreeOfSeparation>();
        separations.add(new DegreeOfSeparation(DOS_0_LABEL, 0));
        separations.add(new DegreeOfSeparation(DOS_1_LABEL, 1));
        separations.add(new DegreeOfSeparation(DOS_2_LABEL, 2));
        separations.add(new DegreeOfSeparation(DOS_3_LABEL, 3));
        separations.add(new DegreeOfSeparation(DOS_4_LABEL, 4));
        separations.add(new DegreeOfSeparation(DOS_5_LABEL, 5));
        return separations;
    }

    @Override
    protected void findRelated(final IInteractionElement node, int degreeOfSeparation) {
        if (!node.getContentType().equals("java")) { //$NON-NLS-1$
            return;
        }
        IJavaElement javaElement = JavaCore.create(node.getHandleIdentifier());
        if (javaElement == null || javaElement instanceof ICompilationUnit || !javaElement.exists()) {
            return;
        }
        if (!acceptElement(javaElement)) {
            return;
        }

        TextSearchScope scope = createTextSearchScope(degreeOfSeparation);
        if (scope != null) {
            runJob(node, javaElement, degreeOfSeparation, getId());
        }
    }

    protected TextSearchScope createTextSearchScope(int degreeOfSeparation) {
        Set<IInteractionElement> landmarks = ContextCore.getContextManager().getActiveLandmarks();

        switch (degreeOfSeparation) {
        case 1:
            // create a search scope for the projects of landmarks
            Set<IResource> l = new HashSet<IResource>();
            for (IInteractionElement landmark : landmarks) {
                if (landmark.getContentType().equals(PdeStructureBridge.CONTENT_TYPE)) {
                    // ||
                    // landmark.getContentType().equals(AntStructureBridge.CONTENT_TYPE))
                    // {
                    String handle = landmark.getHandleIdentifier();
                    IResource element = null;
                    int first = handle.indexOf(";"); //$NON-NLS-1$
                    String filename = handle;
                    if (first != -1) {
                        filename = handle.substring(0, first);
                    }
                    try {
                        // change the file into a document
                        IPath path = new Path(filename);
                        element = ((Workspace) ResourcesPlugin.getWorkspace()).newResource(path, IResource.FILE);
                    } catch (Exception e) {
                        StatusHandler.log(new Status(IStatus.WARNING, PdeUiBridgePlugin.ID_PLUGIN,
                                "Scope creation failed", e)); //$NON-NLS-1$
                    }
                    l.add(element);
                }
            }

            IResource[] res = new IResource[l.size()];
            res = l.toArray(res);
            TextSearchScope doiScope = FileTextSearchScope.newSearchScope(res,
                    new String[] { PdeStructureBridge.CONTENT_TYPE }, false);
            return l.isEmpty() ? null : doiScope;
        case 2:
            // create a search scope for the projects of landmarks
            Set<IProject> projectsToSearch = new HashSet<IProject>();
            for (IInteractionElement landmark : landmarks) {
                AbstractContextStructureBridge bridge = ContextCore.getStructureBridge(landmark.getContentType());
                IResource resource = ResourcesUiBridgePlugin.getDefault().getResourceForElement(landmark, true);
                IProject project = null;
                if (resource != null) {
                    project = resource.getProject();
                } else {
                    Object object = bridge.getObjectForHandle(landmark.getHandleIdentifier());
                    if (object instanceof IJavaElement) {
                        project = ((IJavaElement) object).getJavaProject().getProject();
                    }
                }
                if (project != null) {
                    projectsToSearch.add(project);
                }
            }

            res = new IProject[projectsToSearch.size()];
            res = projectsToSearch.toArray(res);
            TextSearchScope projScope = FileTextSearchScope.newSearchScope(res,
                    new String[] { PdeStructureBridge.CONTENT_TYPE }, false);

            return projectsToSearch.isEmpty() ? null : projScope;
        case 3:
            // create a search scope for the workspace
            return FileTextSearchScope.newSearchScope(new IResource[] { ResourcesPlugin.getWorkspace().getRoot() },
                    new String[] { PdeStructureBridge.CONTENT_TYPE }, false);
        case 4:
            // create a search scope for the workspace
            return FileTextSearchScope.newSearchScope(new IResource[] { ResourcesPlugin.getWorkspace().getRoot() },
                    new String[] { PdeStructureBridge.CONTENT_TYPE }, false);
        default:
            return null;
        }

    }

    protected boolean acceptElement(IJavaElement javaElement) {
        return javaElement != null && (javaElement instanceof IMember || javaElement instanceof IType);
    }

    private void runJob(final IInteractionElement node, final IJavaElement javaElement,
            final int degreeOfSeparation, final String kind) {

        // get the fully qualified name and if it is null, don't search
        String fullyQualifiedName = getFullyQualifiedName(javaElement);

        if (fullyQualifiedName == null) {
            return;
        }

        // Create the search query
        final XMLSearchOperation query = (XMLSearchOperation) getSearchOperation(node, 0, degreeOfSeparation);
        if (query != null) {
            XMLSearchJob job = new XMLSearchJob(query.getLabel(), query);
            query.addListener(new IActiveSearchListener() {

                private boolean gathered = false;

                public void searchCompleted(List<?> l) {
                    // deal with File
                    if (l.isEmpty()) {
                        return;
                    }

                    Map<String, String> nodes = new HashMap<String, String>();

                    if (l.get(0) instanceof FileSearchResult) {
                        FileSearchResult fsr = (FileSearchResult) l.get(0);

                        Object[] far = fsr.getElements();
                        for (Object element : far) {
                            Match[] mar = fsr.getMatches(element);

                            if (element instanceof File) {
                                File f = (File) element;

                                // change the file into a document
                                // FileEditorInput fei = new FileEditorInput(f);

                                for (Match m : mar) {
                                    try {
                                        AbstractContextStructureBridge bridge = ContextCorePlugin.getDefault()
                                                .getStructureBridge(f.getName());
                                        String handle = bridge.getHandleForOffsetInObject(f, m.getOffset());
                                        if (handle != null) {
                                            String second = handle.substring(handle.indexOf(";")); //$NON-NLS-1$

                                            XmlNodeHelper xnode = new XmlNodeHelper(f.getFullPath().toString(),
                                                    second);
                                            nodeMap.put(m, xnode);
                                            Object o = bridge.getObjectForHandle(handle);
                                            String name = bridge.getLabel(o);
                                            if (o != null) {
                                                nodes.put(handle, name);
                                            }
                                        }
                                    } catch (Exception e) {
                                        StatusHandler.log(new Status(IStatus.ERROR, PdeUiBridgePlugin.ID_PLUGIN,
                                                "Unable to create match", e)); //$NON-NLS-1$
                                    }
                                }
                            }
                        }
                    }

                    for (String handle : nodes.keySet()) {

                        incrementInterest(node, PdeStructureBridge.CONTENT_TYPE, handle, degreeOfSeparation);
                    }
                    gathered = true;
                    XmlJavaRelationProvider.this.searchCompleted(node);
                }

                public boolean resultsGathered() {
                    return gathered;
                }
            });
            runningJobs.add(job);
            job.setPriority(Job.DECORATE - 10);
            job.schedule();
        }
    }

    @Override
    public IActiveSearchOperation getSearchOperation(IInteractionElement node, int limitTo,
            int degreeOfSeparation) {
        IJavaElement javaElement = JavaCore.create(node.getHandleIdentifier());
        TextSearchScope scope = createTextSearchScope(degreeOfSeparation);
        if (scope == null) {
            return null;
        }

        String fullyQualifiedName = getFullyQualifiedName(javaElement);

        return new XMLSearchOperation(scope, fullyQualifiedName);
    }

    private String getFullyQualifiedName(IJavaElement je) {
        if (!(je instanceof IMember)) {
            return null;
        }

        IMember m = (IMember) je;
        if (m.getDeclaringType() == null) {
            return ((IType) m).getFullyQualifiedName();
        } else {
            return m.getDeclaringType().getFullyQualifiedName() + "." + m.getElementName(); //$NON-NLS-1$
        }
    }

    public static class XMLSearchJob extends Job {

        private final XMLSearchOperation op;

        /**
         * Constructor
         * 
         * @param name
         */
        public XMLSearchJob(String name, XMLSearchOperation op) {
            super(name);
            this.op = op;
        }

        @Override
        protected IStatus run(IProgressMonitor monitor) {
            return op.run(monitor);
        }

    }

    public static class XMLSearchOperation extends FileSearchQuery implements IActiveSearchOperation {

        @Override
        public ISearchResult getSearchResult() {
            try {
                // get the current page of the outline
                Class<?> clazz = FileSearchQuery.class;
                Field field = clazz.getDeclaredField("fResult"); //$NON-NLS-1$
                field.setAccessible(true);
                FileSearchResult fResult = (FileSearchResult) field.get(this);
                if (fResult == null) {
                    fResult = new FileSearchResult(this);
                    field.set(this, fResult);
                    new XmlActiveSearchUpdater(fResult);
                }
                return fResult;
            } catch (Exception e) {
                StatusHandler.log(new Status(IStatus.WARNING, PdeUiBridgePlugin.ID_PLUGIN,
                        "Failed to get search result: " + e.getMessage())); //$NON-NLS-1$
            }
            return super.getSearchResult();
        }

        @Override
        public IStatus run(IProgressMonitor monitor) {
            try {
                super.run(monitor);
                ISearchResult result = getSearchResult();
                if (result instanceof FileSearchResult) {
                    List<Object> l = new ArrayList<Object>();
                    if (((FileSearchResult) result).getElements().length != 0) {
                        l.add(result);
                    }

                    notifySearchCompleted(l);
                }
                return Status.OK_STATUS;
            } catch (Throwable t) {
                return new Status(IStatus.WARNING, ContextCorePlugin.ID_PLUGIN, 0,
                        Messages.XmlJavaRelationProvider_Skipped_XML_search, null);
            }
        }

        /**
         * Constructor
         * 
         * @param data
         */
        public XMLSearchOperation(TextSearchScope scope, String searchString) {
            super(searchString, false, true, (FileTextSearchScope) scope);
        }

        /** List of listeners wanting to know about the searches */
        private final List<IActiveSearchListener> listeners = new ArrayList<IActiveSearchListener>();

        /**
         * Add a listener for when the bugzilla search is completed
         * 
         * @param l
         *            The listener to add
         */
        public void addListener(IActiveSearchListener l) {
            // add the listener to the list
            listeners.add(l);
        }

        /**
         * Remove a listener for when the bugzilla search is completed
         * 
         * @param l
         *            The listener to remove
         */
        public void removeListener(IActiveSearchListener l) {
            // remove the listener from the list
            listeners.remove(l);
        }

        /**
         * Notify all of the listeners that the bugzilla search is completed
         * 
         * @param doiList
         *            A list of BugzillaSearchHitDoiInfo
         * @param member
         *            The IMember that the search was performed on
         */
        public void notifySearchCompleted(List<Object> l) {
            // go through all of the listeners and call
            // searchCompleted(colelctor,
            // member)
            for (IActiveSearchListener listener : listeners) {
                listener.searchCompleted(l);
            }
        }

    }

    @Override
    public String getGenericId() {
        return SOURCE_ID;
    }

    @Override
    protected String getSourceId() {
        return SOURCE_ID;
    }

    @Override
    public String getName() {
        return NAME;
    }

    @Override
    public void stopAllRunningJobs() {
        for (Job j : runningJobs) {
            j.cancel();
        }
        runningJobs.clear();
    }

    @Override
    protected int getDefaultDegreeOfSeparation() {
        return DEFAULT_DEGREE;
    }
}