Bug 375664 - [3.3.2P][crossfire] Disabling a breakpoint in Eclipse removes it from Firebug rather then disabling it
diff --git a/bundles/org.eclipse.wst.jsdt.debug.core/META-INF/MANIFEST.MF b/bundles/org.eclipse.wst.jsdt.debug.core/META-INF/MANIFEST.MF
index e9c6d52..c99d592 100644
--- a/bundles/org.eclipse.wst.jsdt.debug.core/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.wst.jsdt.debug.core/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %bundleName.name
 Bundle-SymbolicName: org.eclipse.wst.jsdt.debug.core;singleton:=true
-Bundle-Version: 2.0.101.qualifier
+Bundle-Version: 3.0.0.qualifier
 Bundle-Activator: org.eclipse.wst.jsdt.debug.internal.core.JavaScriptDebugPlugin
 Bundle-Vendor: %providerName
 Require-Bundle: org.eclipse.core.runtime,
@@ -15,10 +15,10 @@
  org.eclipse.wst.jsdt.debug.core.jsdi.event,
  org.eclipse.wst.jsdt.debug.core.jsdi.request,
  org.eclipse.wst.jsdt.debug.core.model,
- org.eclipse.wst.jsdt.debug.internal.core;x-friends:="org.eclipse.wst.jsdt.debug.ui",
- org.eclipse.wst.jsdt.debug.internal.core.breakpoints;x-friends:="org.eclipse.wst.jsdt.debug.ui",
+ org.eclipse.wst.jsdt.debug.internal.core;x-friends:="org.eclipse.wst.jsdt.debug.ui,org.eclipse.wst.jsdt.debug.crossfire",
+ org.eclipse.wst.jsdt.debug.internal.core.breakpoints;x-friends:="org.eclipse.wst.jsdt.debug.ui,org.eclipse.wst.jsdt.debug.crossfire",
  org.eclipse.wst.jsdt.debug.internal.core.launching;x-friends:="org.eclipse.wst.jsdt.debug.ui,org.eclipse.wst.jsdt.debug.rhino.ui",
- org.eclipse.wst.jsdt.debug.internal.core.model;x-friends:="org.eclipse.wst.jsdt.debug.ui,org.eclipse.wst.jsdt.debug.rhino.ui"
+ org.eclipse.wst.jsdt.debug.internal.core.model;x-friends:="org.eclipse.wst.jsdt.debug.ui,org.eclipse.wst.jsdt.debug.rhino.ui,org.eclipse.wst.jsdt.debug.crossfire"
 Import-Package: org.eclipse.jface.text,
  org.eclipse.text.edits,
  org.eclipse.wst.jsdt.core,
diff --git a/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/core/jsdi/VirtualMachine.java b/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/core/jsdi/VirtualMachine.java
index 6842c3c..213c1eb 100644
--- a/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/core/jsdi/VirtualMachine.java
+++ b/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/core/jsdi/VirtualMachine.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010 IBM Corporation and others.
+ * Copyright (c) 2010, 2012 IBM Corporation 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
@@ -12,6 +12,7 @@
 
 import java.util.List;
 
+import org.eclipse.wst.jsdt.debug.core.breakpoints.IJavaScriptBreakpoint;
 import org.eclipse.wst.jsdt.debug.core.jsdi.event.EventQueue;
 import org.eclipse.wst.jsdt.debug.core.jsdi.request.EventRequestManager;
 
@@ -153,4 +154,19 @@
 	 * @return the {@link EventQueue} for this {@link VirtualMachine} or <code>null</code>
 	 */
 	public EventQueue eventQueue();
+	
+	/**
+	 * Returns if the {@link VirtualMachine} supports updating existing breakpoints or not
+	 * 
+	 * @return <code>true</code> if this {@link VirtualMachine} can update existing breakpoints <code>false</code> otherwise
+	 * @since 3.4
+	 */
+	public boolean canUpdateBreakpoints();
+	
+	/**
+	 * Update the given {@link IJavaScriptBreakpoint}
+	 * 
+	 * @param breakpoint the breakpoint to update, cannot be <code>null</code>
+	 */
+	public void updateBreakpoint(IJavaScriptBreakpoint breakpoint);
 }
diff --git a/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/internal/core/breakpoints/JavaScriptBreakpoint.java b/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/internal/core/breakpoints/JavaScriptBreakpoint.java
index c9b3fb9..5d9d6a1 100644
--- a/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/internal/core/breakpoints/JavaScriptBreakpoint.java
+++ b/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/internal/core/breakpoints/JavaScriptBreakpoint.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2011 IBM Corporation and others.
+ * Copyright (c) 2010, 2012 IBM Corporation 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
@@ -230,17 +230,26 @@
 	}
 
 	/**
-	 * Recreate this breakpoint in all targets
+	 * Handles the fact that the breakpoint has had its attributes changed.
+	 * This method checks to see if the backing {@link JavaScriptDebugTarget} can
+	 * update breakpoints, and if so issues an update request, otherwise
+	 * the breakpoint is deleted and recreated in affected debug targets
 	 * 
 	 * @throws CoreException
 	 */
-	protected void recreateBreakpoint() throws CoreException {
+	protected void handleBreakpointChange() throws CoreException {
 		DebugPlugin plugin = DebugPlugin.getDefault();
 		if (plugin != null) {
 			IDebugTarget[] targets = plugin.getLaunchManager().getDebugTargets();
 			for (int i = 0; i < targets.length; i++) {
 				if (targets[i].getModelIdentifier().equals(JavaScriptDebugModel.MODEL_ID)) {
-					recreateBreakpointFor((JavaScriptDebugTarget) targets[i]);
+					JavaScriptDebugTarget target = (JavaScriptDebugTarget) targets[i];
+					if(target.canUpdateBreakpoints()) {
+						target.updateBreakpoint(this);
+					}
+					else {
+						recreateBreakpointFor((JavaScriptDebugTarget) targets[i]);
+					}
 				}
 			}
 		}
@@ -267,7 +276,7 @@
 	public void setEnabled(boolean enabled) throws CoreException {
 		if(isEnabled() != enabled) {
 			setAttribute(ENABLED, enabled);
-			recreateBreakpoint();
+			handleBreakpointChange();
 		}
 	}
 	
@@ -277,7 +286,7 @@
 	public void setSuspendPolicy(int policy) throws CoreException {
 		if(getSuspendPolicy() != policy) {
 			setAttribute(SUSPEND_POLICY, policy);
-			recreateBreakpoint();
+			handleBreakpointChange();
 		}
 	}
 
@@ -329,7 +338,7 @@
 	public void setHitCount(int count) throws CoreException, IllegalArgumentException {
 		if (count != getHitCount()) {
 			setAttribute(HIT_COUNT, count);
-			recreateBreakpoint();
+			handleBreakpointChange();
 		}
 	}
 
diff --git a/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/internal/core/breakpoints/JavaScriptFunctionBreakpoint.java b/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/internal/core/breakpoints/JavaScriptFunctionBreakpoint.java
index 23dd164..e173002 100644
--- a/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/internal/core/breakpoints/JavaScriptFunctionBreakpoint.java
+++ b/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/internal/core/breakpoints/JavaScriptFunctionBreakpoint.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010 IBM Corporation and others.
+ * Copyright (c) 2010, 2012 IBM Corporation 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
@@ -141,7 +141,7 @@
 			else {
 				setAttribute(ENTRY, isentry);
 			}	
-			recreateBreakpoint();
+			handleBreakpointChange();
 		}
 	}
 
