From 23c8cbf0c6d069ce144d0844eb6071420662b796 Mon Sep 17 00:00:00 2001 From: mkersten Date: Tue, 12 Jul 2005 23:41:41 +0000 Subject: Progress on Bugzilla Bug 103099 decouple tasks from mylar.ui --- org.eclipse.mylyn.tasks.core/.classpath | 7 + org.eclipse.mylyn.tasks.core/.cvsignore | 1 + org.eclipse.mylyn.tasks.core/.project | 28 ++ org.eclipse.mylyn.tasks.core/META-INF/MANIFEST.MF | 20 + org.eclipse.mylyn.tasks.core/build.properties | 4 + org.eclipse.mylyn.tasks.core/plugin.xml | 9 + .../mylyn/bugzilla/BugzillaEditingMonitor.java | 46 ++ .../mylyn/bugzilla/BugzillaMylarBridge.java | 143 ++++++ .../mylyn/bugzilla/BugzillaNodeLabelProvider.java | 66 +++ .../mylyn/bugzilla/BugzillaStructureBridge.java | 279 +++++++++++ .../eclipse/mylyn/bugzilla/BugzillaUiBridge.java | 141 ++++++ .../mylyn/bugzilla/MylarBugzillaPlugin.java | 100 ++++ .../mylyn/tasks/search/BugzillaMylarSearch.java | 174 +++++++ .../mylyn/tasks/search/BugzillaMylarSearchJob.java | 109 +++++ .../tasks/search/BugzillaMylarSearchOperation.java | 526 +++++++++++++++++++++ .../tasks/search/BugzillaReferencesProvider.java | 143 ++++++ .../src/org/eclipse/mylyn/tasks/search/Util.java | 195 ++++++++ 17 files changed, 1991 insertions(+) create mode 100644 org.eclipse.mylyn.tasks.core/.classpath create mode 100644 org.eclipse.mylyn.tasks.core/.cvsignore create mode 100644 org.eclipse.mylyn.tasks.core/.project create mode 100644 org.eclipse.mylyn.tasks.core/META-INF/MANIFEST.MF create mode 100644 org.eclipse.mylyn.tasks.core/build.properties create mode 100644 org.eclipse.mylyn.tasks.core/plugin.xml create mode 100644 org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/BugzillaEditingMonitor.java create mode 100644 org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/BugzillaMylarBridge.java create mode 100644 org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/BugzillaNodeLabelProvider.java create mode 100644 org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/BugzillaStructureBridge.java create mode 100644 org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/BugzillaUiBridge.java create mode 100644 org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/MylarBugzillaPlugin.java create mode 100644 org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/search/BugzillaMylarSearch.java create mode 100644 org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/search/BugzillaMylarSearchJob.java create mode 100644 org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/search/BugzillaMylarSearchOperation.java create mode 100644 org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/search/BugzillaReferencesProvider.java create mode 100644 org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/search/Util.java (limited to 'org.eclipse.mylyn.tasks.core') diff --git a/org.eclipse.mylyn.tasks.core/.classpath b/org.eclipse.mylyn.tasks.core/.classpath new file mode 100644 index 000000000..751c8f2e5 --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.eclipse.mylyn.tasks.core/.cvsignore b/org.eclipse.mylyn.tasks.core/.cvsignore new file mode 100644 index 000000000..ba077a403 --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/.cvsignore @@ -0,0 +1 @@ +bin diff --git a/org.eclipse.mylyn.tasks.core/.project b/org.eclipse.mylyn.tasks.core/.project new file mode 100644 index 000000000..d9ab28171 --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/.project @@ -0,0 +1,28 @@ + + + org.eclipse.mylar.bugzilla + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.eclipse.mylyn.tasks.core/META-INF/MANIFEST.MF b/org.eclipse.mylyn.tasks.core/META-INF/MANIFEST.MF new file mode 100644 index 000000000..ae5939677 --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/META-INF/MANIFEST.MF @@ -0,0 +1,20 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Mylar Bugzilla Plug-in +Bundle-SymbolicName: org.eclipse.mylar.bugzilla;singleton:=true +Bundle-Version: 0.3.1 +Bundle-Activator: org.eclipse.mylar.bugzilla.MylarBugzillaPlugin +Bundle-Localization: plugin +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.eclipse.mylar.core, + org.eclipse.mylar.ui, + org.eclipse.mylar.bugzilla.ui, + org.eclipse.mylar.bugzilla.core, + org.eclipse.jdt.core, + org.eclipse.ui.ide, + org.eclipse.core.resources, + org.eclipse.mylar.tasks +Eclipse-AutoStart: true +Export-Package: org.eclipse.mylar.bugzilla, + org.eclipse.mylar.tasks.search diff --git a/org.eclipse.mylyn.tasks.core/build.properties b/org.eclipse.mylyn.tasks.core/build.properties new file mode 100644 index 000000000..34d2e4d2d --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/org.eclipse.mylyn.tasks.core/plugin.xml b/org.eclipse.mylyn.tasks.core/plugin.xml new file mode 100644 index 000000000..e593c5e63 --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/plugin.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/BugzillaEditingMonitor.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/BugzillaEditingMonitor.java new file mode 100644 index 000000000..3bee8b160 --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/BugzillaEditingMonitor.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2004 - 2005 University Of British Columbia 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: + * University Of British Columbia - initial API and implementation + *******************************************************************************/ +/* + * Created on Apr 27, 2005 + */ +package org.eclipse.mylar.bugzilla; + +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.mylar.bugzilla.ui.editor.AbstractBugEditor; +import org.eclipse.mylar.bugzilla.ui.outline.BugzillaReportSelection; +import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaTaskEditor; +import org.eclipse.mylar.core.AbstractSelectionMonitor; +import org.eclipse.ui.IWorkbenchPart; + + +/** + * @author Mik Kersten + */ +public class BugzillaEditingMonitor extends AbstractSelectionMonitor { + + public BugzillaEditingMonitor() { + super(); + } + + @Override + protected void handleWorkbenchPartSelection(IWorkbenchPart part, ISelection selection) { + if(!(part instanceof AbstractBugEditor) && !(part instanceof BugzillaTaskEditor)) + return; + + if(selection instanceof StructuredSelection){ + StructuredSelection ss = (StructuredSelection)selection; + Object object = ss.getFirstElement(); + if(object instanceof BugzillaReportSelection) super.handleElementSelection(part, object); + } + } + +} diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/BugzillaMylarBridge.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/BugzillaMylarBridge.java new file mode 100644 index 000000000..38325ab31 --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/BugzillaMylarBridge.java @@ -0,0 +1,143 @@ +/******************************************************************************* + * Copyright (c) 2004 - 2005 University Of British Columbia 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: + * University Of British Columbia - initial API and implementation + *******************************************************************************/ +/* + * Created on Oct 1, 2004 + */ +package org.eclipse.mylar.bugzilla; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IMember; +import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaReportNode; + + +/** + * Class to handle the bridge between mylar and bugzilla + * + * @author Shawn Minto + */ +public class BugzillaMylarBridge { + + /** The hash of all of the landmarks and their related search hits */ + private HashMap>> landmarksHash; + /** + * The currently running search jobs so that we can cancel it if necessary
KEY: IMember VALUE: Job + */ + public static HashMap runningJobs = new HashMap(); + + /** + * Constructor + */ + public BugzillaMylarBridge() { + landmarksHash = new HashMap>>(); + } + + + /** + * Remove a landmark from the hash + * + * @param removed + * This landmark to remove (IJavaElement) + */ + public void removeFromLandmarksHash(IJavaElement removed) { + landmarksHash.remove(removed.getHandleIdentifier()); + } + + /** + * Remove all of the landmarks from the hash that are in the list + * + * @param removed + * This list of landmarks to remove (IJavaElements) + */ + public void removeFromLandmarksHash(List removed) { + + for(IJavaElement je : removed) { + landmarksHash.remove(je.getHandleIdentifier()); + } + } + + /** + * Add data to the landmarks hash + * + * @param doiList + * The list of BugzillaSearchHitDoiInfo + * @param m + * The member that this list is for + */ + public void addToLandmarksHash(List doiList, IMember m, int scope) { + Map> searches = landmarksHash.get(m.getHandleIdentifier()); + + if(searches == null){ + searches = new HashMap>(); + } + searches.put(scope, doiList); + landmarksHash.put(m.getHandleIdentifier(), searches); + } + + /** + * Get the doiList for the given IMember from the landmarks hash + * + * @param m + * The member to get the doiList for + * @return The doiList or null if it doesn't exist + */ + public List getFromLandmarksHash(IMember m, int scope) { + Map> scopes = landmarksHash.get(m.getHandleIdentifier()); + if(scopes == null) + return null; + else + return scopes.get(scope); + } + + /** + * Determine whether the current element has a search job running for it + * + * @param e + * The element that we want to know whether there is a search job + * or not + * @return true if it does else false + */ + public static boolean doesJobExist(String handle) { + return runningJobs.containsKey(handle); + } + + /** + * Remove search job for the given element + * + * @param m + * The element that we want to make sure that the search is + * canceled for + */ + public static void removeSearchJob(String handle) { + + // make sure that there wasn't a previous search job that we know + // of. If there was, cancel it + if (doesJobExist(handle)) { + // get the search job and wait until it is cancelled + Job prevJob = runningJobs.get(handle); + prevJob.cancel(); + runningJobs.remove(handle); + } + } + + /** + * Add a search job to our list + * @param handle The handle of the element that we are searching for + * @param searchJob The job that represents the search + */ + public static void addJob(String handle, Job searchJob) { + runningJobs.put(handle, searchJob); + } +} \ No newline at end of file diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/BugzillaNodeLabelProvider.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/BugzillaNodeLabelProvider.java new file mode 100644 index 000000000..b43781a00 --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/BugzillaNodeLabelProvider.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2004 - 2005 University Of British Columbia 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: + * University Of British Columbia - initial API and implementation + *******************************************************************************/ +/* + * Created on Apr 18, 2005 + */ +package org.eclipse.mylar.bugzilla; + +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.mylar.bugzilla.core.BugReport; +import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaReportNode; +import org.eclipse.mylar.core.model.ITaskscapeNode; +import org.eclipse.mylar.ui.MylarImages; +import org.eclipse.swt.graphics.Image; + +/** + * @author Mik Kersten + */ +public class BugzillaNodeLabelProvider implements ILabelProvider { + + public Image getImage(Object element) { + return MylarImages.getImage(MylarImages.BUG); + } + + /** + * TODO: slow? + */ + public String getText(Object element) { + ITaskscapeNode node = (ITaskscapeNode)element; + + // try to get from the cache before downloading + Object report; + BugzillaReportNode reportNode = MylarBugzillaPlugin.getReferenceProvider().getCached(node.getElementHandle()); + BugReport cachedReport = MylarBugzillaPlugin.getDefault().getStructureBridge().getCached(node.getElementHandle()); + if(reportNode != null && cachedReport == null){ + report = reportNode; + } else{ + report = MylarBugzillaPlugin.getDefault().getStructureBridge().getObjectForHandle(node.getElementHandle()); + } + return MylarBugzillaPlugin.getDefault().getStructureBridge().getName(report); + } + + public void addListener(ILabelProviderListener listener) { + // don't need to worry about listeners + } + + public void dispose() { + // don't care about dispose + } + + public boolean isLabelProperty(Object element, String property) { + return false; + } + + public void removeListener(ILabelProviderListener listener) { + // don't need to worry about listeners + } +} diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/BugzillaStructureBridge.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/BugzillaStructureBridge.java new file mode 100644 index 000000000..3d49edeaf --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/BugzillaStructureBridge.java @@ -0,0 +1,279 @@ +/******************************************************************************* + * Copyright (c) 2004 - 2005 University Of British Columbia 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: + * University Of British Columbia - initial API and implementation + *******************************************************************************/ +/* + * Created on May 2, 2005 + */ +package org.eclipse.mylar.bugzilla; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Platform; +import org.eclipse.mylar.bugzilla.core.BugReport; +import org.eclipse.mylar.bugzilla.core.BugzillaRepository; +import org.eclipse.mylar.bugzilla.core.BugzillaTools; +import org.eclipse.mylar.bugzilla.core.IBugzillaBug; +import org.eclipse.mylar.bugzilla.core.search.BugzillaSearchHit; +import org.eclipse.mylar.bugzilla.ui.editor.AbstractBugEditor; +import org.eclipse.mylar.bugzilla.ui.outline.BugzillaOutlineNode; +import org.eclipse.mylar.bugzilla.ui.outline.BugzillaReportSelection; +import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaCacheFile; +import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaReportNode; +import org.eclipse.mylar.core.IMylarStructureBridge; +import org.eclipse.mylar.core.MylarPlugin; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.actions.WorkspaceModifyOperation; +import org.eclipse.ui.progress.IProgressService; +import org.eclipse.ui.views.markers.internal.ProblemMarker; + + +public class BugzillaStructureBridge implements IMylarStructureBridge { + + public final static String EXTENSION = "bugzilla"; + + public String getResourceExtension() { + return EXTENSION; + } + + public BugzillaStructureBridge() { + super(); + readCacheFile(); + } + + /** + * Handle format: ;; + * + * Use: BugzillaTools ??? + */ + public String getHandleIdentifier(Object object) { + if(object instanceof BugzillaOutlineNode){ + BugzillaOutlineNode n = (BugzillaOutlineNode)object; + return BugzillaTools.getHandle(n); + } + else if(object instanceof BugzillaReportSelection){ + BugzillaReportSelection n = (BugzillaReportSelection)object; + return BugzillaTools.getHandle(n); + } + return null; + } + + private BugReport result; + + public Object getObjectForHandle(final String handle) { + result = null; + + String [] parts = handle.split(";"); + if (parts.length >= 2){ + String server = parts[0]; + final int id = Integer.parseInt(parts[1]); + + String bugHandle = server + ";" + id; + + int commentNumber = -1; + if(parts.length == 3){ + commentNumber = Integer.parseInt(parts[2]); + } + + // get the bugzillaOutlineNode for the element + IEditorPart editorPart = null; + try{ + editorPart = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor(); + }catch(NullPointerException e){ + // do nothing, this just means that there is no active page + } + if(editorPart != null && editorPart instanceof AbstractBugEditor){ + AbstractBugEditor abe = ((AbstractBugEditor)editorPart); + BugzillaOutlineNode node = abe.getModel(); + return findNode(node, commentNumber); + } + + // try to get from the cache, if it doesn't exist, startup an operation to get it + result = getFromCache(bugHandle); + if(result == null){ + WorkspaceModifyOperation op = new WorkspaceModifyOperation() { + protected void execute(IProgressMonitor monitor) throws CoreException { + monitor.beginTask("Downloading Bug# " + id, IProgressMonitor.UNKNOWN); + try { + result = BugzillaRepository.getInstance().getCurrentBug(id); + }catch(Exception e){ + result = null; + } + }}; + + // Use the progess service to execute the runnable + IProgressService service = PlatformUI.getWorkbench().getProgressService(); + try { + service.run(false, false, op); + } catch (InvocationTargetException e) { + // Operation was canceled + } catch (InterruptedException e) { + // Handle the wrapped exception + } + + if(result != null) + cache(bugHandle, result); + } + + BugzillaOutlineNode node = BugzillaOutlineNode.parseBugReport(result); + return findNode(node, commentNumber); + } + else{ + return null; + } + } + + private BugzillaOutlineNode findNode(BugzillaOutlineNode startNode, int commentNumber){ + + if(commentNumber == -1){ + return startNode; + }else if(startNode.getComment() != null && startNode.getComment().getNumber() == commentNumber -1){ + return startNode; + } else if(startNode.isCommentHeader() && commentNumber == 1){ + return startNode; + }else if(startNode.isDescription() && commentNumber == 0){ + return startNode; + } + + BugzillaOutlineNode[] children = startNode.getChildren(); + for(int i = 0; i < children.length; i++){ + BugzillaOutlineNode n = findNode(children[i], commentNumber); + if(n != null) + return n; + } + return null; + } + + public String getParentHandle(String handle) { + + //check so that we don't need to try to get the parent if we are already at the bug report + if(!handle.matches(".*;.*;.*")) + return null; + + BugzillaOutlineNode bon = (BugzillaOutlineNode)getObjectForHandle(handle); + if(bon != null && bon.getParent() != null) + return BugzillaTools.getHandle(bon.getParent()); + else + return null; +// String [] parts = handle.split(";"); +// if (parts.length == 1){ +// return null; +// }else if (parts.length > 2) { +// String newHandle = ""; +// for(int i = 0; i < parts.length - 1; i++) +// newHandle += parts[i] + ";"; +// return newHandle.substring(0, newHandle.length() - 1); +//// return handle.substring(0, handle.lastIndexOf(";")); +// } +// return null; + } + + public String getName(Object object) { + if(object instanceof BugzillaOutlineNode){ + BugzillaOutlineNode b = (BugzillaOutlineNode)object; + return BugzillaTools.getName(b); + } else if (object instanceof BugzillaReportNode){ + BugzillaSearchHit hit = ((BugzillaReportNode)object).getHit(); + return hit.getServer() + ": Bug#: " + hit.getId() + ": " + hit.getDescription(); + } + return ""; + } + + public boolean canBeLandmark(Object element) { + return false; + } + + public boolean acceptsObject(Object object) { + return object instanceof BugzillaOutlineNode || object instanceof BugzillaReportSelection; + } + + public boolean canFilter(Object element) { + return true; + } + + public boolean isDocument(String handle) { + return (handle.indexOf(';') == handle.lastIndexOf(';') && handle.indexOf(";") != -1); + } + + public String getHandleForMarker(ProblemMarker marker) { + return null; + } + + public IProject getProjectForObject(Object object) { + // bugzilla objects do not yet sit in a project + return null; + } + + public String getResourceExtension(String elementHandle) { + return getResourceExtension(); + } + + /* + * + * STUFF FOR CACHING BUG REPORTS + * + */ + + // bug report cache + private Map cache = new HashMap(); + + public void cache(String handle, BugReport report) { + cache.put(handle, report); + cacheFile.add(report); + } + + public void clearCache(){ + cache.clear(); + cacheFile.removeAll(); + } + + private BugReport getFromCache(String bugHandle) { + return cache.get(bugHandle); + } + + public Set getCachedHandles(){ + return cache.keySet(); + } + + private BugzillaCacheFile cacheFile; + + private IPath getCacheFile() { + IPath stateLocation = Platform.getPluginStateLocation(MylarBugzillaPlugin.getDefault()); + IPath configFile = stateLocation.append("offlineReports"); + return configFile; + } + + private void readCacheFile() { + IPath cachPath = getCacheFile(); + + try { + cacheFile = new BugzillaCacheFile(cachPath.toFile()); + ArrayList cached = cacheFile.elements(); + for(IBugzillaBug bug: cached){ + if(bug instanceof BugReport) + cache.put(BugzillaTools.getHandle(bug), (BugReport)bug); + } + } catch (Exception e) { + MylarPlugin.log(e, "occurred while restoring saved offline Bugzilla reports."); + } + } + + public BugReport getCached(String handle) { + return cache.get(handle); + } +} diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/BugzillaUiBridge.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/BugzillaUiBridge.java new file mode 100644 index 000000000..9a340df45 --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/BugzillaUiBridge.java @@ -0,0 +1,141 @@ +/******************************************************************************* + * Copyright (c) 2004 - 2005 University Of British Columbia 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: + * University Of British Columbia - initial API and implementation + *******************************************************************************/ +/* + * Created on Apr 6, 2005 + */ +package org.eclipse.mylar.bugzilla; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.mylar.bugzilla.ui.BugzillaOpenStructure; +import org.eclipse.mylar.bugzilla.ui.ViewBugzillaAction; +import org.eclipse.mylar.bugzilla.ui.editor.AbstractBugEditor; +import org.eclipse.mylar.bugzilla.ui.outline.BugzillaOutlinePage; +import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaTask; +import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaTaskEditor; +import org.eclipse.mylar.core.model.ITaskscapeNode; +import org.eclipse.mylar.tasks.ITask; +import org.eclipse.mylar.tasks.MylarTasksPlugin; +import org.eclipse.mylar.tasks.search.BugzillaReferencesProvider; +import org.eclipse.mylar.ui.IMylarUiBridge; +import org.eclipse.mylar.ui.MylarImages; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.internal.Workbench; + +public class BugzillaUiBridge implements IMylarUiBridge { + + protected BugzillaNodeLabelProvider labelProvider = new BugzillaNodeLabelProvider(); + + public void open(ITaskscapeNode node) { + String handle = node.getElementHandle(); + String bugHandle = handle; + String server =handle.substring(0, handle.indexOf(";")); + + handle = handle.substring(handle.indexOf(";") + 1); + int next = handle.indexOf(";"); + + int bugId; + int commentNumer = -1; + if(next == -1){ + bugId = Integer.parseInt(handle); + } + else{ + bugId = Integer.parseInt(handle.substring(0, handle.indexOf(";"))); + commentNumer = Integer.parseInt(handle.substring(handle.indexOf(";") + 1)); + bugHandle = bugHandle.substring(0, next); + } + + List l = new ArrayList(1); + l.add(new BugzillaOpenStructure(server, bugId, commentNumer)); + + ITask task= MylarTasksPlugin.getTaskListManager().getTaskList().getTaskForId(bugHandle); + if (task != null && task instanceof BugzillaTask) { + BugzillaTask bugzillaTask = (BugzillaTask)task; + bugzillaTask.openTask(commentNumer); + } else { + // open the bug in the editor + ViewBugzillaAction viewBugs = new ViewBugzillaAction("Display bugs in editor", l); + viewBugs.schedule(); + } + } + + public ILabelProvider getLabelProvider() { + return labelProvider; + } + + public void close(ITaskscapeNode node) { + IWorkbenchPage page = Workbench.getInstance().getActiveWorkbenchWindow().getActivePage(); + if (page != null) { + IEditorReference[] references = page.getEditorReferences(); + for (int i = 0; i < references.length; i++) { + IEditorPart part = references[i].getEditor(false); + if (part != null) { + if (part instanceof AbstractBugEditor) { + ((AbstractBugEditor)part).close(); + } else if(part instanceof BugzillaTaskEditor){ + ((BugzillaTaskEditor)part).close(); + } + } + } + } + } + + public boolean acceptsEditor(IEditorPart editorPart) { + return editorPart instanceof AbstractBugEditor; + } + + public List getTreeViewers(IEditorPart editor) { + ArrayList outlines = new ArrayList(1); + TreeViewer outline = getOutlineTreeViewer(editor); + if (outline != null) { + outlines.add(outline); + return outlines; + } else { + return Collections.emptyList(); + } + } + + protected TreeViewer getOutlineTreeViewer(IEditorPart editor) { + if(editor instanceof AbstractBugEditor){ + AbstractBugEditor abe = (AbstractBugEditor)editor; + BugzillaOutlinePage outline = abe.getOutline(); + if(outline != null) return outline.getOutlineTreeViewer(); + } + return null; + } + + public void refreshOutline(Object element, boolean updateLabels) { + IEditorPart editorPart = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor(); + TreeViewer treeViewer = getOutlineTreeViewer(editorPart); + if (treeViewer != null) { + treeViewer.refresh(true); + + treeViewer.expandAll(); + } + } + + public ImageDescriptor getIconForRelationship(String relationshipHandle) { + return MylarImages.EDGE_REF_BUGZILLA; + + } + + public String getNameForRelationship(String relationshipHandle) { + return BugzillaReferencesProvider.NAME; + } +} diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/MylarBugzillaPlugin.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/MylarBugzillaPlugin.java new file mode 100644 index 000000000..6bcf64076 --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/bugzilla/MylarBugzillaPlugin.java @@ -0,0 +1,100 @@ +package org.eclipse.mylar.bugzilla; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.mylar.core.MylarPlugin; +import org.eclipse.mylar.tasks.search.BugzillaReferencesProvider; +import org.eclipse.mylar.ui.MylarUiPlugin; +import org.eclipse.ui.IStartup; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.internal.Workbench; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The main plugin class to be used in the desktop. + */ +public class MylarBugzillaPlugin extends AbstractUIPlugin implements IStartup { + + private static BugzillaMylarBridge bridge = null; + private static BugzillaReferencesProvider referencesProvider = new BugzillaReferencesProvider(); + private BugzillaStructureBridge structureBridge; + + private static MylarBugzillaPlugin plugin; + + public MylarBugzillaPlugin() { + plugin = this; + } + + public void earlyStartup() { + final IWorkbench workbench = PlatformUI.getWorkbench(); + workbench.getDisplay().asyncExec(new Runnable() { + public void run() { + structureBridge = new BugzillaStructureBridge(); + + MylarPlugin.getDefault().addBridge(structureBridge); + MylarPlugin.getTaskscapeManager().addListener(referencesProvider); + MylarUiPlugin.getDefault().addAdapter(BugzillaStructureBridge.EXTENSION, new BugzillaUiBridge()); + MylarPlugin.getDefault().getSelectionMonitors().add(new BugzillaEditingMonitor()); + + IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); + if (window != null) { + // create a new bridge and initialize it + bridge = new BugzillaMylarBridge(); + } + } + }); + } + + /** + * This method is called upon plug-in activation + */ + public void start(BundleContext context) throws Exception { + super.start(context); + } + + /** + * This method is called when the plug-in is stopped + */ + public void stop(BundleContext context) throws Exception { + super.stop(context); + plugin = null; + } + + /** + * Returns the shared instance. + */ + public static MylarBugzillaPlugin getDefault() { + return plugin; + } + + /** + * Returns an image descriptor for the image file at the given + * plug-in relative path. + * + * @param path the path + * @return the image descriptor + */ + public static ImageDescriptor getImageDescriptor(String path) { + return AbstractUIPlugin.imageDescriptorFromPlugin("org.eclipse.mylar.bugzilla.bridge", path); + } + + public static BugzillaMylarBridge getBridge() { + // make sure that the bridge initialized, if not, make a new one + if (bridge == null) { + bridge = new BugzillaMylarBridge(); + } + return bridge; + } + + + public BugzillaStructureBridge getStructureBridge() { + return structureBridge; + } + + public static BugzillaReferencesProvider getReferenceProvider() { + return referencesProvider; + + } +} diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/search/BugzillaMylarSearch.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/search/BugzillaMylarSearch.java new file mode 100644 index 000000000..0abfd8126 --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/search/BugzillaMylarSearch.java @@ -0,0 +1,174 @@ +/******************************************************************************* + * Copyright (c) 2004 - 2005 University Of British Columbia 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: + * University Of British Columbia - initial API and implementation + *******************************************************************************/ +/* + * Created on Oct 13, 2004 + */ +package org.eclipse.mylar.tasks.search; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +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.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IMember; +import org.eclipse.mylar.bugzilla.BugzillaMylarBridge; +import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaReportNode; +import org.eclipse.mylar.core.model.InterestComparator; +import org.eclipse.mylar.core.search.IActiveSearchListener; +import org.eclipse.mylar.core.search.IMylarSearchOperation; + + +/** + * Used to facilitate bugzilla searches based on IJavaElements + * + * @author Shawn Minto + */ +public class BugzillaMylarSearch implements IMylarSearchOperation { + + // scope identifiers + public static final int LOCAL_QUAL = 1; // local implies a bugzilla task, not just an offline report + public static final int LOCAL_UNQUAL = 2; + public static final int FULLY_QUAL = 3; + public static final int UNQUAL = 4; + + private int scope; + + private IJavaElement element; + + private String handle = ""; + + /** + * Constructor + * @param scope The scope of this search + */ + public BugzillaMylarSearch(int scope, IJavaElement element) { + this.scope = scope; + this.element = element; + } + + public IStatus run(IProgressMonitor monitor) { + handle = element.getHandleIdentifier() + " " + scope; + List landmarks = new ArrayList(); + landmarks.add(element); + + if (!BugzillaMylarBridge.doesJobExist(handle)) { + + // perform the bugzilla search + // get only the useful landmarks (IMember) + List members = getMemberLandmarks(landmarks); + + // go through all of the landmarks that we are given and perform a + // search on them + for(IMember m : members){ + + // FIXME: decide whether to do leave the caching of searches in for now or not + // check if we have the info cached +// List landmarkDoi = MylarTasksPlugin.getBridge() +// .getFromLandmarksHash(m, scope); + +// if (landmarkDoi != null) { +// //TODO decide when to queue up and do a refresh search +// notifySearchCompleted(landmarkDoi); +// continue; +// } + + // create a search operation so that we can search + BugzillaMylarSearchOperation op = new BugzillaMylarSearchOperation( + this, m, scope); + + // create a new search job so that it can be scheduled and + // run as a background thread + Job searchJob = new BugzillaMylarSearchJob( + "Querying Bugzilla Server - Mylar - " + + op.getSearchMemberName(), op); + + // schedule the new search job + searchJob.schedule(); + + // save this searchJobs handle so that we can cancel it if need be + BugzillaMylarBridge.addJob(handle, searchJob); + } + } + return Status.OK_STATUS; + } + + /** List of listeners wanting to know about the searches */ + private List listeners = new ArrayList(); + + /** + * 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 doiList) { + // go through all of the listeners and call searchCompleted(colelctor, + // member) + BugzillaMylarBridge.removeSearchJob(handle); + for (IActiveSearchListener listener : listeners) { + listener.searchCompleted(doiList); + } + } + + /** + * Get only the landmarks that are IMember and sort them according to their + * DOI value (highest to lowest) + * + * @param landmarks + * The landmarks to check + * @return List of IMember landmarks sorted by DOI value + */ + public static List getMemberLandmarks(List landmarks) { + List memberLandmarks = new ArrayList(); + + for(IJavaElement je : landmarks) { + + // keep only the IMember landmarks + if (je instanceof IMember) { + memberLandmarks.add((IMember)je); + } + } + + // sort the landmarks + Collections.sort(memberLandmarks, new InterestComparator()); + + return memberLandmarks; + } + +} \ No newline at end of file diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/search/BugzillaMylarSearchJob.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/search/BugzillaMylarSearchJob.java new file mode 100644 index 000000000..b596f5536 --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/search/BugzillaMylarSearchJob.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright (c) 2004 - 2005 University Of British Columbia 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: + * University Of British Columbia - initial API and implementation + *******************************************************************************/ +/* + * Created on Oct 6, 2004 + */ +package org.eclipse.mylar.tasks.search; + +import javax.security.auth.login.LoginException; + +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.jface.dialogs.ErrorDialog; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.mylar.bugzilla.BugzillaMylarBridge; +import org.eclipse.mylar.bugzilla.core.BugzillaPlugin; +import org.eclipse.mylar.bugzilla.core.IBugzillaConstants; +import org.eclipse.ui.PlatformUI; + + +/** + * The bugzilla search job used to search a bugzilla site + * + * @author Shawn Minto + */ +public class BugzillaMylarSearchJob extends Job { + + /** The search operation used to perform the query */ + private BugzillaMylarSearchOperation operation; + + /** + * Constructor + * + * @param name + * Job name + * @param operation + * The operation to perform the search query + */ + public BugzillaMylarSearchJob(String name, + BugzillaMylarSearchOperation operation) { + super(name); + this.operation = operation; + } + + @Override + protected IStatus run(IProgressMonitor monitor) { + // create a new status + final IStatus[] status = new IStatus[1]; + + try { + // execute the search operation + operation.execute(monitor); + + // get the status of the search operation + status[0] = operation.getStatus(); + + // determine if there was an error, if it was cancelled, or if it is + // ok + if ( status[0].getCode() == IStatus.CANCEL) { + // it was cancelled, so just return + status[0] = Status.OK_STATUS; + + // make sure that we know this job is not running anymore + BugzillaMylarBridge.removeSearchJob(operation.getSearchMember().getHandleIdentifier()+" "+operation.getScope());//runningJobs.remove(operation.getSearchMember()); + return status[0]; + } else if (!status[0].isOK()) { + // there was an error, so display an error message + PlatformUI.getWorkbench().getDisplay().asyncExec( + new Runnable() { + public void run() { + ErrorDialog.openError(null, + "Bugzilla Search Error", null, + status[0]); + } + }); + status[0] = Status.OK_STATUS; + + // make sure we know that this job is not running anymore + BugzillaMylarBridge.removeSearchJob(operation.getSearchMember().getHandleIdentifier()+" "+operation.getScope());//runningJobs.remove(operation.getSearchMember()); + return status[0]; + } + } catch (LoginException e) { + // we had a problem while searching that seems like a login info + // problem + // thrown in BugzillaSearchOperation + MessageDialog + .openError( + null, + "Login Error", + "Bugzilla could not log you in to get the information you requested since login name or password is incorrect.\nPlease check your settings in the bugzilla preferences. "); + BugzillaPlugin.log(new Status(IStatus.ERROR, + IBugzillaConstants.PLUGIN_ID, IStatus.OK, "", e)); + } finally { + // make sure that we know that this job is not running anymore + BugzillaMylarBridge.removeSearchJob(operation.getSearchMember().getHandleIdentifier()+" "+operation.getScope());//.runningJobs.remove(operation.getSearchMember()); + } + + return status[0]; + } +} \ No newline at end of file diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/search/BugzillaMylarSearchOperation.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/search/BugzillaMylarSearchOperation.java new file mode 100644 index 000000000..d679c8bdd --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/search/BugzillaMylarSearchOperation.java @@ -0,0 +1,526 @@ +/******************************************************************************* + * Copyright (c) 2004 - 2005 University Of British Columbia 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: + * University Of British Columbia - initial API and implementation + *******************************************************************************/ +/* + * Created on Oct 14, 2004 + */ +package org.eclipse.mylar.tasks.search; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.security.auth.login.LoginException; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +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.mylar.bugzilla.MylarBugzillaPlugin; +import org.eclipse.mylar.bugzilla.core.BugReport; +import org.eclipse.mylar.bugzilla.core.Comment; +import org.eclipse.mylar.bugzilla.core.search.BugzillaSearchEngine; +import org.eclipse.mylar.bugzilla.core.search.BugzillaSearchHit; +import org.eclipse.mylar.bugzilla.core.search.BugzillaSearchQuery; +import org.eclipse.mylar.bugzilla.core.search.IBugzillaSearchOperation; +import org.eclipse.mylar.bugzilla.ui.search.BugzillaResultCollector; +import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaReportNode; +import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaTask; +import org.eclipse.mylar.bugzilla.ui.tasks.StackTrace; +import org.eclipse.mylar.core.MylarPlugin; +import org.eclipse.mylar.tasks.ITask; +import org.eclipse.mylar.tasks.MylarTasksPlugin; +import org.eclipse.mylar.tasks.TaskCategory; +import org.eclipse.ui.actions.WorkspaceModifyOperation; + + +/** + * Bugzilla search operation for Mylar + * + * @author Shawn Minto + */ +public class BugzillaMylarSearchOperation extends WorkspaceModifyOperation + implements IBugzillaSearchOperation { + /** The IMember we are doing the search for */ + private IMember javaElement; + + /** The bugzilla collector for the search */ + private BugzillaResultCollector collector = null; + + /** 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 String name; + + /** The bugzilla search query */ + private BugzillaSearchQuery query; + + private BugzillaMylarSearch search; + + private int scope; + + /** + * Constructor + * + * @param m + * The member that we are doing the search for + */ + public BugzillaMylarSearchOperation(BugzillaMylarSearch 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) { + + BugzillaResultCollector searchCollector = null; + + if(scope == BugzillaMylarSearch.FULLY_QUAL){ + searchCollector = searchQualified(monitor); + }else if(scope == BugzillaMylarSearch.UNQUAL){ + searchCollector = searchUnqualified(monitor); + }else if(scope == BugzillaMylarSearch.LOCAL_QUAL){ + searchCollector = searchLocalQual(monitor); + }else if(scope == BugzillaMylarSearch.LOCAL_UNQUAL){ + searchCollector = searchLocalUnQual(monitor); + }else{ + return; + } + + if(searchCollector == null){ + search.notifySearchCompleted( + new ArrayList()); + return; + } + + List l = searchCollector.getResults(); + + // get the list of doi elements + List doiList = getDoiList(l); + + // we completed the search, so notify all of the listeners + // that the search has been completed + MylarBugzillaPlugin.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 BugzillaResultCollector with the results of the search + */ + private BugzillaResultCollector searchLocalQual(IProgressMonitor monitor) { + + //get the fully qualified name for searching + String elementName = getFullyQualifiedName(javaElement); + + // setup the search result collector + collector = new BugzillaResultCollector(); + collector.setOperation(this); + collector.setProgressMonitor(monitor); + + // get all of the root tasks and start the search + List tasks = MylarTasksPlugin.getTaskListManager().getTaskList().getRootTasks(); + searchLocal(tasks, collector, elementName, monitor); + for (TaskCategory cat : MylarTasksPlugin.getTaskListManager().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 BugzillaResultCollector with the results of the search + */ + private BugzillaResultCollector searchLocalUnQual(IProgressMonitor monitor) { + + // get the element name for searching + String elementName = javaElement.getElementName(); + + // setup the search result collector + collector = new BugzillaResultCollector(); + collector.setOperation(this); + collector.setProgressMonitor(monitor); + + // get all of the root tasks and start the search + List tasks = MylarTasksPlugin.getTaskListManager().getTaskList().getRootTasks(); + searchLocal(tasks, collector, elementName, monitor); + for (TaskCategory cat : MylarTasksPlugin.getTaskListManager().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(List tasks, BugzillaResultCollector 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; + BugReport bug = bugTask.getBugReport(); + + // parse the bug report for the element that we are searching for + boolean isHit = search(elementName, bug); + + // determine if we have a hit or not + if(isHit){ + + // make a search hit from the bug and then add it to the collector + BugzillaSearchHit hit = new BugzillaSearchHit(bug.getId(), bug.getDescription(), "","","","","","","", bug.getServer()); + try{ + searchCollector.accept(hit); + }catch(CoreException e){ + MylarPlugin.log(e, "bug search failed"); + } + } + } + } + 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, BugReport bug) { + + if (bug == null) return false; // MIK: added null check here + String description = bug.getDescription(); + String summary = bug.getSummary(); + List comments = bug.getComments(); + + // search the description and the summary + if(Util.hasElementName(elementName, summary)) + return true; + + if(Util.hasElementName(elementName, description)) + return true; + + Iterator comItr = comments.iterator(); + while (comItr.hasNext()) { + Comment comment = comItr.next(); + String commentText = comment.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 BugzillaResultCollector with the search results + */ + private BugzillaResultCollector search(String url, BugzillaResultCollector 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(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) { + MylarPlugin.log("search cancelled", this); + return null; + } else if (!status.isOK()) { + MylarPlugin.log("search error", this); + MylarPlugin.log(status); + 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 BugzillaResultCollector with the search results + */ + private BugzillaResultCollector searchQualified(IProgressMonitor monitor) + { + // create a new collector for the results + collector = new BugzillaResultCollector(); + collector.setOperation(this); + collector.setProgressMonitor(monitor); + + // get the search url + String url = Util.getExactSearchURL(javaElement); + + // log the url that we are searching with + // MIK: commmented out logging +// MonitorPlugin.log(this, url); + + return search(url, collector, monitor); + } + + /** + * Perform a search for unqualified instances of the member + * @param monitor The progress monitor to use + * @return The BugzillaResultCollector with the search results + */ + private BugzillaResultCollector searchUnqualified(IProgressMonitor monitor) + { + // create a new collector for the results + collector = new BugzillaResultCollector(); + collector.setOperation(this); + collector.setProgressMonitor(monitor); + + // get the search url + String url = Util.getInexactSearchURL(javaElement); + + // log the url that we are searching with + // MIK: commmented out logging +// MonitorPlugin.log(this, url); + + return search(url, collector, monitor); + } + +// /** +// * Remove all of the duplicates +// * @param compare The List of BugzillaSearchHits to compare with +// * @param base The List of BugzillaSearchHits to remove the duplicates from +// */ +// private void removeDuplicates(List compare, List base){ +// +// for(BugzillaSearchHit h1 : compare){ +// Iterator itr2 = base.iterator(); +// while(itr2.hasNext()){ +// BugzillaSearchHit h2 = (BugzillaSearchHit)itr2.next(); +// if(h2.getId() == h1.getId()){ +// // we found a duplicate so remove it +// itr2.remove(); +// break; +// } +// } +// } +// } +// + /** + * 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 doiList) { + + // go through each of the items in the doiList + for(BugzillaReportNode info : doiList) { + + // get the bug report so that we have all of the data + // - descriptions, comments, etc + BugReport 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; + + // see if the description 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); + } + + // go through all of the comments for the bug + Iterator comItr = b.getComments().iterator(); + while (comItr.hasNext()) { + Comment comment = comItr.next(); + String commentText = comment.getText(); + + // see if the comment has a stack trace in it + stackTrace = StackTrace.getStackTrace(commentText, comment); + 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 getDoiList(List results) { + List doiList = new ArrayList(); + + boolean isExact = (scope==BugzillaMylarSearch.FULLY_QUAL || scope==BugzillaMylarSearch.LOCAL_QUAL)?true:false; + + BugzillaReportNode info = null; + // go through all of the results and create a DoiInfo list + for(BugzillaSearchHit hit : results){ + + try { + float value = 0; + info = new BugzillaReportNode( + 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 = BugzillaRepository.getInstance().getBug( +// hit.getId()); +// // add the bug to the doi info for future use +// info.setBug(b); +// } + + } catch (Exception e) { + MylarPlugin.log(e, "search failed"); + } + finally{ + doiList.add(info); + } + } + return doiList; + } + + /** + * @see org.eclipse.mylar.bugzilla.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.mylar.bugzilla.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.mylar.bugzilla.core.search.IBugzillaSearchOperation#getQuery() + */ + public BugzillaSearchQuery getQuery() { + return query; + } + + /** + * @see org.eclipse.mylar.bugzilla.core.search.IBugzillaSearchOperation#setQuery(org.eclipse.mylar.bugzilla.core.search.BugzillaSearchQuery) + */ + public void setQuery(BugzillaSearchQuery 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; + } +} \ No newline at end of file diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/search/BugzillaReferencesProvider.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/search/BugzillaReferencesProvider.java new file mode 100644 index 000000000..7212b8995 --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/search/BugzillaReferencesProvider.java @@ -0,0 +1,143 @@ +/******************************************************************************* + * Copyright (c) 2004 - 2005 University Of British Columbia 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: + * University Of British Columbia - initial API and implementation + *******************************************************************************/ +/* + * Created on Feb 2, 2005 + */ +package org.eclipse.mylar.tasks.search; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.NullProgressMonitor; +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.mylar.bugzilla.BugzillaStructureBridge; +import org.eclipse.mylar.bugzilla.MylarBugzillaPlugin; +import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaReportNode; +import org.eclipse.mylar.core.model.ITaskscapeNode; +import org.eclipse.mylar.core.search.IActiveSearchListener; +import org.eclipse.mylar.core.search.IMylarSearchOperation; +import org.eclipse.mylar.core.search.RelationshipProvider; + + +/** + * @author Shawn Minto + */ +public class BugzillaReferencesProvider extends RelationshipProvider { + + public static final String ID = "org.eclipse.mylar.bugzilla.search.references"; + public static final String NAME = "Bugilla report references"; + + public BugzillaReferencesProvider() { + super(BugzillaStructureBridge.EXTENSION, ID); + } + + protected boolean acceptElement(IJavaElement javaElement) { + return javaElement != null + && (javaElement instanceof IMember || javaElement instanceof IType); + } + + /** + * HACK: checking kind as string - don't want the dependancy to mylar.java + */ + @Override + protected void findRelated(final ITaskscapeNode node, int degreeOfSeparation) { + if (!node.getStructureKind().equals("java")) return; + IJavaElement javaElement = JavaCore.create(node.getElementHandle()); + if (!acceptElement(javaElement)) { + return; + } + runJob(node, degreeOfSeparation); + + //XXX what if degreeOfSeparation is 5? + } + + @Override + public IMylarSearchOperation getSearchOperation(ITaskscapeNode node, int limitTo, int degreeOfSepatation) { + IJavaElement javaElement = JavaCore.create(node.getElementHandle()); + return new BugzillaMylarSearch(degreeOfSepatation, javaElement); + } + + private void runJob(final ITaskscapeNode node, final int degreeOfSeparation) { + BugzillaMylarSearch search = (BugzillaMylarSearch)getSearchOperation(node, 0, degreeOfSeparation); + + search.addListener(new IActiveSearchListener(){ + + private boolean gathered = false; + + public void searchCompleted(List nodes) { + Iterator itr = nodes.iterator(); + + BugzillaStructureBridge bridge = MylarBugzillaPlugin.getDefault().getStructureBridge(); + + while(itr.hasNext()) { + Object o = itr.next(); + if(o instanceof BugzillaReportNode){ + BugzillaReportNode bugzillaNode = (BugzillaReportNode)o; + String handle = bugzillaNode.getElementHandle(); + if(bridge.getCached(handle) == null) + cache(handle, bugzillaNode); + incrementInterest(degreeOfSeparation, BugzillaStructureBridge.EXTENSION, handle); + } + } + gathered = true; + } + + public boolean resultsGathered() { + return gathered; + } + + }); + search.run(new NullProgressMonitor()); + } + + @Override + protected String getSourceId() { + return ID; + } + + @Override + public String getName() { + return NAME; + } + + /* + * + * STUFF FOR TEMPORARILY CACHING A PROXY REPORT + * + * TODO remove the proxys and update the BugzillaStructureBridge cache so that on restart, + * we dont have to get all of the bugs + * + */ + private static final Map reports = new HashMap(); + + public BugzillaReportNode getCached(String handle){ + return reports.get(handle); + } + + protected void cache(String handle, BugzillaReportNode bugzillaNode) { + reports.put(handle, bugzillaNode); + } + + public void clearCachedReports(){ + reports.clear(); + } + + public Collection getCachedHandles() { + return reports.keySet(); + } + +} diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/search/Util.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/search/Util.java new file mode 100644 index 000000000..d883e90ea --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/search/Util.java @@ -0,0 +1,195 @@ +/******************************************************************************* + * Copyright (c) 2004 - 2005 University Of British Columbia 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: + * University Of British Columbia - initial API and implementation + *******************************************************************************/ +/* + * Created on Nov 19, 2004 + */ +package org.eclipse.mylar.tasks.search; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.Charset; + +import org.eclipse.jdt.core.IMember; +import org.eclipse.jdt.core.IType; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.mylar.bugzilla.core.BugzillaPlugin; +import org.eclipse.mylar.bugzilla.core.BugzillaPreferences; +import org.eclipse.mylar.bugzilla.core.IBugzillaConstants; + + +/** + * Utilities methods for the BugzillaMylarBridge + * + * @author Shawn Minto + */ +public class Util { + + /** + * List of all of the search operations that can be done
all words, any words, regex + */ + private static final String[] patternOperationValues = { "allwordssubstr", "anywordssubstr", "regexp" }; + /** + * Sugzilla preferences so that we can get the search params + */ + private static IPreferenceStore prefs = BugzillaPlugin.getDefault().getPreferenceStore(); + /** + * List of all of the resolutions that we can have
FIXED, INVALID, WONTFIX, LATER, REMIND, DUPLICATE, WORKSFORME, MOVED, --- + */ + private static String[] resolutionValues = BugzillaPreferences.queryOptionsToArray(prefs.getString(IBugzillaConstants.RESOLUTION_VALUES)); + /** + * List of all of the statuses that we can have
UNCONFIRMED, NEW, ASSIGNED, REOPENED, RESOLVED, VERIFIED, CLOSED + */ + private static String[] statusValues = BugzillaPreferences.queryOptionsToArray(prefs.getString(IBugzillaConstants.STATUS_VALUES)); + + /** + * Get the bugzilla url used for searching for exact matches + * + * @param je + * The IMember to create the query string for + * @return A url string for the search + */ + public static String getExactSearchURL(IMember je) { + StringBuffer sb = getQueryURLStart(); + + String long_desc = ""; + + // get the fully qualified name of the element + long_desc += BugzillaMylarSearchOperation.getFullyQualifiedName(je); + + try{ + // encode the string to be used as a url + sb.append(URLEncoder.encode(long_desc, Charset.defaultCharset().toString())); + } catch (UnsupportedEncodingException e) + { + // should never get here since we are using the default encoding + } + sb.append(getQueryURLEnd()); + + return sb.toString(); + } + + /** + * Get the bugzilla url used for searching for inexact matches + * + * @param je + * The IMember to create the query string for + * @return A url string for the search + */ + public static String getInexactSearchURL(IMember je) { + StringBuffer sb = getQueryURLStart(); + + + String long_desc = ""; + + // add the member, qualified with just its parents name + if (!(je instanceof IType)) + long_desc += je.getParent().getElementName()+"."; + long_desc += je.getElementName(); + + try{ + // encode the string to be used as a url + sb.append(URLEncoder.encode(long_desc, Charset.defaultCharset().toString())); + } catch (UnsupportedEncodingException e) + { + // should never get here since we are using the default encoding + } + sb.append(getQueryURLEnd()); + + return sb.toString(); + } + + /** + * Create the end of the bugzilla query URL with all of the status' and resolutions that we want + * @return StringBuffer with the end of the query URL in it + */ + public static StringBuffer getQueryURLEnd(){ + + StringBuffer sb = new StringBuffer(); + + // add the status and resolutions that we care about + sb.append("&bug_status=" + statusValues[0]); // UNCONFIRMED + sb.append("&bug_status=" + statusValues[1]); // NEW + sb.append("&bug_status=" + statusValues[2]); // ASSIGNED + sb.append("&bug_status=" + statusValues[3]); // REOPENED + sb.append("&bug_status=" + statusValues[4]); // RESOLVED + sb.append("&bug_status=" + statusValues[5]); // VERIFIED + sb.append("&bug_status=" + statusValues[6]); // CLOSED + + sb.append("&resolution=" + resolutionValues[0]); // FIXED + sb.append("&resolution=" + resolutionValues[3]); // LATER + sb.append("&resolution=" + "---"); // --- + return sb; + } + + /** + * Create the bugzilla query URL start. + * + * @return The start of the query url as a StringBuffer
+ * Example: https://bugs.eclipse.org/bugs/buglist.cgi?long_desc_type=allwordssubstr&long_desc= + */ + public static StringBuffer getQueryURLStart() { + StringBuffer sb = new StringBuffer(BugzillaPlugin.getDefault() + .getServerName()); + + if (sb.charAt(sb.length() - 1) != '/') { + sb.append('/'); + } + sb.append("buglist.cgi?"); + + // use the username and password if we have it + if (BugzillaPreferences.getUserName() != null + && !BugzillaPreferences.getUserName().equals("") + && BugzillaPreferences.getPassword() != null + && !BugzillaPreferences.getPassword().equals("")) { + try{ + sb.append("GoAheadAndLogIn=1&Bugzilla_login=" + + URLEncoder.encode(BugzillaPreferences.getUserName(), Charset.defaultCharset().toString()) + + "&Bugzilla_password=" + + URLEncoder.encode(BugzillaPreferences.getPassword(), Charset.defaultCharset().toString()) + + "&"); + } catch (UnsupportedEncodingException e) + { + // should never get here since we are using the default encoding + } + } + + // add the description search type + sb.append("long_desc_type="); + sb.append(patternOperationValues[0]); // search for all words + sb.append("&long_desc="); + + return sb; + } + + /** + * Search the given string for another string + * @param elementName The name of the element that we are looking for + * @param comment The text to search for this element name + * @return true if the element is found in the text else false + */ + public static boolean hasElementName(String elementName, String comment) { + + // setup a regex for the element name + String regexElement = ".*"+elementName+".*"; + + // get all of the individual lines for the string + String[] lines = comment.split("\n"); + + // go through each of the lines of the string + for (int i = 0; i < lines.length; i++) { + + if (lines[i].matches(regexElement)){ + return true; + } + } + return false; + } +} \ No newline at end of file -- cgit v1.2.3