Bug 540132 - ResourceException when updating breakpoint messages

Breakpoint messages are updated on breakpoint notifications. Those
usually are triggered in a job. Its therefore possible that the
respective project was deleted before such a job manages to update
breakpoint messages. In this case, a ResourceException is thrown.

With this change, a job is scheduled to update breakpoint messages. The
job will use a workspace modification lock and check whether markers
still exist, before updating their messages. This prevents the
ResourceException.

Change-Id: Ie57731dbca587bbe8c2b0afa8b77fe1507ef8e70
Signed-off-by: Simeon Andreev <simeon.danailov.andreev@gmail.com>
Signed-off-by: Andrey Loskutov <loskutov@gmx.de>
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugOptionsManager.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugOptionsManager.java
index f95a836..d0f9167 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugOptionsManager.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugOptionsManager.java
@@ -24,14 +24,19 @@
 import org.eclipse.core.resources.IMarker;

 import org.eclipse.core.resources.IMarkerDelta;

 import org.eclipse.core.resources.IResource;

+import org.eclipse.core.resources.IResourceRuleFactory;

+import org.eclipse.core.resources.IWorkspace;

+import org.eclipse.core.resources.IWorkspaceRoot;

 import org.eclipse.core.resources.IWorkspaceRunnable;

 import org.eclipse.core.resources.ResourcesPlugin;

 import org.eclipse.core.runtime.CoreException;

 import org.eclipse.core.runtime.IAdaptable;

+import org.eclipse.core.runtime.ICoreRunnable;

 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.core.runtime.jobs.ISchedulingRule;

 import org.eclipse.core.runtime.jobs.Job;

 import org.eclipse.debug.core.DebugEvent;

 import org.eclipse.debug.core.DebugException;

@@ -213,6 +218,7 @@
 	 * Called at shutdown by the Java debug ui plug-in

 	 */

 	public void shutdown() {

+		Job.getJobManager().cancel(JavaDebugOptionsManager.class);

 		DebugPlugin debugPlugin = DebugPlugin.getDefault();

 		debugPlugin.removeDebugEventListener(this);

 		debugPlugin.getLaunchManager().removeLaunchListener(this);

@@ -756,15 +762,67 @@
 						} else if (breakpoint instanceof IJavaLineBreakpoint) {

 							type = DebugUIMessages.JavaDebugOptionsManager_Line_breakpoint___4;

 						}

-						breakpoint.getMarker().setAttribute(IMarker.MESSAGE, type + info);

+						IMarker marker = breakpoint.getMarker();

+						if (marker.exists()) {

+							marker.setAttribute(IMarker.MESSAGE, type + info);

+						}

 					}

 				}

 			}

 		};

-		try {

-			ResourcesPlugin.getWorkspace().run(runnable, null, 0, null);

-		} catch (CoreException e) {

-			JDIDebugUIPlugin.log(e);

+

+		final ISchedulingRule modifyWorkspaceRule = modifyWorkspaceRule();

+

+		ISchedulingRule currentRule = Job.getJobManager().currentRule();

+		if (currentRule != null && currentRule.contains(modifyWorkspaceRule)) {

+			try {

+				ResourcesPlugin.getWorkspace().run(runnable, null, 0, null);

+			} catch (CoreException e) {

+				JDIDebugUIPlugin.log(e);

+			}

+		} else {

+			UpdateBreakpointMessagesJob updateBreakpointMessagesJob = new UpdateBreakpointMessagesJob(modifyWorkspaceRule, runnable);

+			updateBreakpointMessagesJob.schedule();

+		}

+	}

+

+	private static ISchedulingRule modifyWorkspaceRule() {

+		IWorkspace workspace = ResourcesPlugin.getWorkspace();

+		IWorkspaceRoot workspaceRoot = workspace.getRoot();

+		IResourceRuleFactory rootFactory = workspace.getRuleFactory();

+		ISchedulingRule modifyWorkspaceRule = rootFactory.modifyRule(workspaceRoot);

+		return modifyWorkspaceRule;

+	}

+

+	private static class UpdateBreakpointMessagesJob extends Job {

+

+		private ISchedulingRule rule;

+		private ICoreRunnable runnable;

+

+		UpdateBreakpointMessagesJob(ISchedulingRule rule, ICoreRunnable runnable) {

+			super("Updating breakpoint messages"); //$NON-NLS-1$

+			this.rule = rule;

+			this.runnable = runnable;

+		}

+

+		@Override

+		protected IStatus run(IProgressMonitor monitor) {

+			if (monitor.isCanceled()) {

+				return Status.CANCEL_STATUS;

+			}

+			try {

+				ResourcesPlugin.getWorkspace().run(runnable, rule, 0, monitor);

+			} catch (CoreException e) {

+				String errorMessage = "Failed to update breakpoint messages"; //$NON-NLS-1$

+				IStatus errorStatus = new Status(IStatus.ERROR, IJavaDebugUIConstants.PLUGIN_ID, errorMessage, e);

+				return errorStatus;

+			}

+			return Status.OK_STATUS;

+		}

+

+		@Override

+		public boolean belongsTo(Object family) {

+			return JavaDebugOptionsManager.class == family;

 		}

 	}