diff --git a/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/internal/core/breakpoints/JavaScriptLineBreakpoint.java b/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/internal/core/breakpoints/JavaScriptLineBreakpoint.java
index c795a60..d8e53cf 100644
--- a/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/internal/core/breakpoints/JavaScriptLineBreakpoint.java
+++ b/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/internal/core/breakpoints/JavaScriptLineBreakpoint.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2011 IBM Corporation and others.
+ * Copyright (c) 2010, 2012 IBM Corporation 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
@@ -152,7 +152,7 @@
 	public void setConditionSuspendOnTrue(boolean suspendontrue) throws CoreException {
 		if (suspendontrue != isConditionSuspendOnTrue()) {
 			setAttribute(CONDITION_SUSPEND_ON_TRUE, suspendontrue);
-			recreateBreakpoint();
+			handleBreakpointChange();
 		}
 	}
 	
@@ -166,7 +166,7 @@
 		else {
 			setAttribute(CONDITION, condition);
 		}
-		recreateBreakpoint();
+		handleBreakpointChange();
 	}
 
 	/* (non-Javadoc)
@@ -182,7 +182,7 @@
 	public void setConditionEnabled(boolean enabled) throws CoreException {
 		if(isConditionEnabled() != enabled) {
 			setAttribute(CONDITION_ENABLED, enabled);
-			recreateBreakpoint();
+			handleBreakpointChange();
 		}
 	}
 }
diff --git a/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/internal/core/model/JavaScriptDebugTarget.java b/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/internal/core/model/JavaScriptDebugTarget.java
index 618fc2d..506b0a3 100644
--- a/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/internal/core/model/JavaScriptDebugTarget.java
+++ b/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/internal/core/model/JavaScriptDebugTarget.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2011 IBM Corporation and others.
+ * Copyright (c) 2010, 2012 IBM Corporation 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
@@ -1027,4 +1027,24 @@
 			fireTerminateEvent();
 		}
 	}
+	
+	/**
+	 * @return if the backing {@link VirtualMachine} can update breakpoints
+	 */
+	public boolean canUpdateBreakpoints() {
+		return this.vm.canUpdateBreakpoints();
+	}
+	
+	/**
+	 * Update the given breakpoint
+	 * 
+	 * @param breakpoint
+	 */
+	public void updateBreakpoint(IJavaScriptBreakpoint breakpoint) {
+		if(this.breakpoints.contains(breakpoint)) {
+			if(this.vm.canUpdateBreakpoints()) {
+				this.vm.updateBreakpoint(breakpoint);
+			}
+		}
+	}
 }
diff --git a/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/internal/core/model/ScriptResolutionManager.java b/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/internal/core/model/ScriptResolutionManager.java
index 2c54448..90266c7 100644
--- a/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/internal/core/model/ScriptResolutionManager.java
+++ b/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/internal/core/model/ScriptResolutionManager.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011 IBM Corporation and others.
+ * Copyright (c) 2011, 2012 IBM Corporation 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
@@ -16,6 +16,7 @@
 import java.util.List;
 
 import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IWorkspaceRoot;
 import org.eclipse.core.resources.ResourcesPlugin;
@@ -142,7 +143,11 @@
 		}
 		file = null;
 		IPath p = SourceLookup.getSourcePath(script.sourceURI());
-		IResource res = ResourcesPlugin.getWorkspace().getRoot().findMember(p);
+		IResource res = ResourcesPlugin.getWorkspace().getRoot().findMember(p.makeAbsolute());
+		if(res == null) {
+			IProject pj = JavaScriptDebugPlugin.getExternalSourceProject(true);
+			res = pj.findMember(p);
+		}
 		if(res != null && res.getType() == IResource.FILE) {
 			file = (IFile) res;
 		}
diff --git a/bundles/org.eclipse.wst.jsdt.debug.crossfire/META-INF/MANIFEST.MF b/bundles/org.eclipse.wst.jsdt.debug.crossfire/META-INF/MANIFEST.MF
index 0e52c32..c961e19 100644
--- a/bundles/org.eclipse.wst.jsdt.debug.crossfire/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.wst.jsdt.debug.crossfire/META-INF/MANIFEST.MF
@@ -6,7 +6,7 @@
 Bundle-Activator: org.eclipse.wst.jsdt.debug.internal.crossfire.CrossFirePlugin
 Bundle-Vendor: %Bundle-Vendor
 Require-Bundle: org.eclipse.core.runtime,
- org.eclipse.wst.jsdt.debug.core;bundle-version="1.0.0",
+ org.eclipse.wst.jsdt.debug.core;bundle-version="3.0.0",
  org.eclipse.wst.jsdt.debug.transport;bundle-version="1.0.0",
  org.eclipse.wst.jsdt.core;bundle-version="1.1.100",
  org.eclipse.debug.core
