/******************************************************************************* * Copyright (c) 2007, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.debug.tests.ui; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.model.IThread; import org.eclipse.debug.internal.core.IInternalDebugCoreConstants; import org.eclipse.debug.internal.ui.DebugUIPlugin; import org.eclipse.debug.internal.ui.InstructionPointerAnnotation; import org.eclipse.debug.internal.ui.InstructionPointerManager; import org.eclipse.debug.internal.ui.viewers.model.InternalTreeModelViewer; import org.eclipse.debug.ui.IDebugUIConstants; import org.eclipse.debug.ui.IDebugView; import org.eclipse.jdt.debug.core.IJavaDebugTarget; import org.eclipse.jdt.debug.core.IJavaLineBreakpoint; import org.eclipse.jdt.debug.core.IJavaStackFrame; import org.eclipse.jdt.debug.core.IJavaThread; import org.eclipse.jdt.debug.tests.AbstractDebugTest; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.AnnotationModelEvent; import org.eclipse.jface.text.source.IAnnotationModel; import org.eclipse.jface.text.source.IAnnotationModelListener; import org.eclipse.jface.text.source.IAnnotationModelListenerExtension; import org.eclipse.jface.viewers.TreePath; import org.eclipse.jface.viewers.TreeSelection; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorReference; import org.eclipse.ui.IPartListener2; import org.eclipse.ui.IPerspectiveDescriptor; import org.eclipse.ui.IPerspectiveListener2; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPartReference; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.ui.texteditor.ITextEditor; /** * Tests functionality of the InstructionPointerManager. * The tests are not currently part of the automated suite because they produce * transient failures that could not be tracked down. * * @since 3.3 * @see InstructionPointerManager */ public class InstructionPointerManagerTests extends AbstractDebugTest { private Object fLock = new Object(); private Annotation fAddedAnnotation = null; private Annotation fRemovedAnnotation = null; private MyPerspectiveListener fPerspectiveListener; private MyAnnotationListener fAnnotationListener; private IPartListener2 fPartListener; private Set<IAnnotationModel> fAnnotationModelsWithListeners = new HashSet<IAnnotationModel>(); private static final String typeThreadStack = "org.eclipse.debug.tests.targets.ThreadStack"; private static final String typeClassOne = "org.eclipse.debug.tests.targets.ClassOne"; private static final String typeClassTwo = "org.eclipse.debug.tests.targets.ClassTwo"; private IJavaDebugTarget target1; private IJavaDebugTarget target2; private IJavaThread thread1; private IJavaThread thread2; private IJavaThread thread3; private IJavaThread thread4; public InstructionPointerManagerTests(String name) { super(name); } public void testManagerWithEditorReuse() throws Exception{ boolean restore = DebugUIPlugin.getDefault().getPreferenceStore().getBoolean(IDebugUIConstants.PREF_REUSE_EDITOR); DebugUIPlugin.getDefault().getPreferenceStore().setValue(IDebugUIConstants.PREF_REUSE_EDITOR, true); try{ addAndRemoveAnnotations(new int[]{1,2,1,2,1,0,1,1}, new int[]{1,1,1,1,1,0,1,1}); } finally { System.out.println("Cleanup"); if (target1 != null){ terminateAndRemove(target1); } if (target2 != null){ terminateAndRemove(target2); } Iterator<IAnnotationModel> annModels = fAnnotationModelsWithListeners.iterator(); while (annModels.hasNext()) { IAnnotationModel currentModel = annModels.next(); currentModel.removeAnnotationModelListener(getAnnotationListener()); } removeAllBreakpoints(); DebugUIPlugin.getDefault().getPreferenceStore().setValue(IDebugUIConstants.PREF_REUSE_EDITOR, restore); Runnable cleanup = new Runnable() { @Override public void run() { IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); activeWorkbenchWindow.removePerspectiveListener(getPerspectiveListener()); } }; DebugUIPlugin.getStandardDisplay().asyncExec(cleanup); } } public void testManagerWithNoEditorReuse() throws Exception{ boolean restore = DebugUIPlugin.getDefault().getPreferenceStore().getBoolean(IDebugUIConstants.PREF_REUSE_EDITOR); DebugUIPlugin.getDefault().getPreferenceStore().setValue(IDebugUIConstants.PREF_REUSE_EDITOR, false); try{ addAndRemoveAnnotations(new int[]{1,2,3,4,5,3,2,1}, new int[]{1,1,2,2,3,2,2,1}); } finally { System.out.println("Cleanup"); if (target1 != null){ terminateAndRemove(target1); } if (target2 != null){ terminateAndRemove(target2); } Iterator<IAnnotationModel> annModels = fAnnotationModelsWithListeners.iterator(); while (annModels.hasNext()) { IAnnotationModel currentModel = annModels.next(); currentModel.removeAnnotationModelListener(getAnnotationListener()); } removeAllBreakpoints(); DebugUIPlugin.getDefault().getPreferenceStore().setValue(IDebugUIConstants.PREF_REUSE_EDITOR, restore); Runnable cleanup = new Runnable() { @Override public void run() { IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); activeWorkbenchWindow.removePerspectiveListener(getPerspectiveListener()); } }; DebugUIPlugin.getStandardDisplay().asyncExec(cleanup); } } /** * Tests the ability of the manager to update it's set and mapping as * annotations are added and removed. * * First, all editors are closed and the manager is checked to ensure there are 0 IPCs. * * <p>Next, annotations are created as follows:<br> * (numbers in brackets correspond to index of expected IPC and Mapping counts checked) * <pre> * Target1 - Thread1 - IPC1 - ClassOne - Editor1 (line 20) [0] * - Thread2 - IPC2 - ClassOne - Editor1 (line 20) [1] * - IPC3 - ThreadStack - Editor2 (line 28) [2] * * Target2 - Thread3 - IPC4 - ThreadStack - Editor2 (line 41) [3] * - Thread4 - IPC5 - ClassTwo - Editor3 (line 24) [4] * </pre> * </p> * <p>They are then removed as follows:<br> * (numbers in brackets correspond to index of expected IPC and Mapping counts checked) * <ol> * <li>Target2 is terminated [5]</li> * <li>Thread1 is resumed [6]</li> * <li>Editor2 is closed [7]</li> * <li>All editors are closed, closing Editor1, No IPCs should exist</li> * </ol> * </p> * @param expectedIPCCounts array of expected values for IPC count at each step as marked above, length must be 8 * @param expectedMappingCounts array of expected values for editor mapping count at each step as marked above, length must be 8 * @throws Exception */ private void addAndRemoveAnnotations(int[] expectedIPCCounts, int[] expectedMappingCounts) throws Exception{ assertEquals("Incorrect number of expected counts", 8, expectedIPCCounts.length); assertEquals("Incorrect number of expected counts", 8, expectedMappingCounts.length); // Close all editors Runnable closeAll = new Runnable() { @Override public void run() { IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); activeWorkbenchWindow.getActivePage().closeAllEditors(false); activeWorkbenchWindow.addPerspectiveListener(getPerspectiveListener()); } }; DebugUIPlugin.getStandardDisplay().syncExec(closeAll); assertEquals("Instruction pointer count was incorrect", 0, InstructionPointerManager.getDefault().getInstructionPointerCount()); assertEquals("Editor mapping count was incorrect", 0, InstructionPointerManager.getDefault().getEditorMappingCount()); // ADD ANNOTATIONS // Launch a target creating two threads, both suspend in ClassOne, one will automatically be selected IJavaLineBreakpoint breakpoint = createLineBreakpoint(20, typeClassOne); fAddedAnnotation = null; getPerspectiveListener().setTitle(typeClassOne); thread1 = launchAndSuspend(typeThreadStack); target1 = (IJavaDebugTarget)thread1.getDebugTarget(); assertNotNull("Target was not launched.",target1); assertNotNull("Target was not launched.",thread1); waitForAnnotationToBeAdded(); assertEquals("Instruction pointer count was incorrect", expectedIPCCounts[0], InstructionPointerManager.getDefault().getInstructionPointerCount()); assertEquals("Editor mapping count was incorrect", expectedMappingCounts[0], InstructionPointerManager.getDefault().getEditorMappingCount()); // Find and select the top stack frame of the other thread Runnable openParent = new Runnable() { @Override public void run() { IDebugView debugView = (IDebugView)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().findView("org.eclipse.debug.ui.DebugView"); Object[] newSegments = new Object[4]; newSegments[0] = target1.getLaunch(); newSegments[1] = target1; try{ IThread[] threads = ((IJavaDebugTarget)newSegments[1]).getThreads(); for (int i = 0; i < threads.length; i++) { if (threads[i].isSuspended() && !threads[i].equals(thread1)){ thread2 = (IJavaThread)threads[i]; newSegments[2] = threads[i]; newSegments[3] = threads[i].getTopStackFrame(); } } ((InternalTreeModelViewer)debugView.getViewer()).setSelection(new TreeSelection(new TreePath(newSegments)), true, true); } catch (DebugException e){ fail("Exception: " + e.getMessage()); } } }; fAddedAnnotation = null; getPerspectiveListener().setTitle(typeClassOne); DebugUIPlugin.getStandardDisplay().syncExec(openParent); waitForAnnotationToBeAdded(); assertNotNull("Thread not selected",thread2); assertEquals("Instruction pointer count was incorrect", expectedIPCCounts[1], InstructionPointerManager.getDefault().getInstructionPointerCount()); assertEquals("Editor mapping count was incorrect", expectedMappingCounts[1], InstructionPointerManager.getDefault().getEditorMappingCount()); // Select the same stack frame and make sure IPC count doesn't change Runnable selectSameStackFrame = new Runnable() { @Override public void run() { IDebugView debugView = (IDebugView)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().findView("org.eclipse.debug.ui.DebugView"); Object[] newSegments = new Object[4]; newSegments[0] = target1.getLaunch(); newSegments[1] = target1; newSegments[2] = thread2; try { newSegments[3] = thread2.getTopStackFrame(); } catch (DebugException e) { fail("Exception: " + e.getMessage()); } ((InternalTreeModelViewer)debugView.getViewer()).setSelection(new TreeSelection(new TreePath(newSegments)), true, true); } }; fAddedAnnotation = null; getPerspectiveListener().setTitle(typeClassOne); DebugUIPlugin.getStandardDisplay().syncExec(selectSameStackFrame); waitForAnnotationToBeAdded(); assertEquals("Instruction pointer count was incorrect", expectedIPCCounts[1], InstructionPointerManager.getDefault().getInstructionPointerCount()); assertEquals("Editor mapping count was incorrect", expectedMappingCounts[1], InstructionPointerManager.getDefault().getEditorMappingCount()); // Select the next stack frame in the same thread Runnable selectSecondStackFrame = new Runnable() { @Override public void run() { IDebugView debugView = (IDebugView)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().findView("org.eclipse.debug.ui.DebugView"); Object[] newSegments = new Object[4]; newSegments[0] = target1.getLaunch(); newSegments[1] = target1; newSegments[2] = thread2; try{ newSegments[3] = thread2.getStackFrames()[1]; // Select the next stack frame } catch (DebugException e){ fail("Exception: " + e.getMessage()); } ((InternalTreeModelViewer)debugView.getViewer()).setSelection(new TreeSelection(new TreePath(newSegments)), true, true); } }; fAddedAnnotation = null; getPerspectiveListener().setTitle(typeThreadStack); DebugUIPlugin.getStandardDisplay().syncExec(selectSecondStackFrame); waitForAnnotationToBeAdded(); // Failure here, reuse, expected 1 but was 2, also with no reuse, expected 3 but was 2 assertEquals("Instruction pointer count was incorrect", expectedIPCCounts[2], InstructionPointerManager.getDefault().getInstructionPointerCount()); assertEquals("Editor mapping count was incorrect", expectedMappingCounts[2], InstructionPointerManager.getDefault().getEditorMappingCount()); // Remove the breakpoint from before and create new ones, start a new target breakpoint.delete(); createLineBreakpoint(41, typeThreadStack); createLineBreakpoint(24, typeClassTwo); target2 = (IJavaDebugTarget)launchAndSuspend(typeThreadStack).getDebugTarget(); assertNotNull("Target was not launched", target2); assertEquals("Instruction pointer count was incorrect", expectedIPCCounts[2], InstructionPointerManager.getDefault().getInstructionPointerCount()); assertEquals("Editor mapping count was incorrect", expectedMappingCounts[2], InstructionPointerManager.getDefault().getEditorMappingCount()); // Select the stack frame from the new debug target displaying ThreadStack Runnable openOtherDebugTarget = new Runnable() { @Override public void run() { IDebugView debugView = (IDebugView)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().findView("org.eclipse.debug.ui.DebugView"); ILaunch[] launches = DebugPlugin.getDefault().getLaunchManager().getLaunches(); Object[] newSegments = new Object[4]; for (int i = 0; i < launches.length; i++) { if (target2.equals(launches[i].getDebugTarget())){ newSegments[0] = launches[i]; newSegments[1] = target2; try{ IThread[] threads = target2.getThreads(); for (int j = 0; j < threads.length; j++) { if (threads[j].isSuspended()){ if (typeThreadStack.equals(((IJavaStackFrame)threads[j].getTopStackFrame()).getDeclaringTypeName())){ thread3 = (IJavaThread)threads[j]; newSegments[2] = threads[j]; newSegments[3] = threads[j].getTopStackFrame(); break; } } } } catch (DebugException e){ fail("Exception: " + e.getMessage()); } break; } } ((InternalTreeModelViewer)debugView.getViewer()).setSelection(new TreeSelection(new TreePath(newSegments)), true, true); } }; fAddedAnnotation = null; getPerspectiveListener().setTitle(typeThreadStack); DebugUIPlugin.getStandardDisplay().syncExec(openOtherDebugTarget); assertNotNull("Thread was not selected",thread3); waitForAnnotationToBeAdded(); assertEquals("Instruction pointer count was incorrect", expectedIPCCounts[3], InstructionPointerManager.getDefault().getInstructionPointerCount()); assertEquals("Editor mapping count was incorrect", expectedMappingCounts[3], InstructionPointerManager.getDefault().getEditorMappingCount()); // Select the other thread from the new target displaying ClassTwo Runnable openOtherThread = new Runnable() { @Override public void run() { IDebugView debugView = (IDebugView)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().findView("org.eclipse.debug.ui.DebugView"); Object[] newSegments = new Object[4]; newSegments[0] = target2.getLaunch(); newSegments[1] = target2; try{ IThread[] threads = target2.getThreads(); for (int i = 0; i < threads.length; i++) { if (threads[i].isSuspended() && !threads[i].equals(thread3)){ thread4 = (IJavaThread)threads[i]; newSegments[2] = threads[i]; newSegments[3] = threads[i].getTopStackFrame(); } } ((InternalTreeModelViewer)debugView.getViewer()).setSelection(new TreeSelection(new TreePath(newSegments)), true, true); } catch (DebugException e){ fail("Exception: " + e.getMessage()); } } }; fAddedAnnotation = null; getPerspectiveListener().setTitle(typeClassTwo); DebugUIPlugin.getStandardDisplay().syncExec(openOtherThread); assertNotNull("Thread was not selected",thread4); waitForAnnotationToBeAdded(); assertEquals("Instruction pointer count was incorrect", expectedIPCCounts[4], InstructionPointerManager.getDefault().getInstructionPointerCount()); assertEquals("Editor mapping count was incorrect", expectedMappingCounts[4], InstructionPointerManager.getDefault().getEditorMappingCount()); // REMOVE ANNOTATIONS // Remove target2 fRemovedAnnotation = null; target2.terminate(); waitForAnnotationToBeRemoved(); assertEquals("Instruction pointer count was incorrect", expectedIPCCounts[5], InstructionPointerManager.getDefault().getInstructionPointerCount()); assertEquals("Editor mapping count was incorrect", expectedMappingCounts[5], InstructionPointerManager.getDefault().getEditorMappingCount()); // TODO Selection of the other target does not occur automatically. This functionality may change and will break this test. // Resume thread1 fRemovedAnnotation = null; thread1.resume(); waitForAnnotationToBeRemoved(); assertEquals("Instruction pointer count was incorrect", expectedIPCCounts[6], InstructionPointerManager.getDefault().getInstructionPointerCount()); assertEquals("Editor mapping count was incorrect", expectedMappingCounts[6], InstructionPointerManager.getDefault().getEditorMappingCount()); // Close the editor displaying ThreadStack.java if it is open Runnable closeEditor2 = new Runnable() { @Override public void run() { IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); IEditorReference[] editors = activeWorkbenchWindow.getActivePage().getEditorReferences(); for (int i = 0; i < editors.length; i++) { if (editors[i].getTitle().equals("ThreadStack.java")){ activeWorkbenchWindow.getActivePage().closeEditors(new IEditorReference[]{editors[i]},false); fRemovedAnnotation = null; // Clear the removed annotation so the test waits for the annotation to be removed break; } } } }; // fRemovedAnnotation is used here to check if the editor has been found and closed successfully. It is set to a annotation object, and will only be reset to null (causing the wait to occur) if the editor is closed. fRemovedAnnotation = new Annotation(true); DebugUIPlugin.getStandardDisplay().syncExec(closeEditor2); waitForAnnotationToBeRemoved(); assertEquals("Instruction pointer count was incorrect", expectedIPCCounts[7], InstructionPointerManager.getDefault().getInstructionPointerCount()); assertEquals("Editor mapping count was incorrect", expectedMappingCounts[7], InstructionPointerManager.getDefault().getEditorMappingCount()); // Close all editors Runnable closeAllEditors = new Runnable() { @Override public void run() { IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); activeWorkbenchWindow.getActivePage().closeAllEditors(false); } }; fRemovedAnnotation = null; DebugUIPlugin.getStandardDisplay().syncExec(closeAllEditors); waitForAnnotationToBeRemoved(); assertEquals("Instruction pointer count was incorrect", 0, InstructionPointerManager.getDefault().getInstructionPointerCount()); assertEquals("Editor mapping count was incorrect", 0, InstructionPointerManager.getDefault().getEditorMappingCount()); } protected MyPerspectiveListener getPerspectiveListener(){ if (fPerspectiveListener == null){ fPerspectiveListener = new MyPerspectiveListener(); return fPerspectiveListener; } return fPerspectiveListener; } protected MyAnnotationListener getAnnotationListener(){ if (fAnnotationListener == null){ fAnnotationListener = new MyAnnotationListener(); return fAnnotationListener; } return fAnnotationListener; } private IPartListener2 getPartListener(){ if (fPartListener == null){ fPartListener = new MyPartListener(); return fPartListener; } return fPartListener; } private void waitForAnnotationToBeAdded() throws Exception{ synchronized (fLock) { if (fAddedAnnotation == null) { fLock.wait(5000); } } assertNotNull("Annotation was not added properly"); // Synchronize with the UI thread so we know that the annotations have finished Runnable runner = new Runnable(){ @Override public void run() { // Do nothing, just waiting for the UI thread to finish annotations } }; DebugUIPlugin.getStandardDisplay().syncExec(runner); } private void waitForAnnotationToBeRemoved() throws Exception{ synchronized (fLock) { if (fRemovedAnnotation == null) { fLock.wait(5000); } } assertNotNull("Annotation was not removed properly"); // Synchronize with the UI thread so we know that the annotations have finished Runnable runner = new Runnable(){ @Override public void run() { // Do nothing, just waiting for the UI thread to finish annotations } }; DebugUIPlugin.getStandardDisplay().syncExec(runner); } class MyPerspectiveListener implements IPerspectiveListener2 { private String fTypeName = IInternalDebugCoreConstants.EMPTY_STRING; private String fTitle = IInternalDebugCoreConstants.EMPTY_STRING; @Override public void perspectiveActivated(IWorkbenchPage page, IPerspectiveDescriptor perspective) {} @Override public void perspectiveChanged(IWorkbenchPage page, IPerspectiveDescriptor perspective, String changeId) {} /* (non-Javadoc) * @see org.eclipse.ui.IPerspectiveListener2#perspectiveChanged(org.eclipse.ui.IWorkbenchPage, org.eclipse.ui.IPerspectiveDescriptor, org.eclipse.ui.IWorkbenchPartReference, java.lang.String) */ @Override public void perspectiveChanged(IWorkbenchPage page, IPerspectiveDescriptor perspective, IWorkbenchPartReference partRef, String changeId) { if (partRef.getTitle().equals(fTitle) && changeId == IWorkbenchPage.CHANGE_EDITOR_OPEN) { IEditorPart editor = (IEditorPart) partRef.getPart(true); if (editor instanceof ITextEditor){ IDocumentProvider docProvider = ((ITextEditor)editor).getDocumentProvider(); IEditorInput editorInput = editor.getEditorInput(); // If there is no annotation model, there's nothing more to do IAnnotationModel annModel = docProvider.getAnnotationModel(editorInput); if (annModel == null) { fail("Could not get the annotation model"); } annModel.addAnnotationModelListener(getAnnotationListener()); fAnnotationModelsWithListeners.add(annModel); } else { fail("Editor was not a text editor"); } partRef.getPage().addPartListener(getPartListener()); } if (changeId == IWorkbenchPage.CHANGE_EDITOR_CLOSE) { if (partRef.getPage().getEditorReferences().length == 0){ partRef.getPage().removePartListener(getPartListener()); } } } public void setTitle(String typeName){ fTypeName = typeName; int index = typeName.lastIndexOf('.'); if (index >= 0){ fTitle = typeName.substring(index+1) + ".java"; } else { fTitle = typeName + ".java"; } } public String getTypeName(){ return fTypeName; } } class MyPartListener implements IPartListener2{ @Override public void partActivated(IWorkbenchPartReference partRef) {} @Override public void partDeactivated(IWorkbenchPartReference partRef) {} @Override public void partHidden(IWorkbenchPartReference partRef) {} @Override public void partOpened(IWorkbenchPartReference partRef) {} @Override public void partVisible(IWorkbenchPartReference partRef) {} @Override public void partBroughtToTop(IWorkbenchPartReference partRef) {} @Override public void partClosed(IWorkbenchPartReference partRef) {} /* (non-Javadoc) * @see org.eclipse.ui.IPartListener2#partInputChanged(org.eclipse.ui.IWorkbenchPartReference) */ @Override public void partInputChanged(IWorkbenchPartReference partRef) { IEditorPart editor = (IEditorPart) partRef.getPart(true); if (editor instanceof ITextEditor){ IDocumentProvider docProvider = ((ITextEditor)editor).getDocumentProvider(); IEditorInput editorInput = editor.getEditorInput(); // If there is no annotation model, there's nothing more to do IAnnotationModel annModel = docProvider.getAnnotationModel(editorInput); if (annModel == null) { fail("Could not get the annotation model"); } annModel.addAnnotationModelListener(getAnnotationListener()); fAnnotationModelsWithListeners.add(annModel); } else { fail("Editor was not a text editor"); } } } class MyAnnotationListener implements IAnnotationModelListener, IAnnotationModelListenerExtension{ @Override public void modelChanged(AnnotationModelEvent event) { Annotation[] annotations = event.getAddedAnnotations(); for (int i = 0; i < annotations.length; i++) { if (annotations[i] instanceof InstructionPointerAnnotation){ synchronized (fLock) { fAddedAnnotation = annotations[i]; fLock.notifyAll(); System.out.println("Annotation added to editor: " + fAddedAnnotation + " (" + this + ")" + event.getAnnotationModel()); } } } annotations = event.getRemovedAnnotations(); for (int i = 0; i < annotations.length; i++) { if (annotations[i] instanceof InstructionPointerAnnotation){ synchronized (fLock) { fRemovedAnnotation = annotations[i]; fLock.notifyAll(); } } } } @Override public void modelChanged(IAnnotationModel model) {} } }