Implementation for  Bug 317352 -  [ui] callin marker creator fires too many jobs
diff --git a/plugins/org.eclipse.objectteams.otdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/callinmarkers/CallinMarkerCreator2.java b/plugins/org.eclipse.objectteams.otdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/callinmarkers/CallinMarkerCreator2.java
index 5b938e7..2300b77 100644
--- a/plugins/org.eclipse.objectteams.otdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/callinmarkers/CallinMarkerCreator2.java
+++ b/plugins/org.eclipse.objectteams.otdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/callinmarkers/CallinMarkerCreator2.java
@@ -183,17 +183,32 @@
 			invalidateBase(cachedBaseClass);
 		}
 	}
-	void invalidateBase(IJavaElement baseClass) {
-		this.m_cachedMarkersForJavaElements.remove(baseClass);
-		try {
-			IJavaElement cu = baseClass.getAncestor(IJavaElement.COMPILATION_UNIT);
-			if (cu != null) {
-				IResource resource = cu.getCorrespondingResource();
-				if (resource != null)
-					this.m_cachedMarkersForResources.remove(resource);
+	public void invalidateBase(IJavaElement baseClass) {
+		invalidateBaseCU(baseClass.getAncestor(IJavaElement.COMPILATION_UNIT));
+	}
+
+	/** API for {@link RoleBindingChangedListener}. */
+	public void invalidateBaseCU(IJavaElement cu) {
+		if (cu != null) {
+			this.m_cachedMarkersForJavaElements.remove(cu);
+			IResource resource = null;
+			try {
+				resource = cu.getCorrespondingResource();
+			} catch (JavaModelException e) {
+				// ignore, just check for null below
 			}
-		} catch (JavaModelException e) {
-			// cannot uncache missing resource
+			if (resource != null)
+				this.m_cachedMarkersForResources.remove(resource);
+			if (this.fActiveEditor != null && this.fActiveEditor instanceof IEditorPart) {
+				IEditorPart editor = (IEditorPart) this.fActiveEditor;
+				if (editor.getEditorInput() instanceof IFileEditorInput) {
+					IResource editorResource = ((IFileEditorInput)editor.getEditorInput()).getFile();
+					if (editorResource != null && !isCreatingMarkersFor(editorResource) && editorResource.equals(cu.getResource())) {
+						IStatusLineManager statusLine = editor.getEditorSite().getActionBars().getStatusLineManager();
+						updateCallinMarkers(new ResourceMarkable(editorResource), statusLine);
+					}
+				}
+			}
 		}
 	}
 	
@@ -348,7 +363,7 @@
 			    Map<IMember, Set<IType>> playedByMap = searchPlayedByBindings(allTypes,
 			    															  new IJavaProject[]{member.getJavaProject()}, 
 			    															  new MySubProgressMonitor(monitor, 20));
-			    if (playedByMap == null)
+			    if (playedByMap == null || playedByMap.isEmpty())
 			    	return;
 
 			    // collect all roles w/ subroles for use as search scope:
@@ -492,6 +507,10 @@
 
 					members.addAll(Arrays.asList(type.getMethods()));
 					members.addAll(Arrays.asList(type.getFields()));
+					IOTType otType = OTModelManager.getOTElement(type);
+					if (otType != null && otType.isRole())
+						for (IMethodMapping mapping : ((IRoleType)otType).getMethodMappings(IRoleType.CALLOUTS))
+							members.add(mapping);
 					// handle all inner types
 					IType[] memberTypes = type.getTypes();
 					for (int idx = 0; idx < memberTypes.length; idx++)
diff --git a/plugins/org.eclipse.objectteams.otdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/callinmarkers/CallinMarkerRemover.java b/plugins/org.eclipse.objectteams.otdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/callinmarkers/CallinMarkerRemover.java
index 70d6085..00ae68e 100644
--- a/plugins/org.eclipse.objectteams.otdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/callinmarkers/CallinMarkerRemover.java
+++ b/plugins/org.eclipse.objectteams.otdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/callinmarkers/CallinMarkerRemover.java
@@ -20,6 +20,7 @@
  **********************************************************************/
 package org.eclipse.objectteams.otdt.internal.ui.callinmarkers;
 
+import org.eclipse.core.internal.resources.ResourceException;
 import org.eclipse.core.resources.IMarker;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IWorkspaceRoot;
@@ -42,7 +43,7 @@
 				resource.deleteMarkers(id, true, IResource.DEPTH_INFINITE);
     }
     
-	public static synchronized void removeCallinMarker(IMember member, IResource resource)
+	public static void removeCallinMarker(IMember member, IResource resource)
     {
         // we need to pass the resource, as the method might already be removed and hence would
         // not be able to give us a resource.
@@ -61,6 +62,10 @@
                 if (marker != null)
                     marker.delete();
             }
+	        catch (ResourceException ex) {
+	        	// tree might be locked for modifications
+	        	// FIXME(SH): handle this case, currently we just ignore this situation
+	        }
             catch (CoreException ex)
             {
     			OTDTUIPlugin.getExceptionHandler().
@@ -73,7 +78,7 @@
      * Finds the marker attached to the given method.
      * Note: may return null if nothing found.
      */
-    private static synchronized IMarker getCallinMarker(IMember baseElement, String markerKind, IResource resource) throws JavaModelException, CoreException
+    private static IMarker getCallinMarker(IMember baseElement, String markerKind, IResource resource) throws JavaModelException, CoreException
     {
         IMarker[] markers = resource.findMarkers(markerKind, true, IResource.DEPTH_INFINITE);
 
diff --git a/plugins/org.eclipse.objectteams.otdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/callinmarkers/JavaElementMarkable.java b/plugins/org.eclipse.objectteams.otdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/callinmarkers/JavaElementMarkable.java
index 03ea62f..2e6106a 100644
--- a/plugins/org.eclipse.objectteams.otdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/callinmarkers/JavaElementMarkable.java
+++ b/plugins/org.eclipse.objectteams.otdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/callinmarkers/JavaElementMarkable.java
@@ -41,6 +41,9 @@
 public class JavaElementMarkable extends AbstractMarkable {
 	IJavaElement fJavaElement;
 
+	/**
+	 * @param javaElement should actually be an IClassFile (otherwise use ResourceMarkable on the IFile (source file))
+	 */
 	public JavaElementMarkable(IJavaElement javaElement) {
 		this.fJavaElement = javaElement;
 	}
diff --git a/plugins/org.eclipse.objectteams.otdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/callinmarkers/RoleBindingChangedListener.java b/plugins/org.eclipse.objectteams.otdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/callinmarkers/RoleBindingChangedListener.java
index 016f94d..7f2f91d 100644
--- a/plugins/org.eclipse.objectteams.otdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/callinmarkers/RoleBindingChangedListener.java
+++ b/plugins/org.eclipse.objectteams.otdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/callinmarkers/RoleBindingChangedListener.java
@@ -20,8 +20,12 @@
  **********************************************************************/
 package org.eclipse.objectteams.otdt.internal.ui.callinmarkers;
 
+import java.util.HashSet;
+import java.util.Set;
+
 import org.eclipse.core.resources.IResource;
 import org.eclipse.jdt.core.ElementChangedEvent;
+import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IElementChangedListener;
 import org.eclipse.jdt.core.IField;
 import org.eclipse.jdt.core.IJavaElement;
@@ -59,16 +63,22 @@
 {
 	public void elementChanged(ElementChangedEvent event)
 	{
-        updateCallinMarkers(new IJavaElementDelta[] { event.getDelta() });        
+		Set<ICompilationUnit> invalidatedCUs = new HashSet<ICompilationUnit>();
+        updateCallinMarkers(new IJavaElementDelta[] { event.getDelta() }, invalidatedCUs);
+        for (ICompilationUnit cu : invalidatedCUs)
+			OTDTUIPlugin.getDefault().getCallinMarkerCreator().invalidateBaseCU(cu);
 	}
 
-	private void updateCallinMarkers(IJavaElementDelta[] deltas)
+	private void updateCallinMarkers(IJavaElementDelta[] deltas, Set<ICompilationUnit> invalidatedCUs)
 	{
 		if (deltas != null)
 		{
 //		    if (deltas.length > 0)
 //		        _CallinMarkerCreator2.reset();
-		    
+		    Set<IOTType> invalidatedRoles = new HashSet<IOTType>();
+		    Set<IMember> addedBaseMembers = new HashSet<IMember>();
+		    ICompilationUnit curCU = null;
+			
 			for (int idx = 0; idx < deltas.length; idx++)
 			{
 				IJavaElementDelta curDelta = deltas[idx];
@@ -79,7 +89,7 @@
 				if (curElem instanceof IParent)
 				{
 					// visit child's deltas recursively				
-					updateCallinMarkers(curDelta.getAffectedChildren());
+					updateCallinMarkers(curDelta.getAffectedChildren(), invalidatedCUs);
 				}
 				// addition/removal of role types:
 				if (   curElem instanceof IType 
@@ -89,23 +99,35 @@
 				{
 					IType roleType = (IType)curElem;
 					IOTType otType = OTModelManager.getOTElement(roleType);
-					if (otType != null && otType.isRole())
-						invalidateRole((IRoleType)otType, roleType);
+					if (otType != null && otType.isRole()) {
+						if (invalidatedRoles.add(otType)) // only if not already handled
+							invalidateRole((IRoleType)otType, roleType);
+					}
 				}
 				// changes of base methods & fields:
 				if (curElem instanceof IMethod || curElem instanceof IField)
 				{
-					handleDeltaKind(curDelta, (IMember)curElem);
+					handleDeltaKind(curDelta, (IMember)curElem, addedBaseMembers);
+					curCU = ((IMember)curElem).getCompilationUnit();
 				}
 				// any changes in method mappings:
 				if (curElem instanceof IMethodMapping) {
 					// changes in method mappings invalidate the current role's baseclass:
 					IJavaElement parent = curElem.getParent();
 					if (parent instanceof IRoleType) {
-						invalidateRole((IRoleType)parent, (IType) ((IRoleType)parent).getCorrespondingJavaElement());
+						IRoleType roleParent = (IRoleType)parent;
+						if (invalidatedRoles.add(roleParent)) // only if not already handled
+							invalidateRole(roleParent, (IType) roleParent.getCorrespondingJavaElement());
 					}
 				}
 			}
+			if (!addedBaseMembers.isEmpty()) {
+				if (addedBaseMembers.size() < 3 && !invalidatedCUs.contains(curCU))
+					for (IMember baseMember : addedBaseMembers)
+						baseMemberAdded(baseMember);
+				else
+					invalidatedCUs.add(curCU);
+			}
 		}
 	}
 	private void invalidateRole(IRoleType otType, IType roleType) {
@@ -118,11 +140,12 @@
 		OTDTUIPlugin.getDefault().getCallinMarkerCreator().invalidateRole(roleType, baseClass);
 	}
 
-    private void handleDeltaKind(IJavaElementDelta delta, IMember baseMember)
+    private void handleDeltaKind(IJavaElementDelta delta, IMember baseMember, Set<IMember> addedBaseMembers)
     {
 		if (delta.getKind() == IJavaElementDelta.ADDED)
 		{
-            baseMemberAdded(baseMember);
+			// don't yet handle, first count how many additions we have
+            addedBaseMembers.add(baseMember);
 		}
 		else if (delta.getKind() == IJavaElementDelta.REMOVED)
 		{