cdt/cdt_6_0_x/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/BreakpointsMediator.java
changeset 112 6b1088abccf8
parent 104 b23e845b9366
child 117 09f3d307f081
equal deleted inserted replaced
111:c2563c416525 112:6b1088abccf8
    11  *******************************************************************************/
    11  *******************************************************************************/
    12 
    12 
    13 package org.eclipse.cdt.dsf.debug.service;
    13 package org.eclipse.cdt.dsf.debug.service;
    14 
    14 
    15 import java.util.ArrayList;
    15 import java.util.ArrayList;
       
    16 import java.util.Collections;
    16 import java.util.HashMap;
    17 import java.util.HashMap;
    17 import java.util.HashSet;
    18 import java.util.HashSet;
    18 import java.util.Hashtable;
    19 import java.util.Hashtable;
    19 import java.util.LinkedList;
    20 import java.util.LinkedList;
    20 import java.util.List;
    21 import java.util.List;
    23 import java.util.concurrent.RejectedExecutionException;
    24 import java.util.concurrent.RejectedExecutionException;
    24 
    25 
    25 import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
    26 import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
    26 import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
    27 import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
    27 import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
    28 import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
       
    29 import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
       
    30 import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
    28 import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
    31 import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
    29 import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
    32 import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
    30 import org.eclipse.cdt.dsf.datamodel.DMContexts;
       
    31 import org.eclipse.cdt.dsf.datamodel.IDMContext;
    33 import org.eclipse.cdt.dsf.datamodel.IDMContext;
    32 import org.eclipse.cdt.dsf.debug.service.IBreakpointAttributeTranslator.EBreakpointStatusChange;
       
    33 import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMContext;
    34 import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMContext;
    34 import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
    35 import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
    35 import org.eclipse.cdt.dsf.internal.DsfPlugin;
    36 import org.eclipse.cdt.dsf.internal.DsfPlugin;
    36 import org.eclipse.cdt.dsf.service.AbstractDsfService;
    37 import org.eclipse.cdt.dsf.service.AbstractDsfService;
    37 import org.eclipse.cdt.dsf.service.DsfSession;
    38 import org.eclipse.cdt.dsf.service.DsfSession;
    40 import org.eclipse.core.runtime.IProgressMonitor;
    41 import org.eclipse.core.runtime.IProgressMonitor;
    41 import org.eclipse.core.runtime.IStatus;
    42 import org.eclipse.core.runtime.IStatus;
    42 import org.eclipse.core.runtime.Status;
    43 import org.eclipse.core.runtime.Status;
    43 import org.eclipse.core.runtime.jobs.Job;
    44 import org.eclipse.core.runtime.jobs.Job;
    44 import org.eclipse.debug.core.DebugPlugin;
    45 import org.eclipse.debug.core.DebugPlugin;
    45 import org.eclipse.debug.core.IBreakpointListener;
       
    46 import org.eclipse.debug.core.IBreakpointManager;
    46 import org.eclipse.debug.core.IBreakpointManager;
    47 import org.eclipse.debug.core.IBreakpointManagerListener;
    47 import org.eclipse.debug.core.IBreakpointManagerListener;
       
    48 import org.eclipse.debug.core.IBreakpointsListener;
    48 import org.eclipse.debug.core.model.IBreakpoint;
    49 import org.eclipse.debug.core.model.IBreakpoint;
    49 import org.osgi.framework.BundleContext;
    50 import org.osgi.framework.BundleContext;
    50 
    51 
    51 /**
    52 /**
    52  * 
    53  * 
    53  */
    54  */
    54 public class BreakpointsMediator extends AbstractDsfService implements IBreakpointManagerListener, IBreakpointListener
    55 public class BreakpointsMediator extends AbstractDsfService implements IBreakpointManagerListener, IBreakpointsListener
    55 {
    56 {
    56 
    57 	public enum BreakpointEventType {ADDED, REMOVED, MODIFIED}; 	
       
    58 	
    57     /**
    59     /**
    58      * The attribute translator that this service will use to map the platform
    60      * The attribute translator that this service will use to map the platform
    59      * breakpiont attributes to the corresponding target attributes, and vice
    61      * breakpoint attributes to the corresponding target attributes, and vice
    60      * versa.
    62      * versa.
    61      */
    63      */
    62     private IBreakpointAttributeTranslator fAttributeTranslator;
    64     private IBreakpointAttributeTranslator fAttributeTranslator;
       
    65     
       
    66     /**
       
    67      * If the attribute translator implements the {@link IBreakpointAttributeTranslatorExtension},
       
    68      * this field will be valid, otherwise it is null.
       
    69      */
       
    70     private IBreakpointAttributeTranslatorExtension fAttributeTranslator2;
    63 
    71 
    64     /**
    72     /**
    65      * DSF Debug service for creating breakpoints.
    73      * DSF Debug service for creating breakpoints.
    66      */
    74      */
    67     IBreakpoints fBreakpoints;
    75     IBreakpoints fBreakpoints;
    68     
    76     
    69     /**
    77     /**
    70      * Platform breakpoint manager
    78      * Platform breakpoint manager
    71      */
    79      */
    72     IBreakpointManager fBreakpointManager;
    80     IBreakpointManager fBreakpointManager;
    73 	
    81 
       
    82     /**
       
    83      * Object describing the information about a single target breakpoint  
       
    84      * corresponding to specific platform breakpoint and breakpoint target 
       
    85      * context.
       
    86      * 
       
    87      * @since 2.1
       
    88      */
       
    89     public interface ITargetBreakpointInfo {
       
    90 
       
    91     	/**
       
    92     	 * Returns the breakpoint attributes as returned by the attribute translator.
       
    93     	 */
       
    94     	public Map<String, Object> getAttributes();
       
    95 
       
    96     	/**
       
    97     	 * Returns the target breakpoint context.  May be <code>null</code> if the 
       
    98     	 * breakpoint failed to install on target. 
       
    99     	 */
       
   100     	public IBreakpointDMContext getTargetBreakpoint();
       
   101 
       
   102     	/**
       
   103     	 * Returns the status result of the last breakpoint operation (install/remove). 
       
   104     	 */
       
   105     	public IStatus getStatus();
       
   106     }
       
   107     
       
   108     private static class TargetBP implements ITargetBreakpointInfo {
       
   109     	
       
   110     	private Map<String, Object> fAttributes;
       
   111     	private Map<String, Object> fAttributesDelta; // not really useful ?
       
   112     	private IBreakpointDMContext fTargetBPContext;
       
   113     	private IStatus fStatus;
       
   114     	
       
   115     	public TargetBP(Map<String, Object> attrs) {
       
   116     		fAttributes = attrs;
       
   117     	}
       
   118     	
       
   119     	public Map<String, Object> getAttributes() {
       
   120 			return fAttributes;
       
   121 		}
       
   122     	
       
   123     	public IBreakpointDMContext getTargetBreakpoint() {
       
   124 			return fTargetBPContext;
       
   125 		}
       
   126     	
       
   127     	public IStatus getStatus() {
       
   128 			return fStatus;
       
   129 		}
       
   130 
       
   131 		public void setTargetBreakpoint(IBreakpointDMContext fTargetBPContext) {
       
   132 			this.fTargetBPContext = fTargetBPContext;
       
   133 		}
       
   134 
       
   135 		public void setStatus(IStatus status) {
       
   136 			this.fStatus = status;
       
   137 		}
       
   138     }
    74     
   139     
    75     ///////////////////////////////////////////////////////////////////////////
   140     ///////////////////////////////////////////////////////////////////////////
    76     // Breakpoints tracking
   141     // Breakpoints tracking
    77     ///////////////////////////////////////////////////////////////////////////
   142     ///////////////////////////////////////////////////////////////////////////
    78 
   143 
    79     /**
   144     /**
    80      * Holds the set of platform breakpoints with their corresponding back-end
   145      * Holds the set of platform breakpoints with their breakpoint information 
    81      * breakpoint attributes, per context (i.e. each platform breakpoint is
   146      * structures, per context (i.e. each platform breakpoint is
    82      * replicated for each execution context).
   147      * replicated for each execution context).
    83      * - Context entry added/removed on start/stopTrackingBreakpoints()
   148      * - Context entry added/removed on start/stopTrackingBreakpoints()
    84      * - Augmented on breakpointAdded()
   149      * - Augmented on breakpointAdded()
    85      * - Modified on breakpointChanged()
   150      * - Modified on breakpointChanged()
    86      * - Diminished on breakpointRemoved()
   151      * - Diminished on breakpointRemoved()
    87      */
   152      */
    88 	private Map<IBreakpointsTargetDMContext, Map<IBreakpoint, List<Map<String, Object>>>> fPlatformBPs = 
   153 	private Map<IBreakpointsTargetDMContext, Map<IBreakpoint, List<TargetBP>>> fPlatformBPs = 
    89 		new HashMap<IBreakpointsTargetDMContext, Map<IBreakpoint, List<Map<String, Object>>>>();
   154 		new HashMap<IBreakpointsTargetDMContext, Map<IBreakpoint, List<TargetBP>>>();
    90 
       
    91     /**
       
    92      * Holds the mapping from platform breakpoint to the corresponding target
       
    93      * breakpoint(s), per context. There can be multiple back-end BPs for a 
       
    94      * single platform BP in the case of [1] multiple target contexts, and/or
       
    95      * [2] thread filtering.
       
    96      * Updated when:
       
    97      * - We start/stop tracking an execution context
       
    98      * - A platform breakpoint is added/removed
       
    99      * - A thread filter is applied/removed
       
   100      */
       
   101 	private Map<IBreakpointsTargetDMContext, Map<IBreakpoint, List<IBreakpointDMContext>>> fBreakpointDMContexts = 
       
   102 		new HashMap<IBreakpointsTargetDMContext, Map<IBreakpoint, List<IBreakpointDMContext>>>();
       
   103 
   155 
   104     /**
   156     /**
   105      * Due to the very asynchronous nature of DSF, a new breakpoint request can
   157      * Due to the very asynchronous nature of DSF, a new breakpoint request can
   106      * pop up at any time before an ongoing one is completed. The following set
   158      * pop up at any time before an ongoing one is completed. The following set
   107      * is used to store requests until the ongoing operation completes.
   159      * is used to store requests until the ongoing operation completes.
   108      */
   160      */
   109 	private Set<IBreakpoint> fPendingRequests    = new HashSet<IBreakpoint>();
   161 	private Set<IBreakpoint> fRunningEvents    = new HashSet<IBreakpoint>();
       
   162 
       
   163 	private static class PendingEventInfo {
       
   164 		PendingEventInfo(BreakpointEventType eventType, IBreakpointsTargetDMContext bpsTargetDmc, RequestMonitor rm) {
       
   165 			fEventType = eventType;
       
   166 			fBPsTargetDmc = bpsTargetDmc;
       
   167 			fRequestMonitor = rm;
       
   168 		}
       
   169 		
       
   170 		RequestMonitor fRequestMonitor;
       
   171 		BreakpointEventType fEventType;
       
   172 		IBreakpointsTargetDMContext fBPsTargetDmc;
       
   173 	}
   110 	
   174 	
   111 	/**
   175 	/**
   112 	 * @see fPendingRequests
   176 	 * @see fPendingRequests
   113 	 */
   177 	 */
   114 	private Set<IBreakpoint> fPendingBreakpoints = new HashSet<IBreakpoint>();
   178 	private Map<IBreakpoint, LinkedList<PendingEventInfo>> fPendingEvents = 
       
   179 		Collections.synchronizedMap(new HashMap<IBreakpoint, LinkedList<PendingEventInfo>>());
   115 	
   180 	
   116     ///////////////////////////////////////////////////////////////////////////
   181     ///////////////////////////////////////////////////////////////////////////
   117     // AbstractDsfService    
   182     // AbstractDsfService    
   118     ///////////////////////////////////////////////////////////////////////////
   183     ///////////////////////////////////////////////////////////////////////////
   119 
   184 
   124 	 * @param debugModelId
   189 	 * @param debugModelId
   125 	 */
   190 	 */
   126 	public BreakpointsMediator(DsfSession session, IBreakpointAttributeTranslator attributeTranslator) {
   191 	public BreakpointsMediator(DsfSession session, IBreakpointAttributeTranslator attributeTranslator) {
   127         super(session);
   192         super(session);
   128         fAttributeTranslator = attributeTranslator;
   193         fAttributeTranslator = attributeTranslator;
       
   194         
       
   195         fAttributeTranslator2 = null;
       
   196         if (attributeTranslator instanceof IBreakpointAttributeTranslatorExtension)
       
   197         	fAttributeTranslator2 = (IBreakpointAttributeTranslatorExtension)attributeTranslator;
   129 	}
   198 	}
   130 
   199 
   131     @Override
   200     @Override
   132     public void initialize(final RequestMonitor rm) {
   201     public void initialize(final RequestMonitor rm) {
   133         // - Collect references for the services we interact with
   202         // - Collect references for the services we interact with
   216      * context until {@link #uninstallBreakpoints(IDMContext)} is called for that
   285      * context until {@link #uninstallBreakpoints(IDMContext)} is called for that
   217      * context.
   286      * context.
   218      * @param dmc Context to start tracking breakpoints for.
   287      * @param dmc Context to start tracking breakpoints for.
   219      * @param rm Completion callback.
   288      * @param rm Completion callback.
   220      */
   289      */
   221     public void startTrackingBreakpoints(IBreakpointsTargetDMContext dmc, final RequestMonitor rm) {
   290     public void startTrackingBreakpoints(final IBreakpointsTargetDMContext dmc, final RequestMonitor rm) {
   222         // - Augment the maps with the new execution context
   291         // - Augment the maps with the new execution context
   223         // - Install the platform breakpoints on the selected target
   292         // - Install the platform breakpoints on the selected target
   224 
       
   225     	// Validate the context
       
   226         final IBreakpointsTargetDMContext breakpointsDmc = DMContexts.getAncestorOfType(dmc, IBreakpointsTargetDMContext.class);
       
   227         if (breakpointsDmc == null) {
       
   228             rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid context type", null)); //$NON-NLS-1$
       
   229             rm.done();            
       
   230             return;
       
   231         }
       
   232             
   293             
   233         // Make sure a mapping for this execution context does not already exist
   294         // Make sure a mapping for this execution context does not already exist
   234 		Map<IBreakpoint, List<Map<String, Object>>> platformBPs = fPlatformBPs.get(dmc);
   295 		Map<IBreakpoint, List<TargetBP>> platformBPs = fPlatformBPs.get(dmc);
   235 		if (platformBPs != null) {
   296 		if (platformBPs != null) {
   236             rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INTERNAL_ERROR, "Context already initialized", null)); //$NON-NLS-1$
   297             rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INTERNAL_ERROR, "Context already initialized", null)); //$NON-NLS-1$
   237             rm.done();            
   298             rm.done();            
   238             return;
   299             return;
   239 		}
   300 		}
   240 
   301 
   241         // Create entries in the breakpoint tables for the new context. These entries should only
   302         // Create entries in the breakpoint tables for the new context. These entries should only
   242         // be removed when this service stops tracking breakpoints for the given context.
   303         // be removed when this service stops tracking breakpoints for the given context.
   243         fPlatformBPs.put(breakpointsDmc, new HashMap<IBreakpoint, List<Map<String, Object>>>());
   304         fPlatformBPs.put(dmc, new HashMap<IBreakpoint, List<TargetBP>>());
   244 		fBreakpointDMContexts.put(breakpointsDmc, new HashMap<IBreakpoint, List<IBreakpointDMContext>>());
       
   245 
   305 
   246         // Install the platform breakpoints (stored in fPlatformBPs) on the target.
   306         // Install the platform breakpoints (stored in fPlatformBPs) on the target.
   247 		// We need to use a background thread for this operation because we are 
   307 		// We need to use a background thread for this operation because we are 
   248 		// accessing the resources system to retrieve the breakpoint attributes.
   308 		// accessing the resources system to retrieve the breakpoint attributes.
   249 		// Accessing the resources system potentially requires using global locks.
   309 		// Accessing the resources system potentially requires using global locks.
   250 		// Also we will be calling IBreakpointAttributeTranslator which is prohibited
   310 		// Also we will be calling IBreakpointAttributeTranslator which is prohibited
   251 		// from being called on the session executor thread.
   311 		// from being called on the session executor thread.
   252 		new Job("MI Debugger: Install initial breakpoint list.") { //$NON-NLS-1$
   312 		new Job("Install initial breakpoint list.") { //$NON-NLS-1$
   253             { setSystem(true); }
   313             { setSystem(true); }
   254 
   314 
   255 			// Get the stored breakpoints from the platform BreakpointManager
   315 			// Get the stored breakpoints from the platform BreakpointManager
   256 			// and install them on the target
   316 			// and install them on the target
   257         	@Override
   317         	@Override
   258             protected IStatus run(IProgressMonitor monitor) {
   318             protected IStatus run(IProgressMonitor monitor) {
   259                 // Read initial breakpoints from platform.  Copy the breakpoint attributes into a local map.
   319         		doBreakpointsAdded(DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(), dmc, rm);
   260                 // Note that we cannot write data into fPlatformBPs table here directly because we are not
       
   261                 // executing on the dispatch thread.
       
   262                 final Map<IBreakpoint, List<Map<String, Object>>> initialPlatformBPs = 
       
   263                     new HashMap<IBreakpoint, List<Map<String, Object>>>();
       
   264                 try {
       
   265                 	// Get the stored breakpoint list from the platform BreakpointManager
       
   266                     IBreakpoint[] bps = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints();
       
   267                     // Single out the installable breakpoints...
       
   268                     for (IBreakpoint bp : bps) {
       
   269                     	if (fAttributeTranslator.supportsBreakpoint(bp)) {
       
   270 	                        // Retrieve the breakpoint attributes
       
   271                     		List<Map<String, Object>> attrsArray = 
       
   272                     		    fAttributeTranslator.getBreakpointAttributes(bp, fBreakpointManager.isEnabled());
       
   273 	                        // Store it for now (will be installed on the dispatcher thread)
       
   274                             initialPlatformBPs.put(bp, attrsArray);
       
   275                         }
       
   276                     }
       
   277                 } catch (CoreException e) {
       
   278                     IStatus status = new Status(
       
   279                         IStatus.ERROR, DsfPlugin.PLUGIN_ID, REQUEST_FAILED, "Unable to read initial breakpoint attributes", e); //$NON-NLS-1$
       
   280                     rm.setStatus(status);
       
   281                     rm.done();
       
   282                     return status;
       
   283                 }
       
   284                 
       
   285                 // Submit the runnable to plant the breakpoints on dispatch thread.
       
   286                 getExecutor().submit(new Runnable() {
       
   287                 	public void run() {
       
   288                 		installInitialBreakpoints(breakpointsDmc, initialPlatformBPs, rm);
       
   289                 	}
       
   290                 });
       
   291 
       
   292                 return Status.OK_STATUS;
   320                 return Status.OK_STATUS;
   293             }
   321             }
   294         }.schedule();    
   322         }.schedule();    
   295     }
   323     }
   296 
   324 
   297     /**
       
   298      * Installs the breakpoints that existed prior to the activation of this
       
   299      * breakpoints context.
       
   300      */
       
   301     private void installInitialBreakpoints(final IBreakpointsTargetDMContext dmc,
       
   302             Map<IBreakpoint, List<Map<String, Object>>> initialPlatformBPs,
       
   303             RequestMonitor rm)
       
   304     {
       
   305         // Retrieve the set of platform breakpoints for this context
       
   306         Map<IBreakpoint, List<Map<String, Object>>> platformBPs = fPlatformBPs.get(dmc);
       
   307         if (platformBPs == null) {
       
   308             rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
       
   309             rm.done();
       
   310             return;
       
   311         }
       
   312 
       
   313         // Install the individual breakpoints on the executor thread
       
   314         // Requires a counting monitor to know when we're done
       
   315         final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm);
       
   316         countingRm.setDoneCount(initialPlatformBPs.size());
       
   317 
       
   318         for (final IBreakpoint bp : initialPlatformBPs.keySet()) {
       
   319             final List<Map<String, Object>> attrs = initialPlatformBPs.get(bp);
       
   320             // Upon determining the debuggerPath, the breakpoint is installed
       
   321             installBreakpoint(dmc, bp, attrs, new RequestMonitor(getExecutor(), countingRm));
       
   322         }
       
   323     }
       
   324 
       
   325     
       
   326     public void stopTrackingBreakpoints(final IBreakpointsTargetDMContext dmc, final RequestMonitor rm) {
   325     public void stopTrackingBreakpoints(final IBreakpointsTargetDMContext dmc, final RequestMonitor rm) {
   327         // - Remove the target breakpoints for the given execution context
   326         // - Remove the target breakpoints for the given execution context
   328         // - Update the maps
   327         // - Update the maps
   329 
   328 
   330     	// Remove the breakpoints for given DMC from the internal maps.
   329     	// Remove the breakpoints for given DMC from the internal maps.
   331         Map<IBreakpoint, List<Map<String, Object>>> platformBPs = fPlatformBPs.get(dmc);
   330         Map<IBreakpoint, List<TargetBP>> platformBPs = fPlatformBPs.get(dmc);
   332         if (platformBPs == null) {
   331         if (platformBPs == null) {
   333             rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INTERNAL_ERROR, "Breakpoints not installed for given context", null)); //$NON-NLS-1$
   332             rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INTERNAL_ERROR, "Breakpoints not installed for given context", null)); //$NON-NLS-1$
   334             rm.done();
   333             rm.done();
   335             return;
   334             return;
   336         }
   335         }
   337 
   336 
   338         // Uninstall the individual breakpoints on the executor thread
   337 		new Job("Uninstall target breakpoints list.") { //$NON-NLS-1$
   339         // Requires a counting monitor to know when we're done
   338             { setSystem(true); }
   340         final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm);
   339 
   341         countingRm.setDoneCount(platformBPs.size());
   340 			// Get the stored breakpoints from the platform BreakpointManager
   342 
   341 			// and install them on the target
   343         for (final IBreakpoint bp : platformBPs.keySet()) {
   342         	@Override
   344             uninstallBreakpoint(dmc, bp, countingRm); 
   343             protected IStatus run(IProgressMonitor monitor) {
       
   344         		doBreakpointsRemoved(DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(), dmc, rm);
       
   345                 return Status.OK_STATUS;
       
   346             }
       
   347         }.schedule();    
       
   348     }
       
   349     
       
   350     /**
       
   351      * Find target breakpoints installed in the given context that are resolved 
       
   352      * from the given platform breakpoint.
       
   353      *  
       
   354      * @param dmc - context
       
   355      * @param platformBp - platform breakpoint
       
   356      * @return array of target breakpoints. 
       
   357      */
       
   358     public ITargetBreakpointInfo[] getTargetBreakpoints(IBreakpointsTargetDMContext dmc, IBreakpoint platformBp) {
       
   359         Map<IBreakpoint, List<TargetBP>> platformBPs = fPlatformBPs.get(dmc);
       
   360 
       
   361         if (platformBPs != null)
       
   362         {
       
   363         	List<TargetBP> bpInfo = platformBPs.get(platformBp);
       
   364             if (bpInfo != null) {
       
   365             	return bpInfo.toArray(new ITargetBreakpointInfo[bpInfo.size()]);
       
   366             }
   345         }
   367         }
       
   368         return null;
   346     }
   369     }
   347 
   370     
       
   371     /**
       
   372      * Find the platform breakpoint that's mapped to the given target breakpoint.
       
   373      * 
       
   374      * @param dmc - context of the target breakpoint, can be null.
       
   375      * @param bp - target breakpoint
       
   376      * @return platform breakpoint. null if not found. 
       
   377      */
       
   378     public IBreakpoint getPlatformBreakpoint(IBreakpointsTargetDMContext dmc, IBreakpointDMContext bp) {
       
   379     	for (IBreakpointsTargetDMContext bpContext : fPlatformBPs.keySet()) {
       
   380     		if (dmc != null && !dmc.equals(bpContext))
       
   381     			continue;
       
   382     		
       
   383 	        Map<IBreakpoint, List<TargetBP>> platformBPs = fPlatformBPs.get(bpContext);
       
   384 	
       
   385 	        if (platformBPs != null && platformBPs.size() > 0)
       
   386 	        {
       
   387 	            for(Map.Entry<IBreakpoint, List<TargetBP>> e: platformBPs.entrySet())
       
   388 	            {
       
   389 	                // Stop at the first occurrence
       
   390 	            	for (TargetBP tbp : e.getValue())
       
   391 	            		if(tbp.getTargetBreakpoint().equals(bp))
       
   392 	            			return e.getKey();
       
   393 	            }    
       
   394 	        }
       
   395     	}
       
   396 
       
   397     	return null;
       
   398     }
       
   399     
   348     ///////////////////////////////////////////////////////////////////////////
   400     ///////////////////////////////////////////////////////////////////////////
   349     // Back-end interface functions
   401     // Back-end interface functions
   350     ///////////////////////////////////////////////////////////////////////////
   402     ///////////////////////////////////////////////////////////////////////////
   351 
   403 
   352 	/**
   404 	/**
   353 	 * Install a new platform breakpoint on the back-end. A platform breakpoint
   405 	 * Install a new platform breakpoint on the back-end. A platform breakpoint
   354 	 * can resolve into multiple back-end breakpoints when threads are taken
   406 	 * can resolve into multiple back-end breakpoints, e.g. when threads are taken
   355 	 * into account.
   407 	 * into account.
   356 	 *  
   408 	 *  
   357 	 * @param dmc
   409 	 * @param dmc
   358 	 * @param breakpoint
   410 	 * @param breakpoint
   359 	 * @param attrsList
   411 	 * @param attrsList - list of attribute map, each mapping to a potential target BP.
   360 	 * @param rm
   412 	 * @param rm
   361 	 */
   413 	 */
   362 	private void installBreakpoint(IBreakpointsTargetDMContext dmc, final IBreakpoint breakpoint,
   414 	private void installBreakpoint(IBreakpointsTargetDMContext dmc, final IBreakpoint breakpoint,
   363 			final List<Map<String, Object>> attrsList, final RequestMonitor rm)
   415 			final List<Map<String, Object>> attrsList, final DataRequestMonitor<List<TargetBP>> rm)
   364 	{
   416 	{
   365     	// Retrieve the set of breakpoints for this context
   417     	// Retrieve the set of breakpoints for this context
   366         final Map<IBreakpoint, List<Map<String, Object>>> platformBPs = fPlatformBPs.get(dmc);
   418         final Map<IBreakpoint, List<TargetBP>> platformBPs = fPlatformBPs.get(dmc);
   367         assert platformBPs != null;
   419         assert platformBPs != null;
   368 
   420 
   369         final Map<IBreakpoint, List<IBreakpointDMContext>> breakpointIDs = fBreakpointDMContexts.get(dmc);
       
   370         assert breakpointIDs != null; // fBreakpointIds should be updated in parallel with fPlatformBPs 
       
   371 
       
   372         // Ensure the breakpoint is not already installed
   421         // Ensure the breakpoint is not already installed
   373         if (platformBPs.containsKey(breakpoint)) {
   422         assert !platformBPs.containsKey(breakpoint);
   374             rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_STATE, "Breakpoint already installed", null)); //$NON-NLS-1$
   423 
   375             rm.done();
   424         final ArrayList<TargetBP> targetBPsAttempted = new ArrayList<TargetBP>(attrsList.size());
   376             return;
   425         for (int i = 0; i < attrsList.size(); i++) {
       
   426         	targetBPsAttempted.add(new TargetBP(attrsList.get(i)));
   377         }
   427         }
       
   428         
       
   429         final ArrayList<TargetBP> targetBPsInstalled = new ArrayList<TargetBP>(attrsList.size());
   378 
   430 
   379         // Update the breakpoint status when all back-end breakpoints have been installed
   431         // Update the breakpoint status when all back-end breakpoints have been installed
   380     	final CountingRequestMonitor installRM = new CountingRequestMonitor(getExecutor(), rm) {
   432     	final CountingRequestMonitor installRM = new CountingRequestMonitor(getExecutor(), rm) {
   381 			@Override
   433 			@Override
   382 			protected void handleSuccess() {
   434 			protected void handleCompleted() {
   383 				// Store the platform breakpoint
   435 				// Store successful targetBPs with the platform breakpoint
   384 				platformBPs.put(breakpoint, attrsList);
   436 				if (targetBPsInstalled.size() > 0)
   385                 new Job("Breakpoint status update") { //$NON-NLS-1$
   437 					platformBPs.put(breakpoint, targetBPsInstalled);
   386                     { setSystem(true); }
   438 				
   387                     @Override
   439 				// Store all targetBPs, success or failure, in the rm.
   388                     protected IStatus run(IProgressMonitor monitor) {
   440 				rm.setData(targetBPsAttempted);
   389                         fAttributeTranslator.updateBreakpointStatus(breakpoint, EBreakpointStatusChange.EInstalled);
       
   390                         return Status.OK_STATUS;
       
   391                     };
       
   392                 }.schedule();
       
   393 		        rm.done();
   441 		        rm.done();
   394 			}
   442 			}
   395 		};
   443 		};
   396 
   444 
   397         // A back-end breakpoint needs to be installed for each specified attributes map.
   445         // A back-end breakpoint needs to be installed for each specified attributes map.
   398 		installRM.setDoneCount(attrsList.size());
   446 		installRM.setDoneCount(attrsList.size());
   399 
   447 
   400 		// Install the back-end breakpoint(s)
   448 		// Install the back-end breakpoint(s)
   401 		for (Map<String, Object> attrs : attrsList) {
   449 		for (int _i = 0; _i < attrsList.size(); _i++) {
       
   450 			final int i = _i;
   402             fBreakpoints.insertBreakpoint(
   451             fBreakpoints.insertBreakpoint(
   403                 dmc, attrs, 
   452                 dmc, attrsList.get(i), 
   404 				new DataRequestMonitor<IBreakpointDMContext>(getExecutor(), installRM) {
   453 				new DataRequestMonitor<IBreakpointDMContext>(getExecutor(), installRM) {
   405 				@Override
   454 				@Override
   406                 protected void handleCompleted() {
   455                 protected void handleCompleted() {
   407                     List<IBreakpointDMContext> list = breakpointIDs.get(breakpoint);
   456 					TargetBP targetBP = targetBPsAttempted.get(i);
   408                     if (list == null) {
       
   409                         list = new LinkedList<IBreakpointDMContext>();
       
   410                         breakpointIDs.put(breakpoint, list);
       
   411                     }
       
   412                     
       
   413                     if (isSuccess()) {
   457                     if (isSuccess()) {
   414 						// Add the breakpoint back-end mapping
   458 						// Add the breakpoint back-end mapping
   415 						list.add(getData());
   459                     	targetBP.setTargetBreakpoint(getData());
   416 					} else {
   460                     	
   417                         // TODO (bug 219841): need to add breakpoint error status tracking
   461                     	targetBPsInstalled.add(targetBP);
   418                         // in addition to fBreakpointDMContexts.
   462 					} 
   419 						installRM.setStatus(getStatus());
   463                     targetBP.setStatus(getStatus());
   420 					}
   464                     
   421 					installRM.done();
   465 					installRM.done();
   422                 }
   466                 }
   423             });
   467             });
   424 		}
   468 		}
   425 	}
   469 	}
   428      * Un-install an individual breakpoint on the back-end. For one platform
   472      * Un-install an individual breakpoint on the back-end. For one platform
   429      * breakpoint, there could be multiple corresponding back-end breakpoints.
   473      * breakpoint, there could be multiple corresponding back-end breakpoints.
   430      * 
   474      * 
   431      * @param dmc
   475      * @param dmc
   432      * @param breakpoint
   476      * @param breakpoint
   433      * @param rm
   477      * @param drm
   434      */
   478      */
   435     private void uninstallBreakpoint(final IBreakpointsTargetDMContext dmc, final IBreakpoint breakpoint, 
   479     private void uninstallBreakpoint(final IBreakpointsTargetDMContext dmc, final IBreakpoint breakpoint, 
   436         final RequestMonitor rm)
   480         final DataRequestMonitor<List<TargetBP>> drm)
   437     {
   481     {
       
   482 		// Remove the back-end breakpoints
       
   483 		final Map<IBreakpoint, List<TargetBP>> platformBPs = fPlatformBPs.get(dmc);
       
   484         if (platformBPs == null) {
       
   485             drm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid breakpoint", null)); //$NON-NLS-1$
       
   486             drm.done();
       
   487             return;
       
   488         }
       
   489 
       
   490         final List<TargetBP> bpList = platformBPs.get(breakpoint);
       
   491         assert bpList != null;
       
   492 
       
   493         // Only try to remove those targetBPs that are successfully installed.
       
   494         
   438   		// Remove completion monitor
   495   		// Remove completion monitor
   439     	CountingRequestMonitor removeRM = new CountingRequestMonitor(getExecutor(), rm) {
   496     	final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), drm) {
   440 			@Override
   497 			@Override
   441 			protected void handleCompleted() {
   498 			protected void handleCompleted() {
   442 		    	// Remove the attributes mapping 
   499 				platformBPs.remove(breakpoint);
   443 		        Map<IBreakpoint, List<Map<String, Object>>> platformBPs = fPlatformBPs.get(dmc);
   500 
   444 		        if (platformBPs == null) {
   501 		        // Complete the request monitor.
   445 		            rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
   502 		        drm.setData(bpList);
   446 		            rm.done();
   503 		        drm.done();
   447 		            return;
       
   448 		        }
       
   449 		        platformBPs.remove(breakpoint);
       
   450 
       
   451 				// Remove the back-end mapping
       
   452 		        Map<IBreakpoint, List<IBreakpointDMContext>> breakpointIDs = fBreakpointDMContexts.get(dmc);
       
   453 		        if (breakpointIDs == null) {
       
   454 		            rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid breakpoint", null)); //$NON-NLS-1$
       
   455 		            rm.done();
       
   456 		            return;
       
   457 		        }
       
   458 		        breakpointIDs.get(breakpoint).clear();
       
   459 		        breakpointIDs.remove(breakpoint);
       
   460 
       
   461 		        // Update breakpoint status
       
   462                 new Job("Breakpoint status update") { //$NON-NLS-1$
       
   463                     { setSystem(true); }
       
   464                     @Override
       
   465                     protected IStatus run(IProgressMonitor monitor) {
       
   466                         fAttributeTranslator.updateBreakpointStatus(breakpoint, EBreakpointStatusChange.EUninstalled);
       
   467                         return Status.OK_STATUS;
       
   468                     };
       
   469                 }.schedule();
       
   470 
       
   471 		        rm.done();
       
   472 			}
   504 			}
   473 		};
   505 		};
   474 
   506 
   475 		// Remove the back-end breakpoints
   507         int count = 0;
   476 		Map<IBreakpoint, List<IBreakpointDMContext>> breakpointIDs = fBreakpointDMContexts.get(dmc);
   508         for (int i = 0; i < bpList.size(); i++) {
   477         if (breakpointIDs == null) {
   509         	final TargetBP bp = bpList.get(i);
   478             rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid breakpoint", null)); //$NON-NLS-1$
   510         	if (bp.getTargetBreakpoint() != null) {
   479             rm.done();
   511         		fBreakpoints.removeBreakpoint(
   480             return;
   512         				bp.getTargetBreakpoint(), 
       
   513         				new RequestMonitor(getExecutor(), countingRm) {
       
   514         					@Override
       
   515         					protected void handleCompleted() {
       
   516         				        bp.setStatus(getStatus());
       
   517         				        bp.fAttributesDelta = bp.fAttributes;
       
   518         				        if (isSuccess()) {
       
   519             						bp.setTargetBreakpoint(null);
       
   520         				        	bp.fAttributes = null;
       
   521         				        } 
       
   522         				        countingRm.done();
       
   523         					}
       
   524         				});
       
   525         		count++;
       
   526         	} else {
       
   527         		bp.setStatus(Status.OK_STATUS);
       
   528         	}
   481         }
   529         }
   482 
   530         countingRm.setDoneCount(count);
   483         List<IBreakpointDMContext> list = breakpointIDs.get(breakpoint);
       
   484         int count = 0;
       
   485         if (list != null) {
       
   486             for (IBreakpointDMContext bp : list) {
       
   487                 fBreakpoints.removeBreakpoint(bp, removeRM);
       
   488             }
       
   489             count = list.size();
       
   490         }
       
   491         removeRM.setDoneCount(count);
       
   492     }
   531     }
   493 	
   532 	
   494 	/**
   533 	/**
   495 	 * Modify an individual breakpoint
   534 	 * Modify an individual breakpoint
   496 	 * 
   535 	 * 
   497 	 * @param context
   536 	 * @param context
   498 	 * @param breakpoint
   537 	 * @param breakpoint
   499 	 * @param attributes
   538 	 * @param attributes
   500 	 * @param rm
   539 	 * @param drm
   501 	 * @throws CoreException
   540 	 * @throws CoreException
   502 	 */
   541 	 */
   503 	private void modifyBreakpoint(final IBreakpointsTargetDMContext context, final IBreakpoint breakpoint,
   542 	private void modifyBreakpoint(final IBreakpointsTargetDMContext context, final IBreakpoint breakpoint,
   504 			final List<Map<String, Object>> newAttrsList0, final IMarkerDelta oldValues, final RequestMonitor rm)
   543 			final List<Map<String, Object>> newAttrsList, final DataRequestMonitor<List<TargetBP>> drm)
   505 	{
   544 	{
   506 	    // This method uses several lists to track the changed breakpoints:
   545 	    // This method uses several lists to track the changed breakpoints:
   507 	    // commonAttrsList - attributes which have not changed 
   546 	    // commonAttrsList - attributes which have not changed 
   508 	    // oldAttrsList - attributes for the breakpoint before the change
   547 	    // oldAttrsList - attributes for the breakpoint before the change
   509 	    // newAttrsList - attributes for the breakpoint after the change
   548 	    // newAttrsList - attributes for the breakpoint after the change
   511 	    // newBpContexts - target-side breakpoints after the change
   550 	    // newBpContexts - target-side breakpoints after the change
   512 	    // attrDeltasList - changes in the attributes for each attribute map in 
   551 	    // attrDeltasList - changes in the attributes for each attribute map in 
   513 	    //     oldAttrsList and newAttrsList
   552 	    //     oldAttrsList and newAttrsList
   514 	    
   553 	    
   515     	// Get the maps
   554     	// Get the maps
   516         final Map<IBreakpoint, List<Map<String, Object>>> platformBPs = fPlatformBPs.get(context);
   555         final Map<IBreakpoint, List<TargetBP>> platformBPs = fPlatformBPs.get(context);
   517         final Map<IBreakpoint, List<IBreakpointDMContext>> breakpointIDs = fBreakpointDMContexts.get(context);
   556         if (platformBPs == null) {
   518         if (platformBPs == null || breakpointIDs == null) {
   557             drm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
   519             rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
   558             drm.done();
   520             rm.done();
       
   521             return;
   559             return;
   522         }
   560         }
   523 
   561 
   524     	// Get the original breakpoint attributes
   562         final List<TargetBP> oldBpList = platformBPs.get(breakpoint);
   525         final List<Map<String, Object>> oldAttrsList0 = platformBPs.get(breakpoint);
   563         
   526         if (oldAttrsList0 == null) {
   564         final List<TargetBP> bpList = new ArrayList<TargetBP>(newAttrsList.size());
   527             rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid breakpoint", null)); //$NON-NLS-1$
   565         
   528             rm.done();
   566         if (oldBpList == null || oldBpList.size() == 0) { // not targetBP installed
   529             return;
   567             drm.setData(bpList);
       
   568         	drm.done();
       
   569         	return;
   530         }
   570         }
   531 
   571         
   532         // Get the list of corresponding back-end breakpoints 
   572         for (int i = 0; i < newAttrsList.size(); i++) {
   533         final List<IBreakpointDMContext> oldBpContexts = new ArrayList<IBreakpointDMContext>(breakpointIDs.get(breakpoint));
   573         	bpList.add(new TargetBP(newAttrsList.get(i)));
   534         if (oldBpContexts == null) {
       
   535             rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid breakpoint", null)); //$NON-NLS-1$
       
   536             rm.done();
       
   537             return;
       
   538         }
   574         }
   539 
       
   540         // Calculate the list of attributes maps that have not changed.  
       
   541         // Immediately add these to the list of new breakpoint contexts,
       
   542         // and remove them from further breakpoint attribute comparisons.
       
   543         final List<Map<String, Object>> commonAttrsList = getCommonAttributeMaps(newAttrsList0, oldAttrsList0);
       
   544         final List<IBreakpointDMContext> newBpContexts = new ArrayList<IBreakpointDMContext>(commonAttrsList.size());
       
   545 
       
   546         final List<Map<String, Object>> newAttrsList = new ArrayList<Map<String, Object>>(newAttrsList0);
       
   547         newAttrsList.removeAll(commonAttrsList);
       
   548         
   575         
   549         List<Map<String, Object>> oldAttrsList = new ArrayList<Map<String, Object>>(oldAttrsList0);
   576         // Create a list of attribute changes.  The length of this list will
   550         for (int i = 0; i < oldAttrsList.size(); i++) {
       
   551             if (commonAttrsList.contains(oldAttrsList.get(i))) {
       
   552                 if (oldBpContexts.size() > i) {
       
   553                     newBpContexts.add(oldBpContexts.remove(i));
       
   554                 }
       
   555             }
       
   556         }
       
   557         oldAttrsList.removeAll(commonAttrsList);
       
   558         
       
   559         // Create a list of attribute changes.  The lenghth of this list will
       
   560         // always be max(oldAttrList.size(), newAttrsList.size()), padded with
   577         // always be max(oldAttrList.size(), newAttrsList.size()), padded with
   561         // null's if oldAttrsList was longer.
   578         // null's if oldAttrsList was longer.
   562         final List<Map<String, Object>> attrDeltasList = getAttributesDeltas(oldAttrsList, newAttrsList);
   579         calcBPsAttrs(oldBpList, bpList);
   563         
   580         
   564         // Create the request monitor that will be called when all
   581         // Create the request monitor that will be called when all
   565         // modifying/inserting/removing is complete.
   582         // modifying/inserting/removing is complete.
   566         final CountingRequestMonitor countingRM = new CountingRequestMonitor(getExecutor(), rm) {
   583         final CountingRequestMonitor countingRM = new CountingRequestMonitor(getExecutor(), drm) {
   567             @Override
   584             @Override
   568             protected void handleCompleted() {
   585             protected void handleCompleted() {
   569                 // Save the new list of breakpoint contexts and attributes 
   586                 // Save the new list of target breakpoints 
   570                 breakpointIDs.put(breakpoint, newBpContexts);
   587             	platformBPs.put(breakpoint, bpList);
   571                 newAttrsList.addAll(commonAttrsList);
   588                 drm.setData(bpList);
   572                 platformBPs.put(breakpoint, newAttrsList);
   589                 drm.done();
   573                 
       
   574                 // Update breakpoint status.  updateBreakpointStatus() cannot
       
   575                 // be called on the executor thread, so we need to 
       
   576                 // use a Job.
       
   577                 new Job("Breakpoint status update") { //$NON-NLS-1$
       
   578                     { setSystem(true); }
       
   579                     @Override
       
   580                     protected IStatus run(IProgressMonitor monitor) {
       
   581                         fAttributeTranslator.updateBreakpointStatus(breakpoint, EBreakpointStatusChange.EModified);
       
   582                         return Status.OK_STATUS;
       
   583                     };
       
   584                 }.schedule();
       
   585                 
       
   586                 super.handleCompleted();
       
   587             }
   590             }
   588         };
   591         };
   589         
   592         
   590         // Set the count, if could be zero if no breakpoints have actually changed.
   593         // Set the count, if could be zero if no breakpoints have actually changed.
   591         countingRM.setDoneCount(attrDeltasList.size());
   594         int coutingRmCount = 0;
   592         
   595         
   593         // Process the changed breakpoints.
   596         // Process the changed breakpoints.
   594         for (int i = 0; i < attrDeltasList.size(); i++) {
   597         for (int _i = 0; _i < bpList.size(); _i++) {
   595             if (attrDeltasList.get(i) == null) {
   598         	final int i = _i;
       
   599         	final TargetBP bp = bpList.get(i);
       
   600             if (bp.fAttributes == null) {
   596                 // The list of new attribute maps was shorter than the old.
   601                 // The list of new attribute maps was shorter than the old.
   597                 // Remove the corresponding target-side bp.
   602                 // Remove the corresponding target-side bp.  
   598                 fBreakpoints.removeBreakpoint(oldBpContexts.get(i), countingRM);
   603             	// Note the target BP context may be null if the target
   599             } else if ( i >= oldBpContexts.size()) {
   604             	// BP failed to insert in the first place.
       
   605             	if (bp.getTargetBreakpoint() != null) {
       
   606             		fBreakpoints.removeBreakpoint(
       
   607             				bp.getTargetBreakpoint(), 
       
   608             				new RequestMonitor(getExecutor(), countingRM) {
       
   609             					@Override
       
   610             					protected void handleCompleted() {
       
   611             						bp.fStatus = getStatus();
       
   612             						countingRM.done();
       
   613             					}
       
   614             				});
       
   615                     coutingRmCount++;
       
   616             	}
       
   617             } else if ( bp.getTargetBreakpoint() == null) {
   600                 // The list of new attribute maps was longer, just insert
   618                 // The list of new attribute maps was longer, just insert
   601                 // the new breakpoint
   619                 // the new breakpoint
   602                 final Map<String, Object> attrs = newAttrsList.get(i);
   620                 final Map<String, Object> attrs = newAttrsList.get(i);
   603                 fBreakpoints.insertBreakpoint(
   621                 fBreakpoints.insertBreakpoint(
   604                     context, attrs, 
   622                     context, attrs, 
   605                     new DataRequestMonitor<IBreakpointDMContext>(getExecutor(), countingRM) {
   623                     new DataRequestMonitor<IBreakpointDMContext>(getExecutor(), countingRM) {
   606                         @Override
   624                         @Override
   607                         protected void handleSuccess() {
   625                         protected void handleCompleted() {
   608                             newBpContexts.add(getData());
   626                         	if (isSuccess()) {
       
   627                         		bp.fTargetBPContext = getData();
       
   628                         	}
       
   629                         	bp.fStatus = getStatus();
   609                             countingRM.done();
   630                             countingRM.done();
   610                         }
   631                         }
   611                     });
   632                     });
   612             } else if ( !fAttributeTranslator.canUpdateAttributes(oldBpContexts.get(i), attrDeltasList.get(i)) ) {
   633                 coutingRmCount++;
       
   634             } else if (bp.fAttributesDelta.size() == 0) { 
       
   635             	// Breakpoint attributes have not changed, only copy over the old status.
       
   636             	bp.fStatus = oldBpList.get(i).fStatus;
       
   637             } else if ( !fAttributeTranslator.canUpdateAttributes(bp.getTargetBreakpoint(), bp.fAttributesDelta) ) {
   613                 // The attribute translator tells us that the debugger cannot modify the 
   638                 // The attribute translator tells us that the debugger cannot modify the 
   614                 // breakpoint to change the given attributes.  Remove the breakpoint
   639                 // breakpoint to change the given attributes.  Remove the breakpoint
   615                 // and insert a new one.
   640                 // and insert a new one.
   616                 final Map<String, Object> attrs = newAttrsList.get(i);
   641                 RequestMonitor removeRm = new RequestMonitor(getExecutor(), countingRM) {
   617                 fBreakpoints.removeBreakpoint(
   642                     @Override
   618                     oldBpContexts.get(i), 
   643                     protected void handleCompleted() {
       
   644                     	if (isSuccess()) {
       
   645                     		bp.fTargetBPContext = null;
       
   646 	                        fBreakpoints.insertBreakpoint(
       
   647 	                            context, newAttrsList.get(i),
       
   648 	                            new DataRequestMonitor<IBreakpointDMContext>(getExecutor(), countingRM) {
       
   649 	                                @Override
       
   650 	                                protected void handleCompleted() {
       
   651 	                                    if (isSuccess()) {
       
   652 	                                        bp.fTargetBPContext = getData();
       
   653 	                                    } 
       
   654 	                                    bp.fStatus = getStatus();
       
   655 	                                    countingRM.done();
       
   656 	                                }
       
   657 	                            });
       
   658                     	} else {
       
   659                     		// Failed to remove old breakpoint, do not proceed to insert a new one
       
   660                     		// just save the error from target with the old context.
       
   661                             bp.fStatus = getStatus();
       
   662                             countingRM.done();
       
   663                     	}
       
   664                     }
       
   665                 };
       
   666 
       
   667             	fBreakpoints.removeBreakpoint(bp.getTargetBreakpoint(), removeRm);
       
   668                 coutingRmCount++;
       
   669             } else {
       
   670                 // The back end can modify the breakpoint.  Update the breakpoint with the 
       
   671                 // new attributes.
       
   672                 fBreakpoints.updateBreakpoint(
       
   673                     bp.getTargetBreakpoint(), bp.fAttributes, 
   619                     new RequestMonitor(getExecutor(), countingRM) {
   674                     new RequestMonitor(getExecutor(), countingRM) {
   620                         @Override
   675                         @Override
   621                         protected void handleCompleted() {
   676                         protected void handleCompleted() {
   622                             fBreakpoints.insertBreakpoint(
   677                             bp.fStatus = getStatus();
   623                                 context, attrs,
       
   624                                 new DataRequestMonitor<IBreakpointDMContext>(getExecutor(), countingRM) {
       
   625                                     @Override
       
   626                                     protected void handleCompleted() {
       
   627                                         if (isSuccess()) { 
       
   628                                             newBpContexts.add(getData());
       
   629                                         } else {
       
   630                                             // TODO (bug 219841): need to add breakpoint error status tracking
       
   631                                             // in addition to fBreakpointDMContexts.
       
   632                                         }
       
   633                                         countingRM.done();
       
   634                                     }
       
   635                                 });
       
   636                         }
       
   637                     });
       
   638             } else {
       
   639                 // The back end can modify the breakpoint.  Update the breakpoint with the 
       
   640                 // new attributes.
       
   641                 final IBreakpointDMContext bpCtx = oldBpContexts.get(i); 
       
   642                 fBreakpoints.updateBreakpoint(
       
   643                     oldBpContexts.get(i), newAttrsList.get(i), 
       
   644                     new RequestMonitor(getExecutor(), countingRM) {
       
   645                         @Override
       
   646                         protected void handleSuccess() {
       
   647                             newBpContexts.add(bpCtx);
       
   648                             countingRM.done();
   678                             countingRM.done();
   649                         }
   679                         }
   650                     });
   680                     });
       
   681                 coutingRmCount++;
   651             }
   682             }
   652         }
   683         }
       
   684         countingRM.setDoneCount(coutingRmCount);
   653 	} 
   685 	} 
   654 	
       
   655 	private List<Map<String, Object>> getCommonAttributeMaps(List<Map<String, Object>> array1, List<Map<String, Object>> array2) 
       
   656 	{
       
   657 	    List<Map<String, Object>> intersection = new LinkedList<Map<String, Object>>();
       
   658 	    List<Map<String, Object>> list2 = new ArrayList<Map<String, Object>>(array2);
       
   659 	    for (Map<String, Object> array1Map : array1) {
       
   660 	        if (list2.remove(array1Map)) {
       
   661 	            intersection.add(array1Map);
       
   662 	        }
       
   663 	    }
       
   664 	    return intersection;
       
   665 	}
       
   666 	
   686 	
   667 	/**
   687 	/**
   668 	 * Determine the set of modified attributes
   688 	 * Determine the set of modified attributes
   669 	 * 
   689 	 * 
   670 	 * @param oldAttributes
   690 	 * @param oldAttributes
   671 	 * @param newAttributes
   691 	 * @param newAttributes
   672 	 * @return
   692 	 * @return
   673 	 */
   693 	 */
   674 	private List<Map<String, Object>> getAttributesDeltas(List<Map<String, Object>> oldAttributesList, List<Map<String, Object>> newAttributesList) {
   694 	private void calcBPsAttrs(List<TargetBP> oldBpList, List<TargetBP> bpList) {
   675 	    List<Map<String, Object>> deltas = new ArrayList<Map<String, Object>>(oldAttributesList.size());
       
   676 	    
       
   677 	    // Go through the bp attributes common to the old and the new lists and calculate
   695 	    // Go through the bp attributes common to the old and the new lists and calculate
   678 	    // their deltas.
   696 	    // their deltas.
   679 	    for (int i = 0; i < oldAttributesList.size() && i < newAttributesList.size(); i++) {
   697 		int i = 0;
   680 	        Map<String, Object> oldAttributes = oldAttributesList.get(i); 
   698 	    for (i = 0; i < oldBpList.size() && i < bpList.size(); i++) {
   681 	        Map<String, Object> newAttributes = newAttributesList.get(i);
   699     		TargetBP newBp = bpList.get(i);
       
   700     		TargetBP oldBp = oldBpList.get(i);
       
   701     		newBp.fTargetBPContext = oldBp.getTargetBreakpoint();
       
   702 	        Map<String, Object> oldAttributes = oldBp.fAttributes; 
       
   703 	        Map<String, Object> newAttributes = newBp.fAttributes;
   682     	    
   704     	    
   683 	        Map<String, Object> delta = new HashMap<String, Object>();
   705 	        if (oldAttributes == null) {
   684     
   706 	        	// Reached a point in the old BP list where breakpoints were 
   685     		Set<String> oldKeySet = oldAttributes.keySet();		
   707 	        	// removed.  Break out of the loop.
   686     		Set<String> newKeySet = newAttributes.keySet();
   708 	        	break;
   687     
   709 	        }
   688     		Set<String> commonKeys  = new HashSet<String>(newKeySet); commonKeys.retainAll(oldKeySet);
   710 	        
   689     		Set<String> addedKeys   = new HashSet<String>(newKeySet); addedKeys.removeAll(oldKeySet);
   711     		bpList.get(i).fAttributesDelta = getAttributesDelta(oldAttributes, newAttributes);
   690     		Set<String> removedKeys = new HashSet<String>(oldKeySet); removedKeys.removeAll(newKeySet);
       
   691     
       
   692     		// Add the modified attributes
       
   693     		for (String key : commonKeys) {
       
   694     			if (!(oldAttributes.get(key).equals(newAttributes.get(key))))
       
   695     				delta.put(key, newAttributes.get(key));
       
   696     		}
       
   697     
       
   698     		// Add the new attributes
       
   699     		for (String key : addedKeys) {
       
   700     			delta.put(key, newAttributes.get(key));
       
   701     		}
       
   702     
       
   703     		// Remove the deleted attributes
       
   704     		for (String key : removedKeys) {
       
   705     			delta.put(key, null);
       
   706     		}
       
   707     		deltas.add(delta);
       
   708 	    } 
   712 	    } 
   709 	    
   713 	    
   710 	    // Add all the new attributes as deltas
   714 	    // Add all the new attributes as deltas
   711 	    for (int i = deltas.size(); i < newAttributesList.size(); i++) {
   715 	    for (; i < bpList.size(); i++) {
   712 	        deltas.add(newAttributesList.get(i));
   716 	    	TargetBP newBP = bpList.get(i); 
       
   717 	        newBP.fAttributesDelta =  newBP.fAttributes;
   713 	    }
   718 	    }
   714 	    
   719 	    
   715         // For any old attribute Maps that were removed, insert a null value in the deltas list.
   720 	    // For breakpoints that were removed create TargetBP entry with a 
   716         for (int i = deltas.size(); i < oldAttributesList.size(); i++) {
   721 	    // null set of attributes
   717             deltas.add(null);
   722 	    for (; i < oldBpList.size(); i++) {
   718         }
   723 	    	TargetBP oldBp = oldBpList.get(i);
   719 	    
   724 	    	if (oldBp.fAttributes == null) {
   720 	    return deltas;
   725 	    		// Guard against old removed breakpoints
       
   726 	    		break;
       
   727 	    	}
       
   728 	    	TargetBP newBp = new TargetBP(null);
       
   729 	    	newBp.fTargetBPContext = oldBp.getTargetBreakpoint();
       
   730 	    	newBp.fAttributesDelta = oldBpList.get(i).fAttributes;
       
   731 	    	bpList.add(newBp);
       
   732 	    }	    
   721 	}
   733 	}
   722 
   734 
   723     ///////////////////////////////////////////////////////////////////////////
   735     ///////////////////////////////////////////////////////////////////////////
   724     // IBreakpointManagerListener implementation
   736     // IBreakpointManagerListener implementation
   725     ///////////////////////////////////////////////////////////////////////////
   737     ///////////////////////////////////////////////////////////////////////////
   726 
   738 
   727 	public void breakpointManagerEnablementChanged(boolean enabled) {
   739 	public void breakpointManagerEnablementChanged(boolean enabled) {
   728 		for (IBreakpoint breakpoint : fBreakpointManager.getBreakpoints()) {
   740 		Map<String, Object> platformAttrDelta = new HashMap<String, Object>(1);
   729 		    breakpointChanged(breakpoint, null);
   741 		platformAttrDelta.put(IBreakpoint.ENABLED, enabled);
   730 		}
   742 		
       
   743 		Map<IBreakpoint, Map<String, Object>> bp2DeltaMap = new HashMap<IBreakpoint, Map<String, Object>>(); 
       
   744 		for (IBreakpoint bp : fBreakpointManager.getBreakpoints()) {
       
   745 			if (! fAttributeTranslator.supportsBreakpoint(bp))
       
   746 				continue;
       
   747 
       
   748 			bp2DeltaMap.put(bp, platformAttrDelta);
       
   749 		}
       
   750 		
       
   751 		doBreakpointsChanged(bp2DeltaMap);
   731 	}
   752 	}
   732 
   753 
   733 	@ThreadSafe
   754 	@ThreadSafe
   734 	public void breakpointAdded(final IBreakpoint breakpoint) {
   755 	public void breakpointsAdded(final IBreakpoint[] bps) {
   735 		if (fAttributeTranslator.supportsBreakpoint(breakpoint)) {
   756 		doBreakpointsAdded(bps, null, null);
   736 			try {
   757 	}
   737                 // Retrieve the breakpoint attributes
   758 	
   738         		final List<Map<String, Object>> attrsArray = 
   759 	@SuppressWarnings("unchecked")
   739                     fAttributeTranslator.getBreakpointAttributes(breakpoint, fBreakpointManager.isEnabled());
   760 	private void doBreakpointsAdded(final IBreakpoint[] bps, final IBreakpointsTargetDMContext bpsTargetDmc, final RequestMonitor rm) {
   740 
   761 		final List<IBreakpoint> bpCandidates = new ArrayList<IBreakpoint>(bps.length);
   741                 getExecutor().execute(new DsfRunnable() {
   762 		
   742 					public void run() {
   763 		for (int i = 0; i < bps.length; i++) {
   743 					    //TODO pp: need to track pending requests 
   764 			IBreakpoint bp = bps[i];
   744 					    
   765 			
   745 						final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), null) {
   766 			if (fAttributeTranslator.supportsBreakpoint(bp)) {
   746 							@Override
   767 				try {
   747 							protected void handleError() {
   768 					if (fAttributeTranslator2 != null) {
   748 								if (getStatus().getSeverity() == IStatus.ERROR) {
   769 						if (bp.getMarker() == null)
   749 									DsfPlugin.getDefault().getLog().log(getStatus());
   770 							continue;
       
   771 						
       
   772 						// if the breakpoint is not enabled, ask translator2 if it can set (and manage)
       
   773 						// disabled breakpoint itself. If not, just bail out.
       
   774 						//
       
   775 						Map<String, Object> platformAttrs = bp.getMarker().getAttributes();
       
   776 						
       
   777 						if (! (Boolean)platformAttrs.get(IBreakpoint.ENABLED) || ! fBreakpointManager.isEnabled()) {
       
   778 							Map<String, Object> platformAttr = new HashMap<String, Object>(1);
       
   779 							platformAttr.put(IBreakpoint.ENABLED, Boolean.FALSE);
       
   780 							Map<String, Object> targetAttr = fAttributeTranslator2.convertAttributeDelta(platformAttr);
       
   781 							if (! fAttributeTranslator2.canUpdateAttributes(null, targetAttr)) {
       
   782 								// bail out.
       
   783 								continue;
       
   784 							}
       
   785 						}
       
   786 					}
       
   787 					
       
   788 					bpCandidates.add(bp);
       
   789 				} catch (CoreException e) {
       
   790 					DsfPlugin.getDefault().getLog().log(e.getStatus());
       
   791 				}
       
   792 			}
       
   793 		}
       
   794 		
       
   795 		// Nothing to do
       
   796 		if (bpCandidates.isEmpty()) {
       
   797 			if (rm != null) {
       
   798 				rm.done();
       
   799 			}
       
   800 			return;
       
   801 		}
       
   802 				
       
   803 		try {
       
   804             getExecutor().execute(new DsfRunnable() {
       
   805 				public void run() {
       
   806 					final Map<IBreakpoint, Map<IBreakpointsTargetDMContext, ITargetBreakpointInfo[]>> eventBPs =  
       
   807 						new HashMap<IBreakpoint, Map<IBreakpointsTargetDMContext, ITargetBreakpointInfo[]>>(bpCandidates.size(), 1);
       
   808 					
       
   809 	                CountingRequestMonitor processPendingCountingRm = new CountingRequestMonitor(getExecutor(), rm) {
       
   810 		                    @Override
       
   811 		                    protected void handleCompleted() {
       
   812 		                    	processPendingRequests();
       
   813 		                    	fireUpdateBreakpointsStatus(eventBPs, BreakpointEventType.ADDED);
       
   814 		                        super.handleCompleted();
       
   815 		                    }
       
   816 		                };	            	
       
   817 	                int processPendingCountingRmCount = 0;
       
   818 	            	
       
   819 	            	for (final IBreakpoint breakpoint : bpCandidates) {
       
   820 	            		final Map<IBreakpointsTargetDMContext, ITargetBreakpointInfo[]> targetBPs = 
       
   821 	            			new HashMap<IBreakpointsTargetDMContext, ITargetBreakpointInfo[]>(fPlatformBPs.size(), 1);
       
   822 	            		eventBPs.put(breakpoint, targetBPs);	
       
   823 	            			
       
   824 						if (fRunningEvents.contains(breakpoint)) {
       
   825 							PendingEventInfo pendingEvent = new PendingEventInfo(BreakpointEventType.ADDED, bpsTargetDmc, processPendingCountingRm);
       
   826 							processPendingCountingRmCount++;
       
   827 							updatePendingRequest(breakpoint, pendingEvent);
       
   828 							continue;
       
   829 						}
       
   830 		                // Mark the breakpoint as being updated and go
       
   831 		                fRunningEvents.add(breakpoint);
       
   832 
       
   833 	            		final CountingRequestMonitor bpTargetsCountingRm = new CountingRequestMonitor(getExecutor(), processPendingCountingRm) {
       
   834 								@Override
       
   835 								protected void handleCompleted() {
       
   836 			                    	// Indicate that the running event has completed
       
   837 			                    	fRunningEvents.remove(breakpoint);
       
   838 			                    	super.handleCompleted();
   750 								}
   839 								}
   751 							}
   840 							};
   752 						};
   841 						int bpTargetsCountingRmCount = 0;
   753 						countingRm.setDoneCount(fPlatformBPs.size());
   842 						processPendingCountingRmCount++;
   754 
   843 	
       
   844 						
   755 						// Install the breakpoint in all the execution contexts
   845 						// Install the breakpoint in all the execution contexts
   756 						for (final IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) {
   846 						for (final IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) {
   757 						    installBreakpoint(dmc, breakpoint, attrsArray, new RequestMonitor(getExecutor(), countingRm));
   847 							if (bpsTargetDmc != null && !bpsTargetDmc.equals(dmc)) {
       
   848 								continue;
       
   849 							}
       
   850 							
       
   851 			                // Now ask lower level to set the bp.
       
   852 							//
       
   853 							if (fAttributeTranslator2 != null) {
       
   854 								fAttributeTranslator2.getTargetBreakpointAttributes(dmc, breakpoint, fBreakpointManager.isEnabled(),
       
   855 										new DataRequestMonitor<List<Map<String,Object>>>(getExecutor(), bpTargetsCountingRm){
       
   856 											@Override
       
   857 											protected void handleSuccess() {
       
   858 												installBreakpoint(
       
   859 											    		dmc, breakpoint, getData(), 
       
   860 											    		new DataRequestMonitor<List<TargetBP>>(getExecutor(), bpTargetsCountingRm) {
       
   861 											    			@Override
       
   862 															protected void handleSuccess() {
       
   863 											    				targetBPs.put(dmc, getData().toArray(new ITargetBreakpointInfo[getData().size()]));
       
   864 											    				super.handleSuccess();
       
   865 											    			};
       
   866 											    		});
       
   867 											}});
       
   868 							}
       
   869 							else {	// Old way
       
   870 								List<Map<String, Object>> attrsArray;
       
   871 								try {
       
   872 									attrsArray = fAttributeTranslator.getBreakpointAttributes(breakpoint, fBreakpointManager.isEnabled());
       
   873 								} catch (CoreException e) {
       
   874 									attrsArray = new ArrayList<Map<String, Object>>();
       
   875 									DsfPlugin.getDefault().getLog().log(e.getStatus());
       
   876 								}
       
   877 				        		
       
   878 								installBreakpoint(
       
   879 						    		dmc, breakpoint, attrsArray, 
       
   880 						    		new DataRequestMonitor<List<TargetBP>>(getExecutor(), bpTargetsCountingRm) {
       
   881 						    			@Override
       
   882 										protected void handleSuccess() {
       
   883 						    				targetBPs.put(dmc, getData().toArray(new ITargetBreakpointInfo[getData().size()]));
       
   884 						    				super.handleSuccess();
       
   885 						    			};
       
   886 						    		});
       
   887 							}
       
   888 							
       
   889 							bpTargetsCountingRmCount++;
   758 						}
   890 						}
   759 					}
   891 						bpTargetsCountingRm.setDoneCount(bpTargetsCountingRmCount);
   760 				});
   892 	            	}
   761 			} catch (CoreException e) {
   893 	            	processPendingCountingRm.setDoneCount(processPendingCountingRmCount);	            	
   762                 DsfPlugin.getDefault().getLog().log(e.getStatus());
   894 				}
   763 			} catch (RejectedExecutionException e) {
   895 			});
       
   896 		} catch (RejectedExecutionException e) {
       
   897 			IStatus status = new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Request for monitor: '" + toString() + "' resulted in a rejected execution exception.", e);//$NON-NLS-1$ //$NON-NLS-2$
       
   898 			if (rm != null) {
       
   899 				rm.setStatus(status);
       
   900 				rm.done();
       
   901 			} else {
       
   902 				DsfPlugin.getDefault().getLog().log(status); 
   764 			}
   903 			}
   765 		}
   904 		}
   766 
       
   767 	}
   905 	}
   768 	
   906 	
   769     ///////////////////////////////////////////////////////////////////////////
   907     ///////////////////////////////////////////////////////////////////////////
   770     // IBreakpointListener implementation
   908     // IBreakpointListener implementation
   771     ///////////////////////////////////////////////////////////////////////////
   909     ///////////////////////////////////////////////////////////////////////////
   772 
   910 
   773 	public void breakpointChanged(final IBreakpoint breakpoint, final IMarkerDelta delta) {
   911 	@SuppressWarnings("unchecked")
   774 		if (fAttributeTranslator.supportsBreakpoint(breakpoint)) {
   912 	public void breakpointsChanged(IBreakpoint[] bps, IMarkerDelta[] deltas) {
       
   913 		Map<IBreakpoint, Map<String, Object>> bp2DeltaMap = new HashMap<IBreakpoint, Map<String, Object>>(); 
       
   914 		for (int i = 0; i < bps.length; i++) {
       
   915 			IBreakpoint bp = bps[i];
       
   916 			
       
   917 			if (deltas[i] == null)
       
   918 				continue;
       
   919 			
       
   920 			if (bp.getMarker() == null)
       
   921 				continue;
       
   922 			
       
   923 			if (! fAttributeTranslator.supportsBreakpoint(bp))
       
   924 				continue;
       
   925 
   775 			try {
   926 			try {
   776                 // Retrieve the breakpoint attributes
   927 				Map<String, Object> oldAttrs = deltas[i].getAttributes();
   777         		final List<Map<String, Object>> attrsArray = 
   928 				Map<String, Object> newAttrs = bp.getMarker().getAttributes();
   778         		    fAttributeTranslator.getBreakpointAttributes(breakpoint, fBreakpointManager.isEnabled());
   929 				
   779 
   930 				Map<String, Object> platformAttrDelta = getAttributesDelta(oldAttrs, newAttrs);
   780 				// Modify the breakpoint in all the target contexts
   931 				
   781 		        getExecutor().execute( new DsfRunnable() { 
   932 				if (platformAttrDelta.size() == 0) // no change. possible when user cancels breakpoint properties dialog.
   782 		            public void run() {
   933 					continue;
   783 
   934 
   784 		            	// If the breakpoint is currently being updated, queue the request and exit
   935 				bp2DeltaMap.put(bp, platformAttrDelta);
   785 		            	if (fPendingRequests.contains(breakpoint)) {
   936 			} catch (CoreException e) {
   786 		            		fPendingBreakpoints.add(breakpoint);
   937 				DsfPlugin.getDefault().getLog().log(e.getStatus());
   787 							return;
   938 			}
       
   939 		}
       
   940 		
       
   941 		doBreakpointsChanged(bp2DeltaMap);
       
   942 	}
       
   943 	
       
   944 	/**
       
   945 	 * 
       
   946 	 * @param bp2DeltaMap - pairs of (breakpoint, attrDelta), where attrDelta contains changed 
       
   947 	 * and new attributes for the breakpoint.  
       
   948 	 */
       
   949 	private void doBreakpointsChanged(Map<IBreakpoint, Map<String, Object>> bp2DeltaMap) {
       
   950 
       
   951 		final Map<IBreakpoint, List<Map<String, Object>>> bpsAttrs = 
       
   952 			new HashMap<IBreakpoint, List<Map<String, Object>>>(bp2DeltaMap.size() * 4/3);
       
   953 
       
   954 		for (IBreakpoint bp : bp2DeltaMap.keySet()) {
       
   955 			try {
       
   956 				Map<String, Object> platformAttrDelta = bp2DeltaMap.get(bp);
       
   957 				
       
   958 				if (fAttributeTranslator2 != null) {
       
   959 					Map<String, Object> targetAttrDelta = fAttributeTranslator2.convertAttributeDelta(platformAttrDelta);
       
   960 		
       
   961 					if (! fAttributeTranslator2.canUpdateAttributes(null, targetAttrDelta)) {
       
   962 						// DSF client cannot handle at least one of the attribute change, just remove
       
   963 						// old target BPs and install new ones.
       
   964 						final IBreakpoint[] platformBPs = new IBreakpoint[] {bp};
       
   965 						
       
   966 						if (platformAttrDelta.containsKey(IBreakpoint.ENABLED)) {
       
   967 							if ((Boolean)platformAttrDelta.get(IBreakpoint.ENABLED))
       
   968 								// platform BP changed from disabled to enabled
       
   969 								doBreakpointsAdded(platformBPs, null, null);
       
   970 							else
       
   971 								doBreakpointsRemoved(platformBPs, null, null);
       
   972 						}
       
   973 						else {
       
   974 							// other attribute change, remove old and install new.
       
   975 							doBreakpointsRemoved(platformBPs, null, new RequestMonitor(getExecutor(), null) {
       
   976 								@Override
       
   977 								protected void handleSuccess() {
       
   978 									doBreakpointsAdded(platformBPs, null, null);
       
   979 								}});
       
   980 						}
       
   981 					}
       
   982 					else 
       
   983 						updateBreakpoint(bp, targetAttrDelta);
       
   984 				}
       
   985 				else { // old way
       
   986 					
       
   987 	                // Retrieve the breakpoint attributes
       
   988 	        		List<Map<String, Object>> attrsArray = 
       
   989 	        		    fAttributeTranslator.getBreakpointAttributes(bp, fBreakpointManager.isEnabled());
       
   990 	        		
       
   991 	        		bpsAttrs.put(bp, attrsArray);
       
   992 				}
       
   993 			} catch (CoreException e) {
       
   994 				DsfPlugin.getDefault().getLog().log(e.getStatus());
       
   995 			}
       
   996 		}
       
   997 		
       
   998 		if (bpsAttrs.isEmpty()) return; // nothing to do
       
   999 		
       
  1000 		try {
       
  1001 			// Modify the breakpoint in all the target contexts
       
  1002 	        getExecutor().execute( new DsfRunnable() { 
       
  1003 	            public void run() {
       
  1004 					final Map<IBreakpoint, Map<IBreakpointsTargetDMContext, ITargetBreakpointInfo[]>> eventBPs =  
       
  1005 						new HashMap<IBreakpoint, Map<IBreakpointsTargetDMContext, ITargetBreakpointInfo[]>>(bpsAttrs.size(), 1);
       
  1006 
       
  1007 					CountingRequestMonitor processPendingCountingRm = new CountingRequestMonitor(getExecutor(), null) {
       
  1008 	                    @Override
       
  1009 	                    protected void handleCompleted() {
       
  1010 	                    	processPendingRequests();
       
  1011 	                    	fireUpdateBreakpointsStatus(eventBPs, BreakpointEventType.MODIFIED);
       
  1012 	                    }
       
  1013 	                };	            	
       
  1014 	                int processPendingCountingRmCount = 0;
       
  1015 	            	
       
  1016 	            	for (final IBreakpoint breakpoint : bpsAttrs.keySet()) {
       
  1017 	            		final Map<IBreakpointsTargetDMContext, ITargetBreakpointInfo[]> targetBPs = 
       
  1018 	            			new HashMap<IBreakpointsTargetDMContext, ITargetBreakpointInfo[]>(fPlatformBPs.size(), 1);
       
  1019 	            		eventBPs.put(breakpoint, targetBPs);	
       
  1020 
       
  1021 	            		// If the breakpoint is currently being updated, queue the request and exit
       
  1022 		            	if (fRunningEvents.contains(breakpoint)) {
       
  1023 		            		updatePendingRequest(breakpoint, new PendingEventInfo(BreakpointEventType.MODIFIED, null, null));
       
  1024 							continue;
   788 		            	}
  1025 		            	}
   789 
  1026 		            	
   790 		                // Keep track of the updates
  1027 		                // Keep track of the updates
   791 		                final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), null) {
  1028 		                CountingRequestMonitor bpTargetsCountingRm = 
   792 		                    @Override
  1029 		                	new CountingRequestMonitor(getExecutor(), processPendingCountingRm) {
   793 		                    protected void handleCompleted() {
  1030 			                    @Override
   794 
  1031 			                    protected void handleCompleted() {
   795 		                    	if (!isSuccess()) {
  1032 			                    	// Indicate that the running event has completed
   796 			                        if (getStatus().getSeverity() == IStatus.ERROR) {
  1033 			                    	fRunningEvents.remove(breakpoint);
   797 			                            DsfPlugin.getDefault().getLog().log(getStatus());
  1034 			                    	super.handleCompleted();
   798 			                        }
  1035 			                    }
   799 		                    	}
  1036 			                };
   800 
  1037 			            processPendingCountingRmCount++;
   801 		                    	// Indicate that the pending request has completed
  1038 		                bpTargetsCountingRm.setDoneCount(fPlatformBPs.size());
   802 		                    	fPendingRequests.remove(breakpoint);
  1039 	
   803 
       
   804 		                    	// Process the next pending update for this breakpoint
       
   805 		                    	if (fPendingBreakpoints.contains(breakpoint)) {
       
   806 		                    		fPendingBreakpoints.remove(breakpoint);
       
   807 		                    		new Job("Deferred breakpoint changed job") { //$NON-NLS-1$
       
   808 		                                { setSystem(true); }
       
   809 		                                @Override
       
   810                                         protected IStatus run(IProgressMonitor monitor) {
       
   811 		                                    breakpointChanged(breakpoint, delta);
       
   812 		                                    return Status.OK_STATUS;
       
   813 		                                };
       
   814 		                    		}.schedule();
       
   815 		                    	}
       
   816 		                    }
       
   817 		                };
       
   818 		                countingRm.setDoneCount(fPlatformBPs.size());
       
   819 
       
   820 		                // Mark the breakpoint as being updated and go
  1040 		                // Mark the breakpoint as being updated and go
   821 		                fPendingRequests.add(breakpoint);
  1041 		                fRunningEvents.add(breakpoint);
   822 		                
  1042 		                
   823 		                // Modify the breakpoint in all the execution contexts
  1043 		                // Modify the breakpoint in all the execution contexts
   824 		                for (final IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) {
  1044 		                for (final IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) {
   825 		                    modifyBreakpoint(dmc, breakpoint, attrsArray, delta, new RequestMonitor(getExecutor(), countingRm));
  1045 		                    modifyBreakpoint(
       
  1046 		                    		dmc, breakpoint, bpsAttrs.get(breakpoint), 
       
  1047 		                    		new DataRequestMonitor<List<TargetBP>>(getExecutor(), bpTargetsCountingRm) {
       
  1048 						    			@Override
       
  1049 										protected void handleSuccess() {
       
  1050 						    				targetBPs.put(dmc, getData().toArray(new ITargetBreakpointInfo[getData().size()]));
       
  1051 						    				super.handleSuccess();
       
  1052 						    			};
       
  1053 		                    		});
   826 		                }
  1054 		                }
   827 		            }
  1055 	            	}
   828 		        });
  1056 	            	processPendingCountingRm.setDoneCount(processPendingCountingRmCount);
   829 		    } catch (CoreException e) {
  1057 	            }
   830                 DsfPlugin.getDefault().getLog().log(e.getStatus());
  1058 	        });
   831 		    } catch (RejectedExecutionException e) {
  1059 	    } catch (RejectedExecutionException e) {
   832 		    }
  1060 			DsfPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Request for monitor: '" + toString() + "' resulted in a rejected execution exception.", e)); //$NON-NLS-1$ //$NON-NLS-2$
   833 		}
  1061 	    }
   834 
  1062 	}
   835 	}
  1063 
   836 
  1064 	/**
   837 	public void breakpointRemoved(final IBreakpoint breakpoint, IMarkerDelta delta) {
  1065 	 * For the given platform BP, update all its target BPs with the given attribute change.
   838 
  1066 	 * 
   839     	if (fAttributeTranslator.supportsBreakpoint(breakpoint)) {
  1067 	 * @param bp
   840             try {
  1068 	 * @param targetAttrDelta - target attribute change.  
   841                 getExecutor().execute(new DsfRunnable() {
  1069 	 */
   842                 	public void run() {
  1070 	private void updateBreakpoint(final IBreakpoint bp, final Map<String, Object> targetAttrDelta) {
   843                         //TODO pp: need to track pending requests 
  1071         getExecutor().execute(new DsfRunnable() {
   844 
  1072         	public void run() {
   845                 		CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), null) {
  1073 				for (IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) {
   846                 			@Override
  1074 					List<TargetBP> targetBPs = fPlatformBPs.get(dmc).get(bp);
   847                 			protected void handleError() {
  1075 					if (targetBPs != null) {
   848                 				if (getStatus().getSeverity() == IStatus.ERROR) {
  1076 						for (TargetBP tbp : targetBPs) {
   849                 					DsfPlugin.getDefault().getLog().log(getStatus());
  1077 							// this must be an installed bp.
   850                 				}
  1078 							assert (tbp.getTargetBreakpoint() != null);
   851                 			}
  1079 							
   852                 		};
  1080 							fBreakpoints.updateBreakpoint(tbp.getTargetBreakpoint(), targetAttrDelta, new RequestMonitor(getExecutor(), null) {});
   853                 		countingRm.setDoneCount(fPlatformBPs.size());
  1081 						}
   854 
  1082 					}
   855                 		// Remove the breakpoint in all the execution contexts
  1083 				}
   856                 		for (IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) {
  1084         	}});
   857                 			if (fPlatformBPs.get(dmc).remove(breakpoint) != null) {
  1085 	}
   858                 				uninstallBreakpoint(dmc, breakpoint, countingRm);
  1086 
   859                 			} else {
  1087 	public void breakpointsRemoved(final IBreakpoint[] bps, IMarkerDelta delta[]) {
   860                 				// Breakpoint not installed for given context, do nothing.
  1088 		doBreakpointsRemoved(bps, null, null);
   861                 			}
  1089 	}
   862                 		}
  1090 	
   863                 	}
  1091 	public void doBreakpointsRemoved(final IBreakpoint[] bps, final IBreakpointsTargetDMContext bpsTargetDmc, final RequestMonitor rm) {
   864                 });
  1092 	
   865             } catch (RejectedExecutionException e) {
  1093 		final List<IBreakpoint> bpCandidates = new ArrayList<IBreakpoint>();
   866             }
  1094 		
   867     	}
  1095 		for (int i = 0; i < bps.length; i++) {
   868 		
  1096 			IBreakpoint bp = bps[i];
   869 	}
  1097 			
       
  1098 			if (fAttributeTranslator.supportsBreakpoint(bp)) {
       
  1099 				if (bpsTargetDmc == null)
       
  1100 					bpCandidates.add(bp);
       
  1101 				else if (fPlatformBPs.get(bpsTargetDmc).containsKey(bp))	// target BPs are installed in the context 
       
  1102 					bpCandidates.add(bp);
       
  1103 			}
       
  1104 		}
       
  1105 		
       
  1106 		if (bpCandidates.isEmpty()) { // nothing to do
       
  1107 			if (rm != null)
       
  1108 				rm.done();
       
  1109 			return;
       
  1110 		}
       
  1111 		
       
  1112 		try {
       
  1113 	        getExecutor().execute(new DsfRunnable() {
       
  1114 	        	public void run() {
       
  1115 					final Map<IBreakpoint, Map<IBreakpointsTargetDMContext, ITargetBreakpointInfo[]>> eventBPs =  
       
  1116 						new HashMap<IBreakpoint, Map<IBreakpointsTargetDMContext, ITargetBreakpointInfo[]>>(bpCandidates.size(), 1);
       
  1117 
       
  1118 					CountingRequestMonitor processPendingCountingRm = new CountingRequestMonitor(getExecutor(), rm) {
       
  1119             			@Override
       
  1120             			protected void handleCompleted() {
       
  1121             				processPendingRequests();
       
  1122 	                    	fireUpdateBreakpointsStatus(eventBPs, BreakpointEventType.REMOVED);
       
  1123             				super.handleCompleted();
       
  1124             			}
       
  1125             		};
       
  1126             		int processPendingCountingRmCount = 0;
       
  1127             		
       
  1128 					for (final IBreakpoint breakpoint : bpCandidates) {
       
  1129 	            		final Map<IBreakpointsTargetDMContext, ITargetBreakpointInfo[]> targetBPs = 
       
  1130 	            			new HashMap<IBreakpointsTargetDMContext, ITargetBreakpointInfo[]>(fPlatformBPs.size(), 1);
       
  1131 	            		eventBPs.put(breakpoint, targetBPs);	
       
  1132 				
       
  1133 		            	// If the breakpoint is currently being updated, queue the request and exit
       
  1134 		            	if (fRunningEvents.contains(breakpoint)) {
       
  1135 		            		PendingEventInfo pendingEvent = new PendingEventInfo(BreakpointEventType.REMOVED, bpsTargetDmc, processPendingCountingRm);
       
  1136             				processPendingCountingRmCount++;
       
  1137 		            		updatePendingRequest(breakpoint, pendingEvent);
       
  1138 							continue;
       
  1139 		            	}
       
  1140 		            	
       
  1141 	            		CountingRequestMonitor bpTargetDmcCRM = new CountingRequestMonitor(getExecutor(), processPendingCountingRm) {
       
  1142 							@Override
       
  1143 							protected void handleCompleted() {
       
  1144 		                    	// Indicate that the running event has completed
       
  1145 		                    	fRunningEvents.remove(breakpoint);
       
  1146 		                    	super.handleCompleted();
       
  1147 							}
       
  1148 						};
       
  1149 						processPendingCountingRmCount++;
       
  1150 						int bpTargetDmcCRMCount = 0;
       
  1151 
       
  1152 	            		// Remove the breakpoint in all the execution contexts
       
  1153 	            		for (final IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) {
       
  1154 	            			if (bpsTargetDmc != null && !bpsTargetDmc.equals(dmc)) {
       
  1155 	            				continue;
       
  1156 	            			}
       
  1157 	            			
       
  1158 	            			if (fPlatformBPs.get(dmc).containsKey(breakpoint)) {		// there are targetBPs installed 
       
  1159 	            				uninstallBreakpoint(
       
  1160 	            						dmc, breakpoint,
       
  1161 	            						new DataRequestMonitor<List<TargetBP>>(getExecutor(), bpTargetDmcCRM) {
       
  1162 							    			@Override
       
  1163 											protected void handleSuccess() {
       
  1164 							    				targetBPs.put(dmc, getData().toArray(new ITargetBreakpointInfo[getData().size()]));
       
  1165 							    				super.handleSuccess();
       
  1166 							    			};
       
  1167 	            						});
       
  1168 	            				bpTargetDmcCRMCount++;
       
  1169 	            			} else {
       
  1170 	            				// Breakpoint not installed for given context, do nothing.
       
  1171 	            			}
       
  1172 	            		}
       
  1173 	            		bpTargetDmcCRM.setDoneCount(bpTargetDmcCRMCount);
       
  1174 					}
       
  1175 					
       
  1176 					processPendingCountingRm.setDoneCount(processPendingCountingRmCount);
       
  1177 	        	}
       
  1178 	        });
       
  1179         } catch (RejectedExecutionException e) {
       
  1180 			IStatus status = new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Request for monitor: '" + toString() + "' resulted in a rejected execution exception.", e);//$NON-NLS-1$ //$NON-NLS-2$
       
  1181 			if (rm != null) {
       
  1182 				rm.setStatus(status);
       
  1183 				rm.done();
       
  1184 			} else {
       
  1185 				DsfPlugin.getDefault().getLog().log(status); 
       
  1186 			}
       
  1187         }
       
  1188 	}
       
  1189 	
       
  1190 	private void updatePendingRequest(IBreakpoint breakpoint, PendingEventInfo pendingEvent) {
       
  1191 		LinkedList<PendingEventInfo> pendingEventsList = fPendingEvents.get(breakpoint);
       
  1192 		if (pendingEventsList == null) {
       
  1193 			pendingEventsList = new LinkedList<PendingEventInfo>();
       
  1194 			fPendingEvents.put(breakpoint, pendingEventsList);
       
  1195 		}
       
  1196 		if (pendingEventsList.size() > 0 &&
       
  1197 				pendingEventsList.getLast().fEventType == BreakpointEventType.MODIFIED) {
       
  1198 			pendingEventsList.removeLast();
       
  1199 		}
       
  1200 		pendingEventsList.add(pendingEvent);
       
  1201 	}
       
  1202 	
       
  1203 	private void processPendingRequests() {
       
  1204 		if (fPendingEvents.isEmpty()) return;  // Nothing to do
       
  1205 		
       
  1206 		final List<PendingEventInfo> modifyBPs = new ArrayList<PendingEventInfo>(1);
       
  1207 		final Map<IBreakpointsTargetDMContext, List<PendingEventInfo>> addBPs =
       
  1208 			new HashMap<IBreakpointsTargetDMContext, List<PendingEventInfo>>(1);
       
  1209 		final Map<IBreakpointsTargetDMContext, List<PendingEventInfo>> removeBPs =
       
  1210 			new HashMap<IBreakpointsTargetDMContext, List<PendingEventInfo>>(1);
       
  1211 		
       
  1212 		// Make a copy to avoid java.util.ConcurrentModificationException.
       
  1213 		Set<IBreakpoint> bpsInPendingEvents = new HashSet<IBreakpoint>(fPendingEvents.keySet()); 
       
  1214 //		for (IBreakpoint bp : fPendingEvents.keySet()) {
       
  1215 		for (IBreakpoint bp : bpsInPendingEvents) {
       
  1216 	    	// Process the next pending update for this breakpoint
       
  1217 	    	if (!fRunningEvents.contains(bp)) {
       
  1218 	    		LinkedList<PendingEventInfo> eventInfoList = fPendingEvents.get(bp);
       
  1219 	    		PendingEventInfo eventInfo = eventInfoList.removeFirst();
       
  1220 	    		if (eventInfoList.isEmpty()) {
       
  1221 	    			fPendingEvents.remove(bp);
       
  1222 	    		}
       
  1223 	    		BreakpointEventType type = eventInfo.fEventType;
       
  1224 	    		if (type.equals(BreakpointEventType.MODIFIED)) {
       
  1225 	    			modifyBPs.add(eventInfo);
       
  1226 	    		} else if (type.equals(BreakpointEventType.ADDED)){
       
  1227 	    			List<PendingEventInfo> addList = addBPs.get(eventInfo.fBPsTargetDmc);
       
  1228 	    			if (addList == null) {
       
  1229 	    				addList = new ArrayList<PendingEventInfo>(1);
       
  1230 	    				addBPs.put(eventInfo.fBPsTargetDmc, addList);
       
  1231 	    			}
       
  1232 	    			addList.add(eventInfo);
       
  1233 	    		} else if (type.equals(BreakpointEventType.REMOVED)){
       
  1234 	    			List<PendingEventInfo> removeList = removeBPs.get(eventInfo.fBPsTargetDmc);
       
  1235 	    			if (removeList == null) {
       
  1236 	    				removeList = new ArrayList<PendingEventInfo>(1);
       
  1237 	    				removeBPs.put(eventInfo.fBPsTargetDmc, removeList);
       
  1238 	    			}
       
  1239 	    			removeList.add(eventInfo);
       
  1240 	    		}
       
  1241 	    	}
       
  1242 		}
       
  1243 
       
  1244 		if (modifyBPs.size() != 0 || removeBPs.size() != 0) {
       
  1245 			new Job("Deferred breakpoint changed job") { //$NON-NLS-1$
       
  1246 	            { setSystem(true); }
       
  1247 	            @Override
       
  1248 	            protected IStatus run(IProgressMonitor monitor) {
       
  1249 	            	if (modifyBPs.size() != 0) {
       
  1250 	            		breakpointsChanged(modifyBPs.toArray(new IBreakpoint[modifyBPs.size()]), null);	            		
       
  1251 	            	}
       
  1252 	            	if (addBPs.size() != 0) {
       
  1253 	            		for (Map.Entry<IBreakpointsTargetDMContext, List<PendingEventInfo>> addBPsEntry : addBPs.entrySet()) {
       
  1254 	            			IBreakpointsTargetDMContext bpsTargetDmc = addBPsEntry.getKey();
       
  1255 	            			final List<PendingEventInfo> addBpList = addBPsEntry.getValue();
       
  1256 	            			RequestMonitor rm = new RequestMonitor(ImmediateExecutor.getInstance(), null) {
       
  1257 	            				@Override
       
  1258 								protected void handleCompleted() {
       
  1259 	            					for (PendingEventInfo eventInfo : addBpList) {
       
  1260 	            						if (eventInfo.fRequestMonitor != null) {
       
  1261 	            							eventInfo.fRequestMonitor.done();
       
  1262 	            						}
       
  1263 	            					}
       
  1264 	            				};
       
  1265 	            			};
       
  1266 		            		doBreakpointsAdded(addBpList.toArray(new IBreakpoint[addBpList.size()]), bpsTargetDmc, rm);	            			            			
       
  1267 	            		}
       
  1268 	            	} 
       
  1269 	            	if (removeBPs.size() != 0) {
       
  1270 	            		for (Map.Entry<IBreakpointsTargetDMContext, List<PendingEventInfo>> removeBPsEntry : removeBPs.entrySet()) {
       
  1271 	            			IBreakpointsTargetDMContext bpsTargetDmc = removeBPsEntry.getKey();
       
  1272 	            			final List<PendingEventInfo> removeBpList = removeBPsEntry.getValue();
       
  1273 	            			RequestMonitor rm = new RequestMonitor(ImmediateExecutor.getInstance(), null) {
       
  1274 	            				@Override
       
  1275 								protected void handleCompleted() {
       
  1276 	            					for (PendingEventInfo eventInfo : removeBpList) {
       
  1277 	            						if (eventInfo.fRequestMonitor != null) {
       
  1278 	            							eventInfo.fRequestMonitor.done();
       
  1279 	            						}
       
  1280 	            					}
       
  1281 	            				};
       
  1282 	            			};
       
  1283 		            		doBreakpointsRemoved(removeBpList.toArray(new IBreakpoint[removeBpList.size()]), bpsTargetDmc, rm);	            			            			
       
  1284 	            		}
       
  1285 	            	} 
       
  1286 	                return Status.OK_STATUS;
       
  1287 	            };
       
  1288 			}.schedule();
       
  1289 		}
       
  1290 	}
       
  1291 	
       
  1292 	private void fireUpdateBreakpointsStatus(final Map<IBreakpoint, Map<IBreakpointsTargetDMContext, ITargetBreakpointInfo[]>> eventBPs, final BreakpointEventType eventType) {
       
  1293         // Update breakpoint status
       
  1294         new Job("Breakpoint status update") { //$NON-NLS-1$
       
  1295             { setSystem(true); }
       
  1296             @Override
       
  1297             protected IStatus run(IProgressMonitor monitor) {
       
  1298             	for (IBreakpoint bp : eventBPs.keySet()) {
       
  1299             		fAttributeTranslator.updateBreakpointStatus(bp);
       
  1300             	}
       
  1301                 
       
  1302                 if (fAttributeTranslator2 != null) {
       
  1303                 	fAttributeTranslator2.updateBreakpointsStatus(eventBPs, eventType);
       
  1304                 }
       
  1305 
       
  1306                 return Status.OK_STATUS;
       
  1307             };
       
  1308         }.schedule();
       
  1309 		
       
  1310 	}
       
  1311 
       
  1312     /**
       
  1313      * Determine the set of modified attributes.
       
  1314      * 
       
  1315      * @param oldAttributes old map of attributes.
       
  1316      * @param newAttributes new map of attributes.
       
  1317      * @return new and changed attribute in the new map. May be empty indicating the two maps are equal.
       
  1318      */
       
  1319     private Map<String, Object> getAttributesDelta(Map<String, Object> oldAttributes, Map<String, Object> newAttributes) {
       
  1320 
       
  1321         Map<String, Object> delta = new HashMap<String,Object>();
       
  1322 
       
  1323         Set<String> oldKeySet = oldAttributes.keySet();
       
  1324         Set<String> newKeySet = newAttributes.keySet();
       
  1325 
       
  1326         Set<String> commonKeys  = new HashSet<String>(newKeySet); commonKeys.retainAll(oldKeySet);
       
  1327         Set<String> addedKeys   = new HashSet<String>(newKeySet); addedKeys.removeAll(oldKeySet);
       
  1328         Set<String> removedKeys = new HashSet<String>(oldKeySet); removedKeys.removeAll(newKeySet);
       
  1329 
       
  1330         // Add the modified attributes
       
  1331         for (String key : commonKeys) {
       
  1332             if (!(oldAttributes.get(key).equals(newAttributes.get(key))))
       
  1333                 delta.put(key, newAttributes.get(key));
       
  1334         }
       
  1335 
       
  1336         // Add the new attributes
       
  1337         for (String key : addedKeys) {
       
  1338             delta.put(key, newAttributes.get(key));
       
  1339         }
       
  1340 
       
  1341         // Remove the deleted attributes
       
  1342         for (String key : removedKeys) {
       
  1343             delta.put(key, null);
       
  1344         }
       
  1345 
       
  1346         return delta;
       
  1347     }
   870 }
  1348 }