blob: 54f30e80c273936f207486bd98f5086a4f5f7f97 [file] [log] [blame]
/*******************************************************************************
* 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.sandbox.bridge.bugs;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.security.auth.login.LoginException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IType;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.mylyn.commons.core.StatusHandler;
import org.eclipse.mylyn.internal.bugzilla.core.BugzillaCorePlugin;
import org.eclipse.mylyn.internal.sandbox.ui.SandboxUiPlugin;
import org.eclipse.mylyn.internal.tasks.core.AbstractTask;
import org.eclipse.mylyn.internal.tasks.core.AbstractTaskCategory;
import org.eclipse.mylyn.internal.tasks.core.deprecated.RepositoryTaskData;
import org.eclipse.mylyn.internal.tasks.core.deprecated.TaskComment;
import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin;
import org.eclipse.mylyn.internal.tasks.ui.deprecated.TaskFactory;
import org.eclipse.mylyn.internal.tasks.ui.search.AbstractRepositorySearchQuery;
import org.eclipse.mylyn.internal.tasks.ui.util.TasksUiInternal;
import org.eclipse.mylyn.tasks.core.ITask;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.core.data.TaskData;
import org.eclipse.mylyn.tasks.ui.TasksUi;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
/**
* Bugzilla search operation for Mylar
*
* @author Shawn Minto
* @author Mik Kersten
*/
public class BugzillaMylynSearchOperation extends WorkspaceModifyOperation implements IBugzillaSearchOperation {
/** The IMember we are doing the search for */
private final IMember javaElement;
/** The bugzilla collector for the search */
private ProgressQueryHitCollector collector = null;//SearchHitCollector
/** The status of the search operation */
private IStatus status;
/** The LoginException that was thrown when trying to do the search */
private LoginException loginException = null;
/** The fully qualified name of the member we are searching for */
private final String name;
/** The bugzilla search query */
private AbstractRepositorySearchQuery query;
private final BugzillaMylynSearch search;
private final int scope;
public BugzillaMylynSearchOperation(BugzillaMylynSearch search, IMember m, int scope) {
this.javaElement = m;
this.search = search;
this.scope = scope;
name = getFullyQualifiedName(m);
}
/**
* Get the fully qualified name of a IMember TODO: move to a more central location so that others can use this, but
* don't want to add unecessary coupling
*
* @return String representing the fully qualified name
*/
public static 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();
}
}
@Override
public void execute(IProgressMonitor monitor) {
ProgressQueryHitCollector searchCollector = null;
if (scope == BugzillaMylynSearch.FULLY_QUAL) {
searchCollector = searchQualified(search.getServerUrl(), monitor);
} else if (scope == BugzillaMylynSearch.UNQUAL) {
searchCollector = searchUnqualified(search.getServerUrl(), monitor);
} else if (scope == BugzillaMylynSearch.LOCAL_QUAL) {
searchCollector = searchLocalQual(monitor);
} else if (scope == BugzillaMylynSearch.LOCAL_UNQUAL) {
searchCollector = searchLocalUnQual(monitor);
} else {
status = Status.OK_STATUS;
return;
}
if (searchCollector == null) {
search.notifySearchCompleted(new ArrayList<BugzillaReportInfo>());
return;
}
Set<AbstractTask> l = searchCollector.getTasks();
// get the list of doi elements
List<BugzillaReportInfo> doiList = getDoiList(l);
// we completed the search, so notify all of the listeners
// that the search has been completed
MylynBugsManager.getBridge().addToLandmarksHash(doiList, javaElement, scope);
search.notifySearchCompleted(doiList);
// MIK: commmented out logging
// MonitorPlugin.log(this, "There were " + doiList.size() + " items
// found");
}
/**
* Search the local bugs for the member using the qualified name
*
* @param monitor
* The progress monitor to search with
* @return The QueryHitCollector with the results of the search
*/
@SuppressWarnings("deprecation")
private ProgressQueryHitCollector searchLocalQual(IProgressMonitor monitor) {
// get the fully qualified name for searching
String elementName = getFullyQualifiedName(javaElement);
// setup the search result collector
collector = new ProgressQueryHitCollector(TasksUiInternal.getTaskList(), new TaskFactory(null));//SearchHitCollector(TasksUiPlugin.getTaskList());
//collector.setOperation(this);
collector.setProgressMonitor(monitor);
// get all of the root tasks and start the search
// FIXME
// Set<AbstractTask> tasks = TasksUiPlugin.getTaskList().getOrphanContainer(
// LocalRepositoryConnector.REPOSITORY_URL).getChildren();
Set<ITask> tasks = new HashSet<ITask>();
searchLocal(tasks, collector, elementName, monitor);
for (AbstractTaskCategory cat : TasksUiPlugin.getTaskList().getTaskCategories()) {
searchLocal(cat.getChildren(), collector, elementName, monitor);
}
// return the collector
return collector;
}
/**
* Search the local bugs for the member using the unqualified name
*
* @param monitor
* The progress monitor to search with
* @return The QueryHitCollector with the results of the search
*/
@SuppressWarnings("deprecation")
private ProgressQueryHitCollector searchLocalUnQual(IProgressMonitor monitor) {
// get the element name for searching
String elementName = javaElement.getElementName();
// setup the search result collector
collector = new ProgressQueryHitCollector(TasksUiInternal.getTaskList(), new TaskFactory(null));//SearchHitCollector(TasksUiPlugin.getTaskList());
//collector.setOperation(this);
collector.setProgressMonitor(monitor);
// get all of the root tasks and start the search
// FIXME
// Set<AbstractTask> tasks = TasksUiPlugin.getTaskList().getOrphanContainer(
// LocalRepositoryConnector.REPOSITORY_URL).getChildren();
Set<ITask> tasks = new HashSet<ITask>();
searchLocal(tasks, collector, elementName, monitor);
for (AbstractTaskCategory cat : TasksUiPlugin.getTaskList().getTaskCategories()) {
searchLocal(cat.getChildren(), collector, elementName, monitor);
}
// return the collector
return collector;
}
/**
* Search the local bugs for the member
*
* @param tasks
* The tasks to search
* @param searchCollector
* The collector to add the results to
* @param elementName
* The name of the element that we are looking for
* @param monitor
* The progress monitor
*/
private void searchLocal(Collection<ITask> tasks, ProgressQueryHitCollector searchCollector, String elementName,
IProgressMonitor monitor) {
if (tasks == null) {
return;
}
// go through all of the tasks
for (ITask task : tasks) {
monitor.worked(1);
// check what kind of task it is
// if (task instanceof BugzillaTask) {
// we have a bugzilla task, so get the bug report
// BugzillaTask bugTask = (BugzillaTask) task;
RepositoryTaskData bugTaskData = TasksUiPlugin.getTaskDataStorageManager().getNewTaskData(
task.getRepositoryUrl(), task.getTaskId());
//RepositoryTaskData bugTaskData = bugTask.getTaskData();
// parse the bug report for the element that we are searching
// for
boolean isHit = search(elementName, bugTaskData);
// determine if we have a hit or not
if (isHit) {
// // make a search hit from the bug and then add it to the collector
// BugzillaQueryHit hit = new BugzillaQueryHit(TasksUiPlugin.getTaskList(), bugTaskData.getDescription(), "", bugTaskData.getRepositoryUrl(), bugTaskData.getId(), null, "");
// BugzillaTask task = new BugzillaTask();
// FIXME
// searchCollector.accept(bugTask);
}
// }
}
status = Status.OK_STATUS;
}
/**
* Search the bug for the given element name
*
* @param elementName
* The name of the element to search for
* @param bug
* The bug to search in
*/
private boolean search(String elementName, RepositoryTaskData bug) {
if (bug == null) {
return false; // MIK: added null check here
}
String description = bug.getDescription();
String summary = bug.getSummary();
List<TaskComment> taskComments = bug.getComments();
// search the summary and the summary
if (Util.hasElementName(elementName, summary)) {
return true;
}
if (Util.hasElementName(elementName, description)) {
return true;
}
Iterator<TaskComment> comItr = taskComments.iterator();
while (comItr.hasNext()) {
TaskComment taskComment = comItr.next();
String commentText = taskComment.getText();
// search the text for a reference to the element
if (Util.hasElementName(elementName, commentText)) {
return true;
}
}
return false;
}
/**
* Perform the actual search on the Bugzilla server
*
* @param url
* The url to use for the search
* @param searchCollector
* The collector to put the search results into
* @param monitor
* The progress monitor to use for the search
* @return The QueryHitCollector with the search results
*/
private ProgressQueryHitCollector search(String url, TaskRepository repository,
ProgressQueryHitCollector searchCollector, IProgressMonitor monitor) {
// set the initial number of matches to 0
int matches = 0;
// setup the progress monitor and start the search
searchCollector.setProgressMonitor(monitor);
BugzillaSearchEngine engine = new BugzillaSearchEngine(repository, url);
try {
// perform the search
status = engine.search(searchCollector, matches);
// check the status so that we don't keep searching if there
// is a problem
if (status.getCode() == IStatus.CANCEL) {
return null;
} else if (!status.isOK()) {
MultiStatus errorStatus = new MultiStatus(SandboxUiPlugin.ID_PLUGIN, 0, "Search error", null);
errorStatus.add(status);
StatusHandler.fail(errorStatus);
return null;
}
return searchCollector;
} catch (LoginException e) {
// save this exception to throw later
this.loginException = e;
}
return null;
}
/**
* Perform a search for qualified instances of the member
*
* @param monitor
* The progress monitor to use
* @return The QueryHitCollector with the search results
*/
@SuppressWarnings("deprecation")
private ProgressQueryHitCollector searchQualified(String repositoryUrl, IProgressMonitor monitor) {
// create a new collector for the results
collector = new ProgressQueryHitCollector(TasksUiInternal.getTaskList(), new TaskFactory(null));//SearchHitCollector(TasksUiPlugin.getTaskList());
//collector.setOperation(this);
collector.setProgressMonitor(monitor);
// get the search url
String url = Util.getExactSearchURL(repositoryUrl, javaElement);
TaskRepository repository = TasksUi.getRepositoryManager().getRepository(BugzillaCorePlugin.CONNECTOR_KIND,
repositoryUrl);
return search(url, repository, collector, monitor);
}
/**
* Perform a search for unqualified instances of the member
*
* @param monitor
* The progress monitor to use
* @return The QueryHitCollector with the search results
*/
@SuppressWarnings("deprecation")
private ProgressQueryHitCollector searchUnqualified(String repositoryUrl, IProgressMonitor monitor) {
// create a new collector for the results
collector = new ProgressQueryHitCollector(TasksUiInternal.getTaskList(), new TaskFactory(null));//SearchHitCollector(TasksUiPlugin.getTaskList());
//collector.setOperation(this);
collector.setProgressMonitor(monitor);
// get the search url
String url = Util.getInexactSearchURL(repositoryUrl, javaElement);
TaskRepository repository = TasksUi.getRepositoryManager().getRepository(BugzillaCorePlugin.CONNECTOR_KIND,
repositoryUrl);
return search(url, repository, collector, monitor);
}
/**
* Perform a second pass parse to determine if there are any stack traces in the bug - currently only used for the
* exact search results
*
* @param doiList
* - the list of BugzillaSearchHitDOI elements to parse
*/
public static void secondPassBugzillaParser(List<BugzillaReportInfo> doiList) {
// go through each of the items in the doiList
for (BugzillaReportInfo info : doiList) {
// get the bug report so that we have all of the data
// - descriptions, comments, etc
TaskData b = null;
try {
b = info.getBug();
} catch (Exception e) {
// don't care since null will be caught
}
// if the report could not be downloaded, try the next one
if (b == null) {
continue;
}
// Add back:
// see if the summary has a stack trace in it
// StackTrace[] stackTrace = StackTrace.getStackTrace(b.getDescription(), b.getDescription());
// if (stackTrace != null) {
//
// // add the stack trace to the doi info
// info.setExact(true);
// info.addStackTraces(stackTrace);
// }
// Add back:
// go through all of the comments for the bug
// Iterator<TaskComment> comItr = b.getComments().iterator();
// while (comItr.hasNext()) {
// TaskComment taskComment = comItr.next();
// String commentText = taskComment.getText();
//
// // see if the comment has a stack trace in it
// stackTrace = StackTrace.getStackTrace(commentText, taskComment);
// if (stackTrace != null) {
//
// // add the stack trace to the doi info
// info.setExact(true);
// info.addStackTraces(stackTrace);
// }
// }
}
}
/**
* Add the results returned to the Hash of landmarks
*
* @param results
* The list of results
* @param isExact
* whether the search was exact or not
*/
private List<BugzillaReportInfo> getDoiList(Set<AbstractTask> results) {
List<BugzillaReportInfo> doiList = new ArrayList<BugzillaReportInfo>();
boolean isExact = (scope == BugzillaMylynSearch.FULLY_QUAL || scope == BugzillaMylynSearch.LOCAL_QUAL) ? true
: false;
BugzillaReportInfo info = null;
// go through all of the results and create a DoiInfo list
for (ITask hit : results) {
try {
float value = 0;
info = new BugzillaReportInfo(value, hit, isExact);
// only download the bug for the exact matches
// downloading bugs kills the time - can we do this elsewhere? -
// different thread? persistant?
// if(isExact){
// // get the bug report for the doi info item
// BugReport b = BugzillaRepositoryUtil.getInstance().getBug(
// hit.getId());
// // add the bug to the doi info for future use
// info.setBug(b);
// }
} catch (Exception e) {
StatusHandler.log(new Status(IStatus.INFO, SandboxUiPlugin.ID_PLUGIN, "Search failed", e));
} finally {
doiList.add(info);
}
}
return doiList;
}
/**
* @see org.eclipse.mylyn.internal.bugs.core.search.IBugzillaSearchOperation#getStatus()
*/
public IStatus getStatus() throws LoginException {
// if a LoginException was thrown while trying to search, throw this
if (loginException == null) {
return status;
} else {
throw loginException;
}
}
/**
* @see org.eclipse.mylyn.internal.bugs.core.search.IBugzillaSearchOperation#getImageDescriptor()
*/
public ImageDescriptor getImageDescriptor() {
return null;
}
/**
* Get the member that we are performing the search for
*
* @return The member this search is being performed for
*/
public IMember getSearchMember() {
return javaElement;
}
/**
* Get the name of the member that we are searching for
*
* @return The fully qualified name of the member
*/
public String getSearchMemberName() {
return name;
}
/**
* @see org.eclipse.mylyn.internal.bugs.core.search.IBugzillaSearchOperation#getQuery()
*/
public AbstractRepositorySearchQuery getQuery() {
return query;
}
/**
* @see org.eclipse.mylyn.internal.bugs.core.search.IBugzillaSearchOperation#setQuery(org.eclipse.mylyn.internal.bugs.core.search.AbstractRepositorySearchQuery)
*/
public void setQuery(AbstractRepositorySearchQuery newQuery) {
this.query = newQuery;
}
/**
* Get the name of the element that we are searching for
*
* @return The name of the element
*/
public String getName() {
return name;
}
/**
* Get the scope of the search operation
*
* @return The scope - defined in BugzillaMylarSearch
*/
public int getScope() {
return scope;
}
}