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 } |
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 } |