diff --git a/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/jsdi/BreakpointTracker.java b/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/jsdi/BreakpointTracker.java
new file mode 100644
index 0000000..5036d1e
--- /dev/null
+++ b/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/jsdi/BreakpointTracker.java
@@ -0,0 +1,401 @@
+/*******************************************************************************
+ * Copyright (c) 2012 IBM Corporation 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:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.jsdt.debug.internal.crossfire.jsdi;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.wst.jsdt.debug.core.breakpoints.IJavaScriptBreakpoint;
+import org.eclipse.wst.jsdt.debug.core.breakpoints.IJavaScriptLineBreakpoint;
+import org.eclipse.wst.jsdt.debug.core.jsdi.ScriptReference;
+import org.eclipse.wst.jsdt.debug.core.model.JavaScriptDebugModel;
+import org.eclipse.wst.jsdt.debug.internal.core.JavaScriptDebugPlugin;
+import org.eclipse.wst.jsdt.debug.internal.core.breakpoints.JavaScriptLineBreakpoint;
+import org.eclipse.wst.jsdt.debug.internal.crossfire.transport.Attributes;
+
+/**
+ * Utility class to handle tracking remote to local breakpoints
+ * 
+ * @since 3.4
+ */
+public final class BreakpointTracker {
+
+	/**
+	 * Mapping of breakpoint handles to {@link RemoteBreakpoint}: <code>Map&lt;Number, RemoteBreakpoint&gt;</code>
+	 */
+	private static Map/*<Number, RemoteBreakpoint>*/ breakpointHandles = new HashMap();
+	/**
+	 * Mapping of breakpoint handles to local {@link IJavaScriptBreakpoint}s: <code>Map&lt;Number, IJavaScriptBreakpoint&gt;</code>
+	 */
+	private static Map/*<Number, IJavaScriptBreakpoint>*/ handleToLocal = new HashMap();
+	/**
+	 * Mapping of {@link CFVirtualMachine} to {@link HashSet} of breakpoint handles: <code>Map&lt;CFVirtualMachine, HashSet&lt;Number&gt;&gt;</code>
+	 */
+	private static Map/*<CFVirtualMachine, HashSet>*/vmToHandles = new HashMap();
+	
+	/**
+	 * Add the breakpoint described by the given JSON to the handles list
+	 * 
+	 * @param vm the {@link CFVirtualMachine}, cannot be <code>null</code>
+	 * @param json the JSON map object, cannot be <code>null</code>
+	 * @return the newly added {@link RemoteBreakpoint} or <code>null</code> if one could not be created and added
+	 */
+	public static RemoteBreakpoint addBreakpoint(CFVirtualMachine vm, Map json) {
+		Assert.isNotNull(vm, Messages.BreakpointTracker_2);
+		Assert.isNotNull(json, Messages.BreakpointTracker_3);
+		Number handle = (Number) json.get(Attributes.HANDLE);
+		if(handle != null) {
+			RemoteBreakpoint bp = (RemoteBreakpoint) breakpointHandles.get(handle);
+			if(bp == null) {
+				bp = new RemoteBreakpoint(vm, 
+					handle,
+					(Map) json.get(Attributes.LOCATION),
+					(Map) json.get(Attributes.ATTRIBUTES),
+					(String)json.get(Attributes.TYPE));
+				breakpointHandles.put(handle, bp);
+				
+			}
+			HashSet handles = (HashSet) vmToHandles.get(handle);
+			if(handles == null) {
+				handles = new HashSet();
+				vmToHandles.put(vm, handles);
+			}
+			handles.add(handle);
+			return bp;
+		}
+		return null;
+	}
+	
+	/**
+	 * Create a local version of the breakpoint if one does not exist
+	 * 
+	 * @param vm the {@link CFVirtualMachine}, cannot be <code>null</code>
+	 * @param json the JSON map describing the breakpoint, cannot be <code>null</code>
+	 * @return the new {@link IJavaScriptBreakpoint} or <code>null</code> if it could not be created
+	 */
+	public static IJavaScriptBreakpoint createLocalBreakpoint(CFVirtualMachine vm, Map json) {
+		Assert.isNotNull(vm, Messages.BreakpointTracker_5);
+		Assert.isNotNull(json, Messages.BreakpointTracker_6);
+		RemoteBreakpoint rb = addBreakpoint(vm, json);
+		if(rb != null && rb.isLineBreakpoint()) {
+			IJavaScriptBreakpoint bp = findLocalBreakpoint(rb);
+			if(bp != null) {
+				return bp;
+			}
+			ScriptReference script = rb.vm.findScript(rb.getUrl());
+			if(script != null) {
+				IFile file = JavaScriptDebugPlugin.getResolutionManager().getFile(script);
+				if(file != null) {
+					HashMap attributes = new HashMap();
+					attributes.put(IJavaScriptBreakpoint.TYPE_NAME, null);
+					attributes.put(IJavaScriptBreakpoint.SCRIPT_PATH, file.getFullPath().makeAbsolute().toString());
+					attributes.put(IJavaScriptBreakpoint.ELEMENT_HANDLE, null);
+					String condition = rb.getCondition();
+					if(condition != null && condition.trim().length() > 0) {
+						attributes.put(JavaScriptLineBreakpoint.CONDITION, condition);
+						attributes.put(JavaScriptLineBreakpoint.CONDITION_ENABLED, Boolean.TRUE);
+						attributes.put(JavaScriptLineBreakpoint.CONDITION_SUSPEND_ON_TRUE, Boolean.TRUE);
+					}
+					try {
+						bp = JavaScriptDebugModel.createLineBreakpoint(file, rb.getLine(), -1, -1, attributes, true);
+						handleToLocal.put(rb.getHandle(), bp);
+						return bp;
+					}
+					catch(DebugException de) {}
+				}
+			}
+		}
+		return null;
+	}
+	
+	/**
+	 * Finds the local equivalent {@link IJavaScriptBreakpoint} given the {@link RemoteBreakpoint}
+	 * 
+	 * @param breakpoint the {@link RemoteBreakpoint}, cannot be <code>null</code>
+	 * @return the local equivalent of the given {@link RemoteBreakpoint} or <code>null</code> if one does not exist
+	 */
+	public static final IJavaScriptBreakpoint findLocalBreakpoint(RemoteBreakpoint breakpoint) {
+		Assert.isNotNull(breakpoint, Messages.BreakpointTracker_7);
+		IJavaScriptBreakpoint bp = getLocalBreakpoint(breakpoint.getHandle());
+		if(bp != null) {
+			return bp;
+		}
+		//else try to find it and map it
+		ScriptReference script = breakpoint.vm.findScript(breakpoint.getUrl());
+		if(script != null) {
+			IFile file = JavaScriptDebugPlugin.getResolutionManager().getFile(script);
+			if(file != null) {
+				IBreakpoint[] bps = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(JavaScriptDebugModel.MODEL_ID);
+				for (int i = 0; i < bps.length; i++) {
+					if(bps[i] instanceof IJavaScriptLineBreakpoint) {
+						IJavaScriptLineBreakpoint jsbp = (IJavaScriptLineBreakpoint) bps[i];
+						try {
+							String scriptpath = jsbp.getScriptPath();
+							if(file.getFullPath().isPrefixOf(new Path(scriptpath)) &&
+									breakpoint.getLine() == jsbp.getLineNumber()) {
+								//potential match, now check the location, for now simply check the line number
+								//map it
+								handleToLocal.put(breakpoint.getHandle(), jsbp);
+								return jsbp;
+							}
+						}
+						catch(CoreException ce) {}
+					}
+					else {
+						IJavaScriptBreakpoint jsbp = (IJavaScriptBreakpoint) bps[i];
+						try {
+							String scriptpath = jsbp.getScriptPath();
+							//script load / exception breakpoints have no further location than the script
+							if(file.getFullPath().isPrefixOf(new Path(scriptpath))) {
+								//map it
+								handleToLocal.put(breakpoint.getHandle(), jsbp);
+								return jsbp;
+							}
+						}
+						catch(CoreException ce) {}
+					}
+					
+				}
+			}
+		}
+		return null;
+	}
+	
+	/**
+	 * Look up the {@link RemoteBreakpoint} with the given {@link IJavaScriptBreakpoint}
+	 * 
+	 * @param breakpoint the local {@link IJavaScriptBreakpoint}, cannot be <code>null</code>
+	 * @return the {@link RemoteBreakpoint} that matches the local {@link IJavaScriptBreakpoint} or <code>null</code>
+	 * if not match is found
+	 */
+	public static RemoteBreakpoint findRemoteBreakpoint(IJavaScriptBreakpoint breakpoint) {
+		Assert.isNotNull(breakpoint, Messages.BreakpointTracker_12);
+		for (Iterator i = handleToLocal.entrySet().iterator(); i.hasNext();) {
+			Entry entry = (Entry) i.next();
+			if(breakpoint.equals(entry.getValue())) {
+				Number handle = (Number) entry.getKey();
+				return getBreakpoint(handle);
+			}
+		}
+		//failed to find it in the cache, try to find it by location
+		for (Iterator i = breakpointHandles.entrySet().iterator(); i.hasNext();) {
+			Entry entry = (Entry) i.next();
+			try {
+				RemoteBreakpoint rb = (RemoteBreakpoint) entry.getValue();
+				ScriptReference script = rb.vm.findScript(rb.getUrl());
+				if(script != null) {
+					IFile file = JavaScriptDebugPlugin.getResolutionManager().getFile(script);
+					if(file != null) {
+						if(breakpoint instanceof IJavaScriptLineBreakpoint) {
+							IJavaScriptLineBreakpoint lb = (IJavaScriptLineBreakpoint) breakpoint;
+							String scriptpath = breakpoint.getScriptPath();
+							if(file.getFullPath().isPrefixOf(new Path(scriptpath)) &&
+									rb.getLine() == lb.getLineNumber()) {
+								handleToLocal.put(rb.handle, breakpoint);
+								return rb;
+							}
+						}
+						else {
+							String scriptpath = breakpoint.getScriptPath();
+							//script load / exception breakpoints have no further location than the script
+							if(file.getFullPath().isPrefixOf(new Path(scriptpath))) {
+								//map it
+								handleToLocal.put(rb.getHandle(), breakpoint);
+								return rb;
+							}
+						}
+					}
+						
+				}
+			}
+			catch(CoreException ce) {}
+		}
+		return null;
+	}
+	
+	/**
+	 * This method synchronizes the enabled and condition attributes from the given {@link IJavaScriptBreakpoint} onto the given
+	 * {@link RemoteBreakpoint}.
+	 * 
+	 * @param rbreakpoint the {@link RemoteBreakpoint}, cannot be <code>null</code>
+	 * @param breakpoint the local {@link IJavaScriptBreakpoint}, cannot be <code>null</code>
+	 * @throws CoreException if we failed to read properties from the {@link IJavaScriptBreakpoint}
+	 */
+	public static final void syncRemoteBreakpoint(RemoteBreakpoint rbreakpoint, IJavaScriptBreakpoint breakpoint) throws CoreException {
+		Assert.isNotNull(rbreakpoint, Messages.BreakpointTracker_13);
+		Assert.isNotNull(breakpoint, Messages.BreakpointTracker_14);
+		rbreakpoint.setEnabled(breakpoint.isEnabled());
+		if(breakpoint instanceof IJavaScriptLineBreakpoint) {
+			IJavaScriptLineBreakpoint lb = (IJavaScriptLineBreakpoint) breakpoint;
+			if(lb.isConditionEnabled()) {
+				rbreakpoint.setCondition(lb.getCondition());
+			}
+			else {
+				rbreakpoint.setCondition(null);
+			}
+		}
+	}
+	
+	/**
+	 * Returns the {@link RemoteBreakpoint} with the given handle
+	 * 
+	 * @param handle the handle, cannot be <code>null</code>
+	 * @return the {@link RemoteBreakpoint} with the given handle or <code>null</code>
+	 */
+	public static final RemoteBreakpoint getBreakpoint(Number handle) {
+		Assert.isNotNull(handle, Messages.BreakpointTracker_0);
+		return (RemoteBreakpoint) breakpointHandles.get(handle);
+	}
+	
+	/**
+	 * Returns the {@link IJavaScriptBreakpoint} mapped to the given {@link RemoteBreakpoint} handle
+	 * 
+	 * @param handle the handle, cannot be <code>null</code>
+	 * @return the mapped {@link IJavaScriptBreakpoint} or <code>null</code>
+	 */
+	public static final IJavaScriptBreakpoint getLocalBreakpoint(Number handle) {
+		Assert.isNotNull(handle, Messages.BreakpointTracker_10);
+		return (IJavaScriptBreakpoint) handleToLocal.get(handle);
+	}
+	
+	/**
+	 * Removes the {@link RemoteBreakpoint} with the given handle
+	 * 
+	 * @param vm the {@link CFVirtualMachine} that processed the request
+	 * @param handle the breakpoint handle, cannot be <code>null</code>
+	 * @return the {@link RemoteBreakpoint} that was removed or <code>null</code>
+	 */
+	public static RemoteBreakpoint removeBreakpoint(CFVirtualMachine vm, Number handle) {
+		Assert.isNotNull(handle, Messages.BreakpointTracker_1);
+		RemoteBreakpoint rb = (RemoteBreakpoint) breakpointHandles.remove(handle);
+		if(rb != null) {
+			HashSet handles = (HashSet) vmToHandles.get(vm);
+			if(handles != null) {
+				handles.remove(handle);
+			}
+			handleToLocal.remove(handle);
+		}
+		return rb;
+	}
+	
+	/**
+	 * Removes the local breakpoint given its remote equivalent
+	 * @param vm the {@link CFVirtualMachine} that processed the removal request
+	 * @param handle the remote breakpoint, cannot be <code>null</code>
+	 */
+	public static void removeLocalBreakpoint(CFVirtualMachine vm, Number handle) {
+		Assert.isNotNull(handle, Messages.BreakpointTracker_9);
+		RemoteBreakpoint rb = removeBreakpoint(vm, handle);
+		if(rb != null) {
+			IJavaScriptBreakpoint jsbp = findLocalBreakpoint(rb);
+			if(jsbp != null) {
+				try {
+					jsbp.delete();
+				} catch (CoreException e) {
+				}
+			}
+		}
+	}
+	
+	/**
+	 * Locates the breakpoint for the handle given in the map and updates its attributes
+	 * 
+	 * @param json the JSON map, cannot be <code>null</code>
+	 * @return the {@link RemoteBreakpoint} that was updated or <code>null</code> if nothing was updated
+	 */
+	public static RemoteBreakpoint updateBreakpoint(Map json) {
+		Assert.isNotNull(json, Messages.BreakpointTracker_4);
+		Number handle = (Number) json.get(Attributes.HANDLE);
+		if(handle != null) {
+			RemoteBreakpoint bp = (RemoteBreakpoint) breakpointHandles.get(handle);
+			if(bp != null) {
+				bp.setEnabled(RemoteBreakpoint.getEnabled(json));
+				bp.setCondition(RemoteBreakpoint.getCondition(json));
+				updateLocalBreakpoint(bp);
+			}
+			return bp;
+		}
+		return null;
+	}
+	
+	/**
+	 * Tries to locate and update the local version of the given {@link RemoteBreakpoint}
+	 * @param rb the {@link RemoteBreakpoint}, cannot be <code>null</code>
+	 * @return the {@link IJavaScriptBreakpoint} that was updated or <code>null</code> if no update occurred
+	 */
+	public static IJavaScriptBreakpoint updateLocalBreakpoint(RemoteBreakpoint rb) {
+		Assert.isNotNull(rb, Messages.BreakpointTracker_8);
+		IJavaScriptBreakpoint bp = getLocalBreakpoint(rb.getHandle());
+		if(bp instanceof IJavaScriptLineBreakpoint) {
+			try {
+				Map attributes = bp.getMarker().getAttributes();
+				boolean edited = false;
+				if(bp.isEnabled() != rb.isEnabled()) {
+					attributes.put(IBreakpoint.ENABLED, Boolean.valueOf(rb.isEnabled()));
+					edited = true;
+				}
+				String condition = ((IJavaScriptLineBreakpoint) bp).getCondition();
+				String rbcondition = rb.getCondition();
+				if(rbcondition != null) {
+					if(!rbcondition.equals(condition)) {
+						attributes.put(JavaScriptLineBreakpoint.CONDITION, rbcondition);
+						attributes.put(JavaScriptLineBreakpoint.CONDITION_ENABLED, Boolean.TRUE);
+						attributes.put(JavaScriptLineBreakpoint.CONDITION_SUSPEND_ON_TRUE, Boolean.TRUE);
+						edited = true;
+					}
+				}
+				else if(condition != null) {
+					attributes.remove(JavaScriptLineBreakpoint.CONDITION);
+					attributes.remove(JavaScriptLineBreakpoint.CONDITION_ENABLED);
+					attributes.remove(JavaScriptLineBreakpoint.CONDITION_SUSPEND_ON_TRUE);
+					edited = true;
+				}
+				if(edited) {
+					bp.getMarker().setAttributes(attributes);
+				}
+			}
+			catch(CoreException ce) {
+				ce.printStackTrace();
+			}
+			return bp;
+		}
+		return null;
+	}
+	
+	/**
+	 * Disconnects and un-caches all of the breakpoints - both local and remote - that were being tracked
+	 * on behalf of the given {@link CFVirtualMachine}
+	 * 
+	 * @param vm the {@link CFVirtualMachine}, cannot be <code>null</code>
+	 */
+	public static void disconnect(CFVirtualMachine vm) {
+		Assert.isNotNull(vm, Messages.BreakpointTracker_11);
+		HashSet handles = (HashSet) vmToHandles.get(vm);
+		if(handles != null) {
+			for (Iterator i = handles.iterator(); i.hasNext();) {
+				Number handle = (Number) i.next();
+				handleToLocal.remove(handle);
+				breakpointHandles.remove(handle);
+			}
+			vmToHandles.remove(vm);
+		}
+	}
+}
diff --git a/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/jsdi/CFVirtualMachine.java b/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/jsdi/CFVirtualMachine.java
index 311ce61..816c99a 100644
--- a/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/jsdi/CFVirtualMachine.java
+++ b/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/jsdi/CFVirtualMachine.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2011 IBM Corporation and others.
+ * Copyright (c) 2010, 2012 IBM Corporation 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
@@ -20,20 +20,19 @@
 import java.util.Map.Entry;
 import java.util.Vector;
 
