blob: cea547d607d1820abc5046f53495769e491342af [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2017 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.dltk.internal.mylyn.search;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.DLTKLanguageManager;
import org.eclipse.dltk.core.IMember;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.IType;
import org.eclipse.dltk.core.search.IDLTKSearchConstants;
import org.eclipse.dltk.core.search.IDLTKSearchScope;
import org.eclipse.dltk.core.search.SearchEngine;
import org.eclipse.dltk.internal.core.ScriptProject;
import org.eclipse.dltk.internal.mylyn.DLTKStructureBridge;
import org.eclipse.dltk.internal.mylyn.DLTKUiBridgePlugin;
import org.eclipse.dltk.internal.ui.search.DLTKSearchQuery;
import org.eclipse.dltk.internal.ui.search.DLTKSearchResult;
import org.eclipse.dltk.ui.search.ElementQuerySpecification;
import org.eclipse.dltk.ui.search.QuerySpecification;
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.resources.ui.ResourcesUiBridgePlugin;
import org.eclipse.search.ui.ISearchResult;
import org.eclipse.search2.internal.ui.InternalSearchUI;
/**
* @author Mik Kersten
*/
public abstract class AbstractJavaRelationProvider extends AbstractRelationProvider {
public static final String ID_GENERIC = "org.eclipse.mylyn.java.relation"; //$NON-NLS-1$
public static final String NAME = "Java relationships"; //$NON-NLS-1$
private static final int DEFAULT_DEGREE = 2;
private static final List<Job> runningJobs = new ArrayList<>();
@Override
public String getGenericId() {
return ID_GENERIC;
}
protected AbstractJavaRelationProvider(String structureKind, String id) {
super(structureKind, id);
}
@Override
public List<IDegreeOfSeparation> getDegreesOfSeparation() {
List<IDegreeOfSeparation> separations = new ArrayList<>();
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 == null) {
return;
}
if (node.getContentType() == null) {
StatusHandler.log(new Status(IStatus.WARNING, DLTKUiBridgePlugin.ID_PLUGIN, "Null content type for: " //$NON-NLS-1$
+ node));
return;
}
if (!node.getContentType().equals(DLTKStructureBridge.CONTENT_TYPE)) {
return;
}
IModelElement javaElement = DLTKCore.create(node.getHandleIdentifier());
if (!acceptElement(javaElement) || !javaElement.exists()/*
* ||
* javaElement
* instanceof
* IInitializer
*/) {
return;
}
IDLTKSearchScope scope = createJavaSearchScope(javaElement, degreeOfSeparation);
if (scope != null) {
runJob(node, degreeOfSeparation, getId());
}
}
private IDLTKSearchScope createJavaSearchScope(IModelElement element, int degreeOfSeparation) {
Set<IInteractionElement> landmarks = ContextCore.getContextManager().getActiveLandmarks();
List<IInteractionElement> interestingElements = ContextCore.getContextManager()
.getActiveContext()
.getInteresting();
Set<IModelElement> searchElements = new HashSet<>();
int includeMask = IDLTKSearchScope.SOURCES;
if (degreeOfSeparation == 1) {
for (IInteractionElement landmark : landmarks) {
AbstractContextStructureBridge bridge = ContextCore.getStructureBridge(landmark.getContentType());
if (includeNodeInScope(landmark, bridge)) {
Object o = bridge.getObjectForHandle(landmark.getHandleIdentifier());
if (o instanceof IModelElement) {
IModelElement landmarkElement = (IModelElement) o;
if (landmarkElement.exists()) {
if (landmarkElement instanceof IMember && !landmark.getInterest().isPropagated()) {
searchElements.add(((IMember) landmarkElement).getSourceModule());
} else if (landmarkElement instanceof ISourceModule) {
searchElements.add(landmarkElement);
}
}
}
}
}
} else if (degreeOfSeparation == 2) {
for (IInteractionElement interesting : interestingElements) {
AbstractContextStructureBridge bridge = ContextCore.getStructureBridge(interesting.getContentType());
if (includeNodeInScope(interesting, bridge)) {
Object object = bridge.getObjectForHandle(interesting.getHandleIdentifier());
if (object instanceof IModelElement) {
IModelElement interestingElement = (IModelElement) object;
if (interestingElement.exists()) {
if (interestingElement instanceof IMember && !interesting.getInterest().isPropagated()) {
searchElements.add(((IMember) interestingElement).getSourceModule());
} else if (interestingElement instanceof ISourceModule) {
searchElements.add(interestingElement);
}
}
}
}
}
} else if (degreeOfSeparation == 3 || degreeOfSeparation == 4) {
for (IInteractionElement interesting : interestingElements) {
AbstractContextStructureBridge bridge = ContextCore.getStructureBridge(interesting.getContentType());
if (includeNodeInScope(interesting, bridge)) {
// TODO what to do when the element is not a java element,
// how determine if a javaProject?
IResource resource = ResourcesUiBridgePlugin.getDefault().getResourceForElement(interesting, true);
if (resource != null) {
IProject project = resource.getProject();
if (project != null && ScriptProject.hasScriptNature(project) && project.exists()) {
IScriptProject javaProject = DLTKCore.create(project);// ((IModelElement)o).getJavaProject();
if (javaProject != null && javaProject.exists()) {
searchElements.add(javaProject);
}
}
}
}
}
if (degreeOfSeparation == 4) {
includeMask = IDLTKSearchScope.SOURCES | IDLTKSearchScope.APPLICATION_LIBRARIES
| IDLTKSearchScope.SYSTEM_LIBRARIES;
}
} else if (degreeOfSeparation == 5) {
return SearchEngine.createWorkspaceScope(DLTKLanguageManager.getLanguageToolkit(element));
}
if (searchElements.size() == 0) {
return null;
} else {
IModelElement[] elements = new IModelElement[searchElements.size()];
int j = 0;
for (IModelElement searchElement : searchElements) {
elements[j] = searchElement;
j++;
}
return SearchEngine.createSearchScope(elements, includeMask,
DLTKLanguageManager.getLanguageToolkit(element));
}
}
/**
* Only include Java elements and files.
*/
private boolean includeNodeInScope(IInteractionElement interesting, AbstractContextStructureBridge bridge) {
if (interesting == null || bridge == null) {
return false;
} else {
if (interesting.getContentType() == null) {
// TODO: remove
StatusHandler.log(new Status(IStatus.WARNING, DLTKUiBridgePlugin.ID_PLUGIN, "Null content type for: " //$NON-NLS-1$
+ interesting.getHandleIdentifier()));
return false;
} else {
return interesting.getContentType().equals(DLTKStructureBridge.CONTENT_TYPE)
|| bridge.isDocument(interesting.getHandleIdentifier());
}
}
}
protected boolean acceptResultElement(IModelElement element) {
return true; // !(element instanceof IImportDeclaration);
}
protected boolean acceptElement(IModelElement javaElement) {
return javaElement != null && (javaElement instanceof IMember || javaElement instanceof IType);
}
private void runJob(final IInteractionElement node, final int degreeOfSeparation, final String kind) {
int limitTo = 0;
if (kind.equals(DLTKReferencesProvider.ID)) {
limitTo = IDLTKSearchConstants.REFERENCES;
// } else if (kind.equals(JavaImplementorsProvider.ID)) {
// limitTo = IDLTKSearchConstants.IMPLEMENTORS;
} else if (kind.equals(JUnitReferencesProvider.ID)) {
limitTo = IDLTKSearchConstants.REFERENCES;
} else if (kind.equals(DLTKReadAccessProvider.ID)) {
limitTo = IDLTKSearchConstants.REFERENCES;
} else if (kind.equals(DLTKWriteAccessProvider.ID)) {
limitTo = IDLTKSearchConstants.REFERENCES;
}
final JavaSearchOperation query = (JavaSearchOperation) getSearchOperation(node, limitTo, degreeOfSeparation);
if (query == null) {
return;
}
JavaSearchJob job = new JavaSearchJob(query.getLabel(), query);
query.addListener(new IActiveSearchListener() {
private boolean gathered = false;
@Override
public boolean resultsGathered() {
return gathered;
}
@Override
public void searchCompleted(List<?> l) {
if (l == null) {
return;
}
List<IModelElement> relatedHandles = new ArrayList<>();
Object[] elements = l.toArray();
for (Object element : elements) {
if (element instanceof IModelElement) {
relatedHandles.add((IModelElement) element);
}
}
for (IModelElement element : relatedHandles) {
if (!acceptResultElement(element)) {
continue;
}
incrementInterest(node, DLTKStructureBridge.CONTENT_TYPE, element.getHandleIdentifier(),
degreeOfSeparation);
}
gathered = true;
AbstractJavaRelationProvider.this.searchCompleted(node);
}
});
InternalSearchUI.getInstance();
runningJobs.add(job);
job.setPriority(Job.DECORATE - 10);
job.schedule();
}
@Override
public IActiveSearchOperation getSearchOperation(IInteractionElement node, int limitTo, int degreeOfSeparation) {
IModelElement javaElement = DLTKCore.create(node.getHandleIdentifier());
if (javaElement == null || !javaElement.exists()) {
return null;
}
IDLTKSearchScope scope = createJavaSearchScope(javaElement, degreeOfSeparation);
if (scope == null) {
return null;
}
QuerySpecification specs = new ElementQuerySpecification(javaElement, limitTo, scope,
Messages.AbstractJavaRelationProvider_Mylyn_degree_of_separation + degreeOfSeparation);
return new JavaSearchOperation(specs);
}
protected static class JavaSearchJob extends Job {
private final JavaSearchOperation op;
public JavaSearchJob(String name, JavaSearchOperation op) {
super(name);
this.op = op;
}
/**
* @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected IStatus run(IProgressMonitor monitor) {
return op.run(monitor);
}
}
protected static class JavaSearchOperation extends DLTKSearchQuery implements IActiveSearchOperation {
private ISearchResult result = null;
@Override
public ISearchResult getSearchResult() {
if (result == null) {
result = new DLTKSearchResult(this);
}
new DLTKActiveSearchResultUpdater((DLTKSearchResult) result);
return result;
}
@Override
public IStatus run(IProgressMonitor monitor) {
try {
IStatus runStatus = super.run(monitor);
ISearchResult result = getSearchResult();
if (result instanceof DLTKSearchResult) {
// TODO make better
Object[] objs = ((DLTKSearchResult) result).getElements();
if (objs == null) {
notifySearchCompleted(null);
} else {
List<Object> l = new ArrayList<>();
for (Object obj : objs) {
l.add(obj);
}
notifySearchCompleted(l);
}
}
return runStatus;
} catch (Throwable t) {
StatusHandler.log(new Status(IStatus.ERROR, DLTKUiBridgePlugin.ID_PLUGIN, "Java search failed", t)); //$NON-NLS-1$
}
IStatus status = new Status(IStatus.WARNING, ContextCorePlugin.ID_PLUGIN, IStatus.OK,
Messages.AbstractJavaRelationProvider_could_not_run_Java_search, null);
notifySearchCompleted(null);
return status;
}
/**
* Constructor
*
* @param data
*/
public JavaSearchOperation(QuerySpecification data) {
super(data);
}
/** List of listeners wanting to know about the searches */
private final List<IActiveSearchListener> listeners = new ArrayList<>();
/**
* Add a listener for when the bugzilla search is completed
*
* @param l
* The listener to add
*/
@Override
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
*/
@Override
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 void stopAllRunningJobs() {
for (Job j : runningJobs) {
j.cancel();
}
runningJobs.clear();
}
@Override
protected int getDefaultDegreeOfSeparation() {
return DEFAULT_DEGREE;
}
}