-import org.eclipse.core.resources.IMarkerDelta;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.QualifiedName;
 import org.eclipse.debug.core.DebugPlugin;
-import org.eclipse.debug.core.IBreakpointListener;
 import org.eclipse.debug.core.IBreakpointManager;
 import org.eclipse.debug.core.model.IBreakpoint;
 import org.eclipse.wst.jsdt.core.JavaScriptCore;
-import org.eclipse.wst.jsdt.debug.core.breakpoints.IJavaScriptLineBreakpoint;
+import org.eclipse.wst.jsdt.debug.core.breakpoints.IJavaScriptBreakpoint;
 import org.eclipse.wst.jsdt.debug.core.jsdi.BooleanValue;
 import org.eclipse.wst.jsdt.debug.core.jsdi.NullValue;
 import org.eclipse.wst.jsdt.debug.core.jsdi.NumberValue;
+import org.eclipse.wst.jsdt.debug.core.jsdi.ScriptReference;
 import org.eclipse.wst.jsdt.debug.core.jsdi.StringValue;
 import org.eclipse.wst.jsdt.debug.core.jsdi.UndefinedValue;
 import org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine;
@@ -61,7 +60,7 @@
  * 
  * @since 1.0
  */
-public class CFVirtualMachine extends CFMirror implements VirtualMachine, IBreakpointListener {
+public class CFVirtualMachine extends CFMirror implements VirtualMachine {
 
 	private final NullValue nullvalue = new CFNullValue(this);
 	private final UndefinedValue undefinedvalue = new CFUndefinedValue(this);
@@ -73,7 +72,6 @@
 	
 	private Map threads = null;
 	private Map scripts = null;
-	private Map breakpointHandles = new HashMap();
 	
 	/**
 	 * Constructor
@@ -91,15 +89,16 @@
 	 */
 	void initializeBreakpoints() {
 		IBreakpointManager manager = DebugPlugin.getDefault().getBreakpointManager();
-		manager.addBreakpointListener(this);
 		IBreakpoint[] managerBreakpoints = manager.getBreakpoints(JavaScriptDebugModel.MODEL_ID);
 		Vector allBps = new Vector();
 		for (int i = 0; i < managerBreakpoints.length; i++) {
 			IBreakpoint current = managerBreakpoints[i];
-			if (current instanceof JavaScriptLineBreakpoint) {
-				try {
+			try {
+				if(!current.isRegistered()) {
+					continue;
+				}
+				if (current instanceof JavaScriptLineBreakpoint) {
 					JavaScriptLineBreakpoint breakpoint = (JavaScriptLineBreakpoint)current;
-
 					IResource resource = breakpoint.getMarker().getResource();
 					QualifiedName qName = new QualifiedName(JavaScriptCore.PLUGIN_ID, "scriptURL"); //$NON-NLS-1$
 					String url = resource.getPersistentProperty(qName);
@@ -119,6 +118,7 @@
 								attributes.put(Attributes.CONDITION, condition);
 							}
 						}
+						attributes.put(Attributes.ENABLED, new Boolean(breakpoint.isEnabled()));
 						int hitCount = breakpoint.getHitCount();
 						if (hitCount != -1) {
 							attributes.put(Attributes.HIT_COUNT, new Integer(hitCount));
@@ -129,20 +129,30 @@
 						bpMap.put(Attributes.ATTRIBUTES, attributes);
 						allBps.add(bpMap);
 					}
-				} catch (CoreException e) {
-					CrossFirePlugin.log(e);
-				}				
+				}
+			} catch (CoreException e) {
+				CrossFirePlugin.log(e);
 			}
 		}
 		if (allBps.size() > 0) {
 			CFRequestPacket request = new CFRequestPacket(Commands.SET_BREAKPOINTS, null);
 			request.setArgument(Attributes.BREAKPOINTS, Arrays.asList(allBps.toArray()));
 			CFResponsePacket response = ((CFVirtualMachine)virtualMachine()).sendRequest(request);
-			if (!response.isSuccess()) {
-				if(TRACE) {
-					Tracing.writeString("VM [failed setbreakpoints request]: "+JSON.serialize(request)); //$NON-NLS-1$
+			if (response.isSuccess()) {
+				List list = (List)response.getBody().get(Attributes.BREAKPOINTS);
+				if (list != null && list.size() > 0) {
+					for (Iterator i = list.iterator(); i.hasNext();) {
+						Map bp = (Map)i.next();
+						if (bp != null) {
+							RemoteBreakpoint rb = BreakpointTracker.addBreakpoint((CFVirtualMachine) virtualMachine(), bp);
+							BreakpointTracker.findLocalBreakpoint(rb);
+						}
+					}
 				}
 			}
+			else if(TRACE) {
+				Tracing.writeString("VM [failed setbreakpoints request]: "+JSON.serialize(request)); //$NON-NLS-1$
+			}
 		}
 		
 		CFRequestPacket request = new CFRequestPacket(Commands.GET_BREAKPOINTS, null);
@@ -152,7 +162,7 @@
 			Map bp = null;
 			for (Iterator i = list.iterator(); i.hasNext();) {
 				bp = (Map) i.next();
-				addBreakpoint(bp);
+				BreakpointTracker.addBreakpoint(this, bp);
 			}
 		}
 		else if(TRACE) {
@@ -161,47 +171,6 @@
 	}
 	
 	/**
-	 * Sends the <code>getbreakpoint</code> request for the given breakpoint handle
-	 * @param handle
-	 * @return the {@link RemoteBreakpoint} representing the request or <code>null</code> if the breakpoint could not be found
-	 */
-	public RemoteBreakpoint getBreakpoint(Number handle) {
-		CFRequestPacket request = new CFRequestPacket(Commands.GET_BREAKPOINTS, null);
-		request.setArgument(Attributes.HANDLES, Arrays.asList(new Number[] {handle}));
-		CFResponsePacket response = sendRequest(request);
-		if(response.isSuccess()) {
-			List list = (List)response.getBody().get(Attributes.BREAKPOINTS);
-			if (list != null && list.size() > 0) {
-				addBreakpoint((Map)list.get(0));
-			}
-		}
-		else if(TRACE) {
-			Tracing.writeString("VM [failed getbreakpoint request]: "+JSON.serialize(request)); //$NON-NLS-1$
-		}
-		return (RemoteBreakpoint) breakpointHandles.get(handle);
-	}
-	
-	/**
-	 * Sends the <code>changebreakpoint</code> request for the given breakpoint handle to change the given map of attributes
-	 * @param handle
-	 * @param attributes
-	 * @return the changed {@link RemoteBreakpoint} object or <code>null</code> if the request failed
-	 */
-	public RemoteBreakpoint changeBreakpoint(Number handle, Map attributes) {
-		CFRequestPacket request = new CFRequestPacket(Commands.CHANGE_BREAKPOINTS, null);
-		request.setArgument(Attributes.HANDLES, Arrays.asList(new Number[] {handle}));
-		request.setArgument(Attributes.ATTRIBUTES, attributes);
-		CFResponsePacket response = sendRequest(request);
-		if(response.isSuccess()) {
-			updateBreakpoint(response.getBody());
-		}
-		else if(TRACE) {
-			Tracing.writeString("VM [failed getbreakpoint request]: "+JSON.serialize(request)); //$NON-NLS-1$
-		}
-		return (RemoteBreakpoint) breakpointHandles.get(handle);
-	}
-	
-	/**
 	 * Called via reflection to determine if the VM supports suspend on script loads
 	 * @return <code>true</code> if this VM can suspend when a script loads <code>false</code> otherwise
 	 */
@@ -210,44 +179,6 @@
 	}
 	
 	/**
-	 * Add the breakpoint described by the given JSON to the handles list
-	 * @param json
-	 */
-	public void addBreakpoint(Map json) {
-		if(json != null) {
-			Number handle = (Number) json.get(Attributes.HANDLE);
-			if(handle != null) {
-				RemoteBreakpoint bp = (RemoteBreakpoint) breakpointHandles.get(handle);
-				if(bp == null) {
-					bp = new RemoteBreakpoint(this, 
-						handle,
-						(Map) json.get(Attributes.LOCATION),
-						(Map) json.get(Attributes.ATTRIBUTES),
-						(String)json.get(Attributes.TYPE));
-				}
-			}
-		}
-	}
-	
-	/**
-	 * Locates the breakpoint for the handle given in the map and updates its attributes
-	 * 
-	 * @param json the JSON map, cannot be <code>null</code>
-	 */
-	public void updateBreakpoint(Map json) {
-		if(json != null) {
-			Number handle = (Number) json.get(Attributes.HANDLE);
-			if(handle != null) {
-				RemoteBreakpoint bp = (RemoteBreakpoint) breakpointHandles.get(handle);
-				if(bp != null) {
-					bp.setEnabled(RemoteBreakpoint.getEnabled(json));
-					bp.setCondition(RemoteBreakpoint.getCondition(json));
-				}
-			}
-		}
-	}
-	
-	/**
 	 * Adds or removes the breakpoint from the cache based on the <code>isset</code> attribute
 	 * 
 	 * @param json the JSON map, cannot be <code>null</code>
@@ -256,11 +187,16 @@
 		if(json != null) {
 			Boolean isset = (Boolean)json.get(Attributes.SET);
 			if(isset != null && isset.booleanValue()) {
-				updateBreakpoint(json);
-			}
+				Map bp = (Map) json.get(Attributes.BREAKPOINT);
+				RemoteBreakpoint rb = BreakpointTracker.updateBreakpoint(bp);
+				if(rb == null) {
+					BreakpointTracker.createLocalBreakpoint(this, bp);
+				}
+ 			}
 			else {
-				Number handle = (Number) json.get(Attributes.HANDLE);
-				breakpointHandles.remove(handle);
+				Map bp = (Map) json.get(Attributes.BREAKPOINT);
+				Number handle = (Number) bp.get(Attributes.HANDLE);
+				BreakpointTracker.removeLocalBreakpoint(this, handle);
 			}
 		}
 	}
@@ -354,7 +290,7 @@
 			request.getArguments().put(Attributes.TOOLS, Arrays.asList(tools));
 			CFResponsePacket response = sendRequest(request);
 			if(response.isSuccess()) {
-				//TODO handle the tool being enabled
+				//TODO handle the tool being disabled
 				return true;
 			}
 			else if(TRACE) {
@@ -587,10 +523,10 @@
 	}
 
 	/**
-	 * Returns the script with the given url or <code>null</code>
+	 * Returns the {@link ScriptReference} with the given URL or <code>null</code>
 	 * 
 	 * @param url
-	 * @return the thread or <code>null</code>
+	 * @return the {@link ScriptReference} or <code>null</code>
 	 */
 	public synchronized CFScriptReference findScript(String url) {
 		if(scripts == null) {
@@ -605,7 +541,7 @@
 			//to be asked for all of its scripts
 			script = (CFScriptReference) scripts.get(url);
 		}
-		//if we find we have a script id that is not cached, we should try a lookup + add in the vm
+		//if we find we have a script id that is not cached, we should try a lookup + add in the VM
 		if(script == null) {
 			if(TRACE) {
 				Tracing.writeString("VM [failed to find script]: "+url); //$NON-NLS-1$
@@ -649,7 +585,7 @@
 	}
 	
 	/**
-	 * Removes the script with the given url from the listing
+	 * Removes the script with the given URL from the listing
 	 * 
 	 * @param url the script to remove
 	 */
@@ -798,41 +734,40 @@
 			this.queue.dispose();
 			this.ermanager.dispose();
 			this.session.dispose();
+			BreakpointTracker.disconnect(this);
 		} finally {
 			disconnected = true;
-			DebugPlugin.getDefault().getBreakpointManager().removeBreakpointListener(this);
 		}
 	}
 
 	/* (non-Javadoc)
-	 * @see org.eclipse.debug.core.IBreakpointListener#breakpointAdded(org.eclipse.debug.core.model.IBreakpoint)
+	 * @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#canUpdateBreakpoints()
 	 */
-	public void breakpointAdded(IBreakpoint breakpoint) {
-		if (JavaScriptDebugModel.MODEL_ID.equals(breakpoint.getModelIdentifier())) {
-			if (breakpoint instanceof IJavaScriptLineBreakpoint) {
-				//TODO check handle map send request as needed
-			}
-	 	}
+	public boolean canUpdateBreakpoints() {
+		return true;
 	}
 
 	/* (non-Javadoc)
-	 * @see org.eclipse.debug.core.IBreakpointListener#breakpointRemoved(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta)
+	 * @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#updateBreakpoint(org.eclipse.wst.jsdt.debug.core.breakpoints.IJavaScriptBreakpoint)
 	 */
-	public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) {
-		if (JavaScriptDebugModel.MODEL_ID.equals(breakpoint.getModelIdentifier())) {
-			if (breakpoint instanceof IJavaScriptLineBreakpoint) {
-				//TODO check handle map send request as needed
+	public void updateBreakpoint(IJavaScriptBreakpoint breakpoint) {
+		RemoteBreakpoint rb = BreakpointTracker.findRemoteBreakpoint(breakpoint);
+		if(rb != null) {
+			try {
+				BreakpointTracker.syncRemoteBreakpoint(rb, breakpoint);
+				CFRequestPacket request = new CFRequestPacket(Commands.CHANGE_BREAKPOINT, null);
+				request.setArgument(Attributes.HANDLE, rb.getHandle());
+				HashMap attributes = new HashMap();
+				attributes.put(Attributes.ENABLED, Boolean.valueOf(rb.isEnabled()));
+				attributes.put(Attributes.CONDITION, rb.getCondition());
+				request.setArgument(Attributes.ATTRIBUTES, attributes);
+				CFResponsePacket response = sendRequest(request);
+				if(!response.isSuccess() && TRACE) {
+					Tracing.writeString("VM [failed changebreakpoint request]: "+JSON.serialize(request)); //$NON-NLS-1$
+				}
 			}
-		}
-	}
-
-	/* (non-Javadoc)
-	 * @see org.eclipse.debug.core.IBreakpointListener#breakpointChanged(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta)
-	 */
-	public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) {
-		if (JavaScriptDebugModel.MODEL_ID.equals(breakpoint.getModelIdentifier())) {
-			if (breakpoint instanceof IJavaScriptLineBreakpoint) {
-				//TODO check handle map send request as needed
+			catch(CoreException ce) {
+				//if we could not sync do not send a request
 			}
 		}
 	}
diff --git a/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/jsdi/Messages.java b/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/jsdi/Messages.java
index de129f0..f38f47b 100644
--- a/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/jsdi/Messages.java
+++ b/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/jsdi/Messages.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010 IBM Corporation and others.
+ * Copyright (c) 2010, 2012 IBM Corporation 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
@@ -17,6 +17,21 @@
  */
 public class Messages extends NLS {
 	private static final String BUNDLE_NAME = "org.eclipse.wst.jsdt.debug.internal.crossfire.jsdi.messages"; //$NON-NLS-1$
+	public static String BreakpointTracker_0;
+	public static String BreakpointTracker_1;
+	public static String BreakpointTracker_10;
+	public static String BreakpointTracker_11;
+	public static String BreakpointTracker_12;
+	public static String BreakpointTracker_13;
+	public static String BreakpointTracker_14;
+	public static String BreakpointTracker_2;
+	public static String BreakpointTracker_3;
+	public static String BreakpointTracker_4;
+	public static String BreakpointTracker_5;
+	public static String BreakpointTracker_6;
+	public static String BreakpointTracker_7;
+	public static String BreakpointTracker_8;
+	public static String BreakpointTracker_9;
 	public static String crossfire_vm;
 	public static String thread_name;
 	public static String vm_name;
diff --git a/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/jsdi/RemoteBreakpoint.java b/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/jsdi/RemoteBreakpoint.java
index d51a5c8..0b884b2 100644
--- a/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/jsdi/RemoteBreakpoint.java
+++ b/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/jsdi/RemoteBreakpoint.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011 IBM Corporation and others.
+ * Copyright (c) 2011, 2012 IBM Corporation 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
@@ -34,7 +34,7 @@
 	
 	CFVirtualMachine vm = null;
 	Number handle = null;
-	String kind = null;
+	String type = null;
 	Map location = null;
 	Map attributes = null;
 	
@@ -44,14 +44,14 @@
 	 * @param handle
 	 * @param location
 	 * @param attributes
-	 * @param kind
+	 * @param type
 	 */
-	public RemoteBreakpoint(CFVirtualMachine vm, Number handle, Map location, Map attributes, String kind) {
+	public RemoteBreakpoint(CFVirtualMachine vm, Number handle, Map location, Map attributes, String type) {
 		this.vm = vm;
 		this.handle = handle;
 		this.location = location;
 		this.attributes = attributes;
-		this.kind = kind;
+		this.type = type;
 	}
 	
 	/**
@@ -62,7 +62,7 @@
 	}
 	
 	/**
-	 * @return the url
+	 * @return the URL
 	 */
 	public String getUrl() {
 		if(this.location != null) {
@@ -133,10 +133,20 @@
 	}
 	
 	/**
-	 * @return the kind
+	 * Returns the type of the breakpoint
+	 * @return the type
+	 * @see RemoteBreakpoint for type names
 	 */
-	public String getKind() {
-		return kind;
+	public String getType() {
+		return type;
+	}
+	
+	/**
+	 * Returns if this breakpoint is a line breakpoint
+	 * @return <code>true</code> if the type of the breakpoint is <code>line</code>
+	 */
+	public boolean isLineBreakpoint() {
+		return TYPE_LINE.equals(this.type);
 	}
 	
 	/* (non-Javadoc)
@@ -145,7 +155,7 @@
 	public boolean equals(Object o) {
 		if(o instanceof RemoteBreakpoint) {
 			RemoteBreakpoint bp = (RemoteBreakpoint) o;
-			return handle.equals(bp.handle) && mapsEqual(location, bp.location) && mapsEqual(attributes, bp.attributes) && kind.equals(bp.kind);
+			return handle.equals(bp.handle) && mapsEqual(location, bp.location) && mapsEqual(attributes, bp.attributes) && type.equals(bp.type);
 		}
 		return false;
 	}
@@ -191,7 +201,7 @@
 	 * @see java.lang.Object#hashCode()
 	 */
 	public int hashCode() {
-		return handle.hashCode() + mapHashCode(location) + mapHashCode(attributes) + kind.hashCode();
+		return handle.hashCode() + mapHashCode(location) + mapHashCode(attributes) + type.hashCode();
 	}
 	
 	/**
@@ -213,7 +223,7 @@
 	public int compareTo(Object o) {
 		if(o instanceof RemoteBreakpoint) {
 			RemoteBreakpoint bp = (RemoteBreakpoint) o;
-			return this.kind.compareTo(bp.kind);
+			return this.type.compareTo(bp.type);
 		}
 		return 0;
 	}
@@ -255,7 +265,10 @@
 		Object val = json.get(Attributes.ATTRIBUTES);
 		if(val instanceof Map) {
 			Map map = (Map) val;
-			return (String)map.get(Attributes.CONDITION);
+			String condition = (String)map.get(Attributes.CONDITION);
+			if(condition != null && condition.trim().length() > 0) {
+				return condition;
+			}
 		}
 		return null;
 	}
diff --git a/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/jsdi/messages.properties b/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/jsdi/messages.properties
index faa75c2..819ae33 100644
--- a/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/jsdi/messages.properties
+++ b/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/jsdi/messages.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2010 IBM Corporation and others.
+# Copyright (c) 2010, 2012 IBM Corporation 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
@@ -8,6 +8,21 @@
 # Contributors:
 #     IBM Corporation - initial API and implementation
 ###############################################################################
+BreakpointTracker_1=You cannot remove a breakpoint with a null handle
+BreakpointTracker_10=You cannot look up a local breakpoint with a null handle
+BreakpointTracker_11=You cannot disconnect a null VM
+BreakpointTracker_12=You cannot look up a RemoteBreakpoint with a null local breakpoint
+BreakpointTracker_13=You cannot synchronize a null RemoteBreakpoint
+BreakpointTracker_14=You cannot synchronize from a null local IJavaScriptBreakpoint
+BreakpointTracker_2=You cannot add a breakpoint to a null VM
+BreakpointTracker_3=You cannot add a breakpoint with a null JSON map
+BreakpointTracker_4=You cannot update a breakpoint with no JSON map
+BreakpointTracker_5=You cannot create a new breakpoint with a null VM
+BreakpointTracker_6=You cannot create a new breakpoint from a null JSON map
+BreakpointTracker_7=You cannot search for a null remote breakpoint
+BreakpointTracker_0=You cannot look up a null handle
+BreakpointTracker_8=You cannot update a local breakpoint with a null remote breakpoint
+BreakpointTracker_9=You cannot remove a local breakpoint with a null remote breakpoint handle
 crossfire_vm=Crossfire VM
 thread_name={0} - {1}
 vm_name=CrossFire VM
diff --git a/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/request/CFBreakpointRequest.java b/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/request/CFBreakpointRequest.java
index e32e647..dba809e 100644
--- a/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/request/CFBreakpointRequest.java
+++ b/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/request/CFBreakpointRequest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2011 IBM Corporation and others.
+ * Copyright (c) 2010, 2012 IBM Corporation 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
@@ -19,8 +19,10 @@
 import org.eclipse.wst.jsdt.debug.core.jsdi.ThreadReference;
 import org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine;
 import org.eclipse.wst.jsdt.debug.core.jsdi.request.BreakpointRequest;
+import org.eclipse.wst.jsdt.debug.internal.crossfire.jsdi.BreakpointTracker;
 import org.eclipse.wst.jsdt.debug.internal.crossfire.jsdi.CFScriptReference;
 import org.eclipse.wst.jsdt.debug.internal.crossfire.jsdi.CFVirtualMachine;
+import org.eclipse.wst.jsdt.debug.internal.crossfire.jsdi.RemoteBreakpoint;
 import org.eclipse.wst.jsdt.debug.internal.crossfire.transport.Attributes;
 import org.eclipse.wst.jsdt.debug.internal.crossfire.transport.CFRequestPacket;
 import org.eclipse.wst.jsdt.debug.internal.crossfire.transport.CFResponsePacket;
@@ -128,11 +130,12 @@
 					if (bp != null) {
 						Number handle = (Number) bp.get(Attributes.HANDLE);
 						bpHandle = new Long(handle.longValue());
+						RemoteBreakpoint rb = BreakpointTracker.addBreakpoint((CFVirtualMachine) virtualMachine(), bp);
+						if(rb != null) {
+							BreakpointTracker.findLocalBreakpoint(rb);
+						}
 					}
 				}
-				else {
-					//TODO create a dummy breakpoint whose details can be filled in when an onToggleBreakpoint event is received
-				}
 			}
 		}
 		else if(bpHandle != null) {
@@ -141,6 +144,7 @@
 			request.getArguments().put(Attributes.HANDLES, Arrays.asList(new Number[] {bpHandle}));
 			CFResponsePacket response = ((CFVirtualMachine)virtualMachine()).sendRequest(request);
 			if(response.isSuccess()) {
+				BreakpointTracker.removeBreakpoint((CFVirtualMachine) virtualMachine(), bpHandle);
 				bpHandle = null;
 			}
 		}
diff --git a/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/transport/Commands.java b/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/transport/Commands.java
index dbebd9b..1b58c6f 100644
--- a/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/transport/Commands.java
+++ b/bundles/org.eclipse.wst.jsdt.debug.crossfire/src/org/eclipse/wst/jsdt/debug/internal/crossfire/transport/Commands.java
@@ -24,7 +24,7 @@
 	/**
 	 * The "changebreakpoint" command
 	 */
-	public static final String CHANGE_BREAKPOINTS = "changeBreakpoints"; //$NON-NLS-1$
+	public static final String CHANGE_BREAKPOINT = "changeBreakpoint"; //$NON-NLS-1$
 	/**
 	 * The "deletebreakpoint" command
 	 */
diff --git a/bundles/org.eclipse.wst.jsdt.debug.rhino/src/org/eclipse/wst/jsdt/debug/internal/rhino/jsdi/VirtualMachineImpl.java b/bundles/org.eclipse.wst.jsdt.debug.rhino/src/org/eclipse/wst/jsdt/debug/internal/rhino/jsdi/VirtualMachineImpl.java
index d9e316d..436fed3 100644
--- a/bundles/org.eclipse.wst.jsdt.debug.rhino/src/org/eclipse/wst/jsdt/debug/internal/rhino/jsdi/VirtualMachineImpl.java
+++ b/bundles/org.eclipse.wst.jsdt.debug.rhino/src/org/eclipse/wst/jsdt/debug/internal/rhino/jsdi/VirtualMachineImpl.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2011 IBM Corporation and others.
+ * Copyright (c) 2010, 2012 IBM Corporation 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
@@ -16,6 +16,7 @@
 import java.util.List;
 import java.util.Map;
 
+import org.eclipse.wst.jsdt.debug.core.breakpoints.IJavaScriptBreakpoint;
 import org.eclipse.wst.jsdt.debug.core.jsdi.BooleanValue;
 import org.eclipse.wst.jsdt.debug.core.jsdi.NullValue;
 import org.eclipse.wst.jsdt.debug.core.jsdi.NumberValue;
@@ -446,4 +447,17 @@
 	public EventQueue eventQueue() {
 		return eventQueue;
 	}
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#canUpdateBreakpoints()
+	 */
+	public boolean canUpdateBreakpoints() {
+		return false;
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine#updateBreakpoint(org.eclipse.wst.jsdt.debug.core.breakpoints.IJavaScriptBreakpoint)
+	 */
+	public void updateBreakpoint(IJavaScriptBreakpoint breakpoint) {
+	}
 }