[58349] Handle class shape changes, pass #1
diff --git a/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/BeaninfoAdapterFactory.java b/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/BeaninfoAdapterFactory.java
index f750a45..bf8d231 100644
--- a/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/BeaninfoAdapterFactory.java
+++ b/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/BeaninfoAdapterFactory.java
@@ -11,7 +11,7 @@
  *******************************************************************************/
 /*
  *  $RCSfile: BeaninfoAdapterFactory.java,v $
- *  $Revision: 1.3 $  $Date: 2004/05/05 21:03:09 $ 
+ *  $Revision: 1.4 $  $Date: 2004/06/09 22:46:55 $ 
  */
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.WeakReference;
@@ -152,6 +152,28 @@
 			}
 		}
 	}
+	
+	public void markStaleIntrospectionPlusInner(String sourceName, boolean clearResults) {
+		processQueue();
+		String sourceNameForInner = sourceName + '$';
+		synchronized (this) {
+			Iterator itr = fIntrospected.entrySet().iterator();
+			while (itr.hasNext()) {
+				Map.Entry entry = (Map.Entry) itr.next();
+				String entryName = (String) entry.getKey();
+				if (entryName.equals(sourceName) || entryName.startsWith(sourceNameForInner)) {
+					// It is the item or one of its inner classes.
+					WeakValue ref = (WeakValue) entry.getValue();
+					BeaninfoClassAdapter a = (BeaninfoClassAdapter) ref.get();					
+					if (a != null) {
+						if (clearResults)
+							a.clearIntrospection();
+						a.markStaleFactory(isRegistryCreated() ? getRegistry() : null); // Mark it stale with the current registry.
+					}
+				}
+			}
+		}
+	}	
 
 	/**
 	 * Register an adapter for introspection.
@@ -166,46 +188,6 @@
 			fIntrospected.put(sourceName, new WeakValue(sourceName, adapter, fRefQ));
 		}
 	}
-
-	/**
-	 * Unregister the introspection and remove the adapter and clear out any introspection it may of done.
-	 * @param sourceName Fully qualified source name, use type for reflection, i.e. "a.b.c.Class1$InnerClass"
-	 */
-	public void unregisterIntrospection(String sourceName) {
-		processQueue();
-		synchronized (this) {
-			WeakValue ref = (WeakValue) fIntrospected.remove(sourceName);
-			if (ref != null) {
-				BeaninfoClassAdapter a = (BeaninfoClassAdapter) ref.get();
-				a.clearIntrospection();
-				a.getTarget().eAdapters().remove(a);
-			}
-		}
-	}
-
-	/**
-	 * Unregister this class and all inner classes (denoted by having same name plus '$' plus stuff)
-	 * @param sourceName Fully qualified source name, use type for reflection, i.e. "a.b.c.Class1$InnerClass"
-	 */
-	public void unregisterIntrospectionPlusInner(String sourceName) {
-		processQueue();
-		String sourceNameForInner = sourceName + '$';
-		synchronized (this) {
-			Iterator itr = fIntrospected.entrySet().iterator();
-			while (itr.hasNext()) {
-				Map.Entry entry = (Map.Entry) itr.next();
-				String entryName = (String) entry.getKey();
-				if (entryName.equals(sourceName) || entryName.startsWith(sourceNameForInner)) {
-					// It is the item or one of its inner classes.
-					WeakValue ref = (WeakValue) entry.getValue();
-					itr.remove();	// Since I removed it BEFORE sending removeAdapter, I won't get a concurrentmodification exception from removeAdapter also removing it, since it won't be there then.
-					BeaninfoClassAdapter a = (BeaninfoClassAdapter) ref.get();
-					a.clearIntrospection();
-					a.getTarget().eAdapters().remove(a);
-				}
-			}
-		}
-	}
 	
 	/**
 	 * Remove adapter. This happens in the case that adapter is being removed and
diff --git a/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/BeaninfoClassAdapter.java b/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/BeaninfoClassAdapter.java
index d72bace..c7c4300 100644
--- a/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/BeaninfoClassAdapter.java
+++ b/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/BeaninfoClassAdapter.java
@@ -11,7 +11,7 @@
  *******************************************************************************/
 /*
  *  $RCSfile: BeaninfoClassAdapter.java,v $
- *  $Revision: 1.13 $  $Date: 2004/06/02 19:42:39 $ 
+ *  $Revision: 1.14 $  $Date: 2004/06/09 22:46:55 $ 
  */
 
 import java.io.FileNotFoundException;
@@ -423,7 +423,9 @@
 						retrievedExtensionDocument = NEVER_RETRIEVED_EXTENSION_DOCUMENT;
 					}
 					if (retrievedExtensionDocument == NEVER_RETRIEVED_EXTENSION_DOCUMENT)
-						applyExtensionDocument(true);	// Add in Root stuff so that it will work correctly even though undefined.					
+						applyExtensionDocument(true);	// Add in Root stuff so that it will work correctly even though undefined.
+					// Mark that we've done all introspections so as not to waste time until we get notified that it has been added
+					// back in.
 					hasIntrospected = hasIntrospectedOperations = hasIntrospectedProperties = hasIntrospectedEvents = true;
 				} else {
 					if (retrievedExtensionDocument == RETRIEVED_ROOT_ONLY) {
@@ -952,7 +954,7 @@
 		// allow discovered duplicates unless they are different types.
 		HashMap supers = new HashMap(50);
 		BeanDecorator bd = Utilities.getBeanDecorator(getJavaClass());
-		if (bd.isMergeSuperProperties()) {
+		if (bd == null || bd.isMergeSuperProperties()) {
 			JavaClass superType = getJavaClass().getSupertype();
 			if (superType != null) {
 				Iterator superAllItr = superType.getAllProperties().iterator();
@@ -1343,7 +1345,7 @@
 		// will be allowed and we will not override them.
 		HashMap supers = new HashMap(50);
 		BeanDecorator bd = Utilities.getBeanDecorator(getJavaClass());
-		if (bd.isMergeSuperBehaviors()) {
+		if (bd == null || bd.isMergeSuperBehaviors()) {
 			EClass superType = getJavaClass().getSupertype();
 			if (superType != null) {
 				Iterator superAllItr = superType.getEAllOperations().iterator();
@@ -1590,7 +1592,7 @@
 		// allow discovered duplicates.
 		HashMap supers = new HashMap(50);
 		BeanDecorator bd = Utilities.getBeanDecorator(getJavaClass());
-		if (bd.isMergeSuperEvents()) {
+		if (bd == null || bd.isMergeSuperEvents()) {
 			JavaClass superType = (JavaClass) getJavaClass().getSupertype();
 			if (superType != null) {
 				Iterator superAllItr = superType.getAllEvents().iterator();
diff --git a/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/BeaninfoModelSynchronizer.java b/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/BeaninfoModelSynchronizer.java
index 5b12900..96a82e1 100644
--- a/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/BeaninfoModelSynchronizer.java
+++ b/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/BeaninfoModelSynchronizer.java
@@ -11,14 +11,9 @@
  *******************************************************************************/
 /*
  *  $RCSfile: BeaninfoModelSynchronizer.java,v $
- *  $Revision: 1.4 $  $Date: 2004/03/24 15:07:44 $ 
+ *  $Revision: 1.5 $  $Date: 2004/06/09 22:46:55 $ 
  */
 
-import java.util.*;
-
-import org.eclipse.core.resources.*;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResourceDelta;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.jdt.core.*;
@@ -32,22 +27,27 @@
 public class BeaninfoModelSynchronizer extends JavaModelListener {
 	protected BeaninfoAdapterFactory fAdapterFactory;
 	protected IJavaProject fProject; // The project this listener is opened on.
-	protected IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
-	private static final IPath CLASSPATH_PATH = new Path(".classpath"); //$NON-NLS-1$
 	private static final IPath BEANINFOCONFIG_PATH = new Path(BeaninfoNature.P_BEANINFO_SEARCH_PATH);	//$NON-NLS-1$	
 
 	public BeaninfoModelSynchronizer(BeaninfoAdapterFactory aFactory, IJavaProject aProject) {
-		super();
+		super(ElementChangedEvent.POST_CHANGE);
 		fAdapterFactory = aFactory;
 		fProject = aProject;
-		// We're really only interested in Post_Change, not the others, so we will
-		// remove ourself (since super ctor added ourself) and then add ourself
-		// back with only post change. (Post change is after everything has been
-		// reconciled and build).
-		JavaCore.removeElementChangedListener(this);
-		JavaCore.addElementChangedListener(this, ElementChangedEvent.POST_CHANGE);	
 	}
 
+	/* (non-Javadoc)
+	 * @see org.eclipse.jem.internal.adapters.jdom.JavaModelListener#getJavaProject()
+	 */
+	protected IJavaProject getJavaProject() {
+		return fProject;
+	}
+	/* (non-Javadoc)
+	 * @see org.eclipse.jem.internal.adapters.jdom.JavaModelListener#isAlsoClasspathChange(org.eclipse.core.runtime.IPath)
+	 */
+	protected boolean isAlsoClasspathChange(IPath path) {
+		return path.equals(BEANINFOCONFIG_PATH);
+	}
+	
 	/**
 	 * Stop the synchronizer from listening to any more changes.
 	 */
@@ -60,97 +60,6 @@
 		return fAdapterFactory;
 	}
 
-	protected IJavaProject getJavaProject(IClasspathEntry entry) {
-		IProject proj = workspaceRoot.getProject(entry.getPath().segment(0));
-		if (proj != null)
-			return (IJavaProject) JavaCore.create(proj);
-		return null;
-	}
-	
-	private boolean isClassPathChange(IJavaElementDelta delta) {
-		int flags = delta.getFlags();
-		return (
-			delta.getKind() == IJavaElementDelta.CHANGED
-				&& ((flags & IJavaElementDelta.F_ADDED_TO_CLASSPATH) != 0)
-				|| ((flags & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) != 0)
-				|| ((flags & IJavaElementDelta.F_REORDER) != 0));
-	}
-
-	/**
-	 * This method will check to see if a <code>javaProject</code> is a project in the
-	 * classpath of the adapterFactory java project.
-	 */
-	protected boolean isInClasspath(IJavaProject javaProject) {
-		IJavaProject adapterJavaProject = fProject;
-		if (javaProject.equals(adapterJavaProject))
-			return true;
-		return isInClasspath(javaProject, adapterJavaProject, true, new HashSet());
-	}
-
-	protected boolean isInClasspath(IJavaProject testProject, IJavaProject targetProject, boolean isFirstLevel, Set visited) {
-		if (visited.contains(targetProject))
-			return false;
-		visited.add(targetProject);
-		IClasspathEntry[] entries = null;
-		try {
-			entries = targetProject.getRawClasspath();
-		} catch (JavaModelException e) {
-			return false;
-		}
-		IClasspathEntry entry, resEntry;
-		IJavaProject proj = null;
-		List projects = null;
-		for (int i = 0; i < entries.length; i++) {
-			entry = entries[i];
-			if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
-				resEntry = JavaCore.getResolvedClasspathEntry(entry);
-				proj = getJavaProject(resEntry);
-				if (isFirstLevel || resEntry.isExported()) {
-					if (proj.equals(testProject))
-						return true;
-					else {
-						if (projects == null)
-							projects = new ArrayList();
-						projects.add(proj);
-					}
-				}
-			}
-		}
-		return isInClasspath(testProject, projects, false, visited);
-	}
-	
-	protected boolean isInClasspath(IJavaProject testProject, List someJavaProjects, boolean isFirstLevel, Set visited) {
-		if (someJavaProjects == null)
-			return false;
-		int size = someJavaProjects.size();
-		IJavaProject javaProj = null;
-		for (int i = 0; i < size; i++) {
-			javaProj = (IJavaProject) someJavaProjects.get(i);
-			return isInClasspath(testProject, javaProj, isFirstLevel, visited);
-		}
-		return false;
-	}
-
-	/*
-	 * Test if .classpath/.beaninfoconfig is part of the change. This is necessary
-	 * because .classpath/.beaninfoconfig changes of DEPENDENT PROJECTS are not signaled
-	 * through classpath change mechanisms of the top project.
-	 */
-	private boolean isClasspathResourceChange(IJavaElementDelta delta) {
-		IResourceDelta[] resources = delta.getResourceDeltas();
-		if (resources == null)
-			return false;
-		IPath path = null;
-		for (int i = 0; i < resources.length; i++) {
-			if (resources[i].getKind() != IResourceDelta.NO_CHANGE) {
-				path = resources[i].getProjectRelativePath();
-				if (path.equals(CLASSPATH_PATH) || path.equals(BEANINFOCONFIG_PATH))
-					return true;
-			}
-		}
-		return false;
-	}
-
 	protected void processJavaElementChanged(IJavaProject element, IJavaElementDelta delta) {
 		if (isInClasspath(element)) {
 			if (delta.getKind() == IJavaElementDelta.REMOVED || delta.getKind() == IJavaElementDelta.ADDED) {
@@ -163,7 +72,7 @@
 				}
 				return;
 			} else if (isClasspathResourceChange(delta)) {
-				getAdapterFactory().markAllStale(); // The .classpath file itself in SOME DEPENDENT PROJECT has changed. 
+				getAdapterFactory().markAllStale(); // The .classpath file (or .beaninfoconfig) itself in SOME DEPENDENT PROJECT has changed. 
 				return;
 			}
 			processChildren(element, delta);
@@ -178,26 +87,26 @@
 	 * If it is not a content change then process the children.
 	 */
 	protected void processJavaElementChanged(ICompilationUnit element, IJavaElementDelta delta) {
-		if (!element.isWorkingCopy()) {
-			if (((delta.getKind() == IJavaElementDelta.CHANGED && (delta.getFlags() & IJavaElementDelta.F_PRIMARY_WORKING_COPY) == 0) || delta.getKind() == IJavaElementDelta.ADDED)) {
-				try {
-					IType[] flushTypes = element.getAllTypes();
-					for (int i = 0; i < flushTypes.length; i++) {
-						getAdapterFactory().markStaleIntrospection(flushTypes[i].getFullyQualifiedName(), false);
-					}
-				} catch (JavaModelException e) {
-				}
-			}
-			if (delta.getKind() == IJavaElementDelta.REMOVED) {
-				// It doesn't matter if totally removed or just moved somewhere else, we will clear out and remove the
+		switch (delta.getKind()) {
+			case IJavaElementDelta.CHANGED :
+				// A file save had occurred. It doesn't matter if currently working copy or not.
+				// It means something has changed to the file on disk, but don't know what.
+				if ((delta.getFlags() & IJavaElementDelta.F_PRIMARY_RESOURCE) != 0) {
+					getAdapterFactory().markStaleIntrospectionPlusInner(getFullNameFromElement(element), false);	// Flush everything, including inner classes.
+				}						
+				
+				break;
+			case IJavaElementDelta.ADDED:
+			case IJavaElementDelta.REMOVED:
+				// Need to know for add because we optimize the beaninfo such that once found as undefined, it won't
+				// introspect again until we mark it stale. So we need to mark it stale to refresh it.
+				
+				// It doesn't matter if totally removed or just moved somewhere else, we will clear out
 				// adapter because there could be a rename which would be a different class.
-				// Currently the element is already deleted and there is no way to find the types in the unit to remove.
-				// So instead we ask factory to remove all it any that start with it plus for inner classes.				
-				getAdapterFactory().unregisterIntrospectionPlusInner(getFullNameFromElement(element));
-				return;
-				// Since the compilation unit was removed we don't need to process the children (actually the children list will be empty
-			}
-			processChildren(element, delta);
+				// Currently the element is already deleted or added and there is no way to find the types in the unit to flush.
+				// So instead we ask factory to flush all it any that start with it plus for inner classes.				
+				getAdapterFactory().markStaleIntrospectionPlusInner(getFullNameFromElement(element), true);	// Flush everything, including inner classes.
+				break;
 		}
 	}
 
@@ -210,7 +119,7 @@
 			// adapter because there could be a rename which would be a different class.
 			// Currently the element is already deleted and there is no way to find the types in the unit to remove.
 			// So instead we ask factory to remove all it any that start with it plus for inner classes.
-			getAdapterFactory().unregisterIntrospectionPlusInner(getFullNameFromElement(element));
+			getAdapterFactory().markStaleIntrospectionPlusInner(getFullNameFromElement(element), true);
 			return; // Since the classfile was removed we don't need to process the children (actually the children list will be empty
 		}
 		IJavaElementDelta[] children = delta.getAffectedChildren();
@@ -251,6 +160,20 @@
 		else
 			super.processJavaElementChanged(element, delta);
 	}
+	
+	protected void processJavaElementChanged(IPackageFragment element, IJavaElementDelta delta) {
+		switch (delta.getKind()) {
+			case IJavaElementDelta.ADDED:
+				break;	// Don't need to do anything on a new package. If this was from a new fragroot, we would recycle already. Otherwise, it will find this package on the first use.
+			case IJavaElementDelta.REMOVED:
+				if (delta.getAffectedChildren().length == 0)
+					fAdapterFactory.markAllStale();
+				break;
+			default :
+				super.processJavaElementChanged(element, delta);
+		}
+	}
+	
 
 	/**
 	 * Handle the change for a single element, children will be handled separately.
@@ -259,7 +182,11 @@
 	 */
 	protected void processJavaElementChanged(IType element, IJavaElementDelta delta) {
 		if (delta.getKind() == IJavaElementDelta.REMOVED) {
-			getAdapterFactory().unregisterIntrospectionPlusInner(element.getFullyQualifiedName());	// Close it out. Doesn't matter if moved_to, that would be a rename which requires brand new class.
+			// Close it out. Doesn't matter if moved_to, that would be a rename which requires brand new class.
+			// We can't actually get rid of the beaninfo adapter because it may be asked for again
+			// just to see if not defined. It may also come back later and we want to know about
+			// it to recycle the vm.
+			getAdapterFactory().markStaleIntrospection(element.getFullyQualifiedName(), true);	
 		} else
 			getAdapterFactory().markStaleIntrospection(element.getFullyQualifiedName(), false); // Just mark it stale
 		processChildren(element, delta);
diff --git a/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/BeaninfoNature.java b/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/BeaninfoNature.java
index 30befeb..c2f7848 100644
--- a/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/BeaninfoNature.java
+++ b/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/BeaninfoNature.java
@@ -11,7 +11,7 @@
  *******************************************************************************/
 /*
  *  $RCSfile: BeaninfoNature.java,v $
- *  $Revision: 1.18 $  $Date: 2004/06/04 15:29:34 $ 
+ *  $Revision: 1.19 $  $Date: 2004/06/09 22:46:55 $ 
  */
 
 import java.io.*;
@@ -352,6 +352,7 @@
 		return fRegistry;
 	}
 	
+	private Object createSemaphore = new Object();	// Semaphore so that only one create can happen at a time.
 	/*
 	 * This is <package-protected> so that only the appropriate create job in this
 	 * package can call it. This is because this must be controlled to only be
@@ -359,24 +360,29 @@
 	 * If waitForBuild is passed onto launching the registry. If we suspended the builds, then we must not
 	 * wait, or a deadlock will occur.
 	 */
-	synchronized void createRegistry(IProgressMonitor pm, boolean waitForBuild) {
-		pm.beginTask(BeanInfoAdapterMessages.getString("UICreateRegistryJobHandler.StartBeaninfoRegistry"), 100);	//$NON-NLS-1$		
-		// synchronized on this nature so that only one can create on this particular project at a time.
-		if (fRegistry != null) {
-			pm.done();
-			return;	// It had already been created. Could of been because threads were racing to do the creation, and one got there first.
-		}
+	void createRegistry(IProgressMonitor pm, boolean waitForBuild) {
+		// synchronized on createsemaphore so that only one can create on this particular project at a time.
+		synchronized (createSemaphore) {
+			pm.beginTask(BeanInfoAdapterMessages.getString("UICreateRegistryJobHandler.StartBeaninfoRegistry"), 100); //$NON-NLS-1$		
+			if (isRegistryCreated()) {
+				pm.done();
+				return; // It had already been created. Could of been because threads were racing to do the creation, and one got there first.
+			}
 
-		try {
-			ConfigurationContributor configurationContributor =  (ConfigurationContributor) getConfigurationContributor();
-			configurationContributor.setNature(this);
-			fRegistry = ProxyLaunchSupport.startImplementation(fProject, "Beaninfo", //$NON-NLS-1$
-				new IConfigurationContributor[] { configurationContributor}, waitForBuild, new SubProgressMonitor(pm, 100));
-			fRegistry.addRegistryListener(registryListener);
-		} catch (CoreException e) {
-			BeaninfoPlugin.getPlugin().getLogger().log(e.getStatus());
-		} finally {
-			pm.done();
+			try {
+				ConfigurationContributor configurationContributor = (ConfigurationContributor) getConfigurationContributor();
+				configurationContributor.setNature(this);
+				ProxyFactoryRegistry registry = ProxyLaunchSupport.startImplementation(fProject, "Beaninfo", //$NON-NLS-1$
+						new IConfigurationContributor[] { configurationContributor}, waitForBuild, new SubProgressMonitor(pm, 100));
+				registry.addRegistryListener(registryListener);
+				synchronized(this) {
+					fRegistry = registry;
+				}
+			} catch (CoreException e) {
+				BeaninfoPlugin.getPlugin().getLogger().log(e.getStatus());
+			} finally {
+				pm.done();
+			}
 		}
 	}
 	
@@ -645,10 +651,6 @@
 					// First time for this nature, or first time after registry reset. Need to compute the info.
 					// It is possible for this to be called BEFORE the first usage of BeanInfo. The editor usually
 					// brings up the editor's registry before it gets anything from BeanInfo.
-					
-					// Save it for override processing. That happens over and over later after all config processing is done.
-					info.getJavaProject().getProject().setSessionProperty(CONFIG_INFO_SESSION_KEY, info);
-					
 					List contributorsList = new ArrayList(10);
 					if (!info.getContainerIds().isEmpty()) {
 						// Run through all of the visible container ids that are applicable and get BeanInfo contributors.
@@ -699,6 +701,11 @@
 					// Save it for all beaninfo processing (and configuration processing if they implement proxy configuration contributor).
 					explicitContributors = (IBeanInfoContributor[]) contributorsList.toArray(new IBeanInfoContributor[contributorsList.size()]);
 					info.getJavaProject().getProject().setSessionProperty(BEANINFO_CONTRIBUTORS_SESSION_KEY, explicitContributors);
+					// Save it for override processing. That happens over and over later after all config processing is done.
+					// Do it last so that if there is a race condition, since this property is a flag to indicate we have data,
+					// we need to make sure the Beaninfo data is already set at the point we set this.
+					// We could actually set it twice because of this, but it is the same data, so, so what.
+					info.getJavaProject().getProject().setSessionProperty(CONFIG_INFO_SESSION_KEY, info);					
 				} else {
 					explicitContributors = (IBeanInfoContributor[]) info.getJavaProject().getProject().getSessionProperty(BEANINFO_CONTRIBUTORS_SESSION_KEY);
 				}
diff --git a/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/CreateRegistryJobHandler.java b/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/CreateRegistryJobHandler.java
index 196deee..38fb4d0 100644
--- a/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/CreateRegistryJobHandler.java
+++ b/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/CreateRegistryJobHandler.java
@@ -10,7 +10,7 @@
  *******************************************************************************/
 /*
  *  $RCSfile: CreateRegistryJobHandler.java,v $
- *  $Revision: 1.4 $  $Date: 2004/06/04 15:29:34 $ 
+ *  $Revision: 1.5 $  $Date: 2004/06/09 22:46:55 $ 
  */
 package org.eclipse.jem.internal.beaninfo.adapters;
 
@@ -64,6 +64,41 @@
 	}
 	
 	private int suspendedCount = 0;	// Number of nested suspends. Resume will occur only when it goes back to zero.
+	
+	private boolean[] startSemaphore = new boolean[1];	// Used to tell caller when suspend job has suspended the build ruile.
+	private boolean[] stopSemaphore = new boolean[1];	// Used to tell when to stop. The [0] value is whether stop requested or not.
+	// The purpose of this job is to suspend the builds while beaninfo is creating its registries. This is to
+	// prevent deadlocks between a beaninfo start reqistry request and a start request for beaninfo coming from
+	// a builder. It is a separate job so that if several overlapping beaninfo registry requests come in, then
+	// the first one in will suspend the build, and the build will not resume until the last one out. The first
+	// one in my finish before the next one, so we don't want builds to resume until all have completed.
+	private Job suspendJob = new Job("Suspend builds for BeanInfo") {	//$NON-NLS-1$
+
+		{
+			this.setSystem(true);	// Don't show these to users.
+			// The rule for running this is build rule. This is how it stops the builders
+			this.setRule(ResourcesPlugin.getWorkspace().getRuleFactory().buildRule());
+		}
+		
+		protected IStatus run(IProgressMonitor monitor) {
+			synchronized (startSemaphore) {
+				startSemaphore[0] = true;
+				startSemaphore.notifyAll();
+			}
+			
+			// Now we just wait until suspend count goes to 0. We will be told when this happens.
+			synchronized (stopSemaphore) {
+				while (!stopSemaphore[0]) {
+					try {
+						stopSemaphore.wait();
+					} catch (InterruptedException e) {
+					}
+				}
+			}
+			return Status.OK_STATUS;
+		}
+	};
+	
 	/*
 	 * Do the creation.
 	 * 
@@ -76,7 +111,6 @@
 		pm.beginTask("", 400);	//$NON-NLS-1$
 		IJobManager jobManager = Platform.getJobManager();
 		Job currentJob = jobManager.currentJob();
-		ISchedulingRule suspendedBuildRule = null;	// The build rule. This will be null if I don't suspend.
 		try {
 			if (currentJob == null || (!currentJob.belongsTo(ResourcesPlugin.FAMILY_AUTO_BUILD) && !currentJob.belongsTo(ResourcesPlugin.FAMILY_MANUAL_BUILD))) {
 				// We are not in the build, so suspend the rule. But first, wait for the builds to complete. This
@@ -96,9 +130,25 @@
 					pm.worked(200);
 				
 				synchronized(this) {
-					++suspendedCount; // We need to keep track of nesting of suspends because Eclipse doesn't. The first resume will cause it to resume.
-					suspendedBuildRule = ResourcesPlugin.getWorkspace().getRuleFactory().buildRule();
-					jobManager.suspend(suspendedBuildRule, new SubProgressMonitor(pm, 100));
+					if (suspendedCount++ == 0) {
+						// Only start the suspend job on the first suspend request.
+						// We can not let anyone else get past here until we know the
+						// build has been halted.
+						synchronized (stopSemaphore) {
+							stopSemaphore[0] = false;	// Reset it for next start
+							stopSemaphore.notifyAll();	// Just in case job is still waiting.
+						}
+						synchronized (startSemaphore) {
+							startSemaphore[0] = false;
+							suspendJob.schedule();
+							while (!startSemaphore[0]) {
+								try {
+									startSemaphore.wait();	// Wait for suspend job to say it has the build rule suspended.
+								} catch (InterruptedException e) {
+								}
+							}
+						}
+					}
 				}
 			} else
 				pm.worked(300);
@@ -107,12 +157,16 @@
 			nature.createRegistry(new SubProgressMonitor(pm, 100), false);	
 		} finally {
 			synchronized (this) {
-				if (suspendedBuildRule != null) {
-					if (--suspendedCount<= 0) {
-						suspendedCount = 0;	// Just to be safe.
-						jobManager.resume(suspendedBuildRule);
+				// No matter what happens we need to stop the suspend job if we are the last.
+				if (--suspendedCount <= 0)
+					suspendedCount = 0;
+					if (suspendJob.getState() != Job.NONE) {
+						// The job is running.
+						synchronized (stopSemaphore) {
+							stopSemaphore[0] = true;
+							stopSemaphore.notifyAll();	// Tell suspend job to stop.
+						}						
 					}
-				}
 			}
 			pm.done();
 		}
diff --git a/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/core/BeaninfoPlugin.java b/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/core/BeaninfoPlugin.java
index 2b2f1fc..8f9bd53 100644
--- a/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/core/BeaninfoPlugin.java
+++ b/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/core/BeaninfoPlugin.java
@@ -11,7 +11,7 @@
  *******************************************************************************/
 /*
  *  $RCSfile: BeaninfoPlugin.java,v $
- *  $Revision: 1.4 $  $Date: 2004/05/24 23:23:31 $ 
+ *  $Revision: 1.5 $  $Date: 2004/06/09 22:46:55 $ 
  */
 
 
@@ -84,25 +84,25 @@
 	
 	private static final OverrideContribution[] EMPTY_OC = new OverrideContribution[0];	// Used for an empty contribution list for a fragment.
 
-	public BeaninfoEntry[] getContainerIdBeanInfos(String containerID) {
+	public synchronized BeaninfoEntry[] getContainerIdBeanInfos(String containerID) {
 		if (containerIdsToBeaninfoEntryContributions == null)
 			processBeanInfoContributionExtensionPoint();
 		return (BeaninfoEntry[]) containerIdsToBeaninfoEntryContributions.get(containerID);
 	}
 	
-	public BeaninfoEntry[] getPluginBeanInfos(String pluginid) {
+	public synchronized BeaninfoEntry[] getPluginBeanInfos(String pluginid) {
 		if (pluginToBeaninfoEntryContributions == null)
 			processBeanInfoContributionExtensionPoint();
 		return (BeaninfoEntry[]) pluginToBeaninfoEntryContributions.get(pluginid);
 	}
 	
-	public IConfigurationElement[] getPluginContributors(String pluginid) {
+	public synchronized IConfigurationElement[] getPluginContributors(String pluginid) {
 		if (pluginToContributors == null)
 			processBeanInfoContributionExtensionPoint();
 		return (IConfigurationElement[]) pluginToContributors.get(pluginid);
 	}	
 	
-	public IConfigurationElement[] getContainerIdContributors(String containerID) {
+	public synchronized IConfigurationElement[] getContainerIdContributors(String containerID) {
 		if (containerIdsToContributors == null)
 			processBeanInfoContributionExtensionPoint();
 		return (IConfigurationElement[]) containerIdsToContributors.get(containerID);
@@ -116,7 +116,7 @@
 	public static final String PI_PACKAGE = "package";
 	public static final String PI_PATH = "path";
 	
-	protected void processBeanInfoContributionExtensionPoint() {
+	protected synchronized void processBeanInfoContributionExtensionPoint() {
 		ContributorExtensionPointInfo info = ProxyPlugin.processContributionExtensionPoint(PI_BEANINFO_CONTRIBUTION_EXTENSION_POINT);
 		ConfigurationElementReader reader = new ConfigurationElementReader();
 		// Process the container IDs first.
@@ -431,8 +431,10 @@
 		try {
 			IConfigurationContributionInfo info = (IConfigurationContributionInfo) project.getSessionProperty(BeaninfoNature.CONFIG_INFO_SESSION_KEY);
 			final IBeanInfoContributor[] explicitContributors = (IBeanInfoContributor[]) project.getSessionProperty(BeaninfoNature.BEANINFO_CONTRIBUTORS_SESSION_KEY);
-			if (ocFragments == null)
-				processBeanInfoContributionExtensionPoint();	// We haven't processed them yet.
+			synchronized (this) {
+				if (ocFragments == null)
+					processBeanInfoContributionExtensionPoint(); // We haven't processed them yet.
+			}
 			for (int fragmentIndex = 0; fragmentIndex < ocFragments.length; fragmentIndex++) {
 				if (ocFragments[fragmentIndex].isPrefixOf(packagePath)) {
 					String leftOver = null;	// The left over portion of the package. This will be set first time needed. 
diff --git a/plugins/org.eclipse.jem.proxy/proxy/org/eclipse/jem/internal/proxy/core/ProxyPlugin.java b/plugins/org.eclipse.jem.proxy/proxy/org/eclipse/jem/internal/proxy/core/ProxyPlugin.java
index 9e29f35..02e33ed 100644
--- a/plugins/org.eclipse.jem.proxy/proxy/org/eclipse/jem/internal/proxy/core/ProxyPlugin.java
+++ b/plugins/org.eclipse.jem.proxy/proxy/org/eclipse/jem/internal/proxy/core/ProxyPlugin.java
@@ -11,7 +11,7 @@
  *******************************************************************************/
 /*
  *  $RCSfile: ProxyPlugin.java,v $
- *  $Revision: 1.24 $  $Date: 2004/06/02 19:58:49 $ 
+ *  $Revision: 1.25 $  $Date: 2004/06/09 22:46:57 $ 
  */
 
 
@@ -674,7 +674,7 @@
 	 * 
 	 * @since 1.0.0
 	 */
-	public IConfigurationElement[] getContainerConfigurations(String containerid) {
+	public synchronized IConfigurationElement[] getContainerConfigurations(String containerid) {
 		if (containerToContributions == null)
 			processProxyContributionExtensionPoint();
 		return (IConfigurationElement[]) containerToContributions.get(containerid);
@@ -688,13 +688,13 @@
 	 * 
 	 * @since 1.0.0
 	 */
-	public IConfigurationElement[] getPluginConfigurations(String pluginid) {
+	public synchronized IConfigurationElement[] getPluginConfigurations(String pluginid) {
 		if (pluginToContributions == null)
 			processProxyContributionExtensionPoint();
 		return (IConfigurationElement[]) pluginToContributions.get(pluginid);
 	}
 	
-	protected void processProxyContributionExtensionPoint() {
+	protected synchronized void processProxyContributionExtensionPoint() {
 		ContributorExtensionPointInfo info = processContributionExtensionPoint(PI_CONFIGURATION_CONTRIBUTION_EXTENSION_POINT);
 		containerToContributions = info.containerToContributions;
 		pluginToContributions = info.pluginToContributions;
diff --git a/plugins/org.eclipse.jem.proxy/proxyRemote/org/eclipse/jem/internal/proxy/remote/REMMethodProxy.java b/plugins/org.eclipse.jem.proxy/proxyRemote/org/eclipse/jem/internal/proxy/remote/REMMethodProxy.java
index 31a7046..9a3cd9b 100644
--- a/plugins/org.eclipse.jem.proxy/proxyRemote/org/eclipse/jem/internal/proxy/remote/REMMethodProxy.java
+++ b/plugins/org.eclipse.jem.proxy/proxyRemote/org/eclipse/jem/internal/proxy/remote/REMMethodProxy.java
@@ -11,7 +11,7 @@
  *******************************************************************************/
 /*
  *  $RCSfile: REMMethodProxy.java,v $
- *  $Revision: 1.5 $  $Date: 2004/05/24 23:23:36 $ 
+ *  $Revision: 1.6 $  $Date: 2004/06/09 22:46:57 $ 
  */
 
 import org.eclipse.core.runtime.IStatus;
@@ -61,14 +61,10 @@
 		return fMethodName;
 	}
 
-	public IBeanTypeProxy[] getParameterTypes() {
+	public synchronized IBeanTypeProxy[] getParameterTypes() {
 		if (fParameterTypes == null) {
-			IArrayBeanProxy parmTypes =
-				(IArrayBeanProxy) REMStandardBeanProxyConstants
-					.getConstants(fFactory)
-					.getMethodParameterTypesMessage()
-					.invokeCatchThrowableExceptions(
-					this);
+			IArrayBeanProxy parmTypes = (IArrayBeanProxy) REMStandardBeanProxyConstants.getConstants(fFactory)
+					.getMethodParameterTypesMessage().invokeCatchThrowableExceptions(this);
 			if (parmTypes == null)
 				fParameterTypes = new IBeanTypeProxy[0]; // There was some error, only way null is returned
 			else {
diff --git a/plugins/org.eclipse.jem.workbench/workbench/org/eclipse/jem/internal/adapters/jdom/JavaClassJDOMAdaptor.java b/plugins/org.eclipse.jem.workbench/workbench/org/eclipse/jem/internal/adapters/jdom/JavaClassJDOMAdaptor.java
index 7109c34..fc960c8 100644
--- a/plugins/org.eclipse.jem.workbench/workbench/org/eclipse/jem/internal/adapters/jdom/JavaClassJDOMAdaptor.java
+++ b/plugins/org.eclipse.jem.workbench/workbench/org/eclipse/jem/internal/adapters/jdom/JavaClassJDOMAdaptor.java
@@ -11,12 +11,13 @@
  *******************************************************************************/
 /*
  *  $RCSfile: JavaClassJDOMAdaptor.java,v $
- *  $Revision: 1.5 $  $Date: 2004/02/24 19:33:35 $ 
+ *  $Revision: 1.6 $  $Date: 2004/06/09 22:47:06 $ 
  */
 
 import java.util.*;
 import java.util.logging.Level;
 
+import org.eclipse.core.resources.IResource;
 import org.eclipse.emf.common.notify.Notification;
 import org.eclipse.emf.common.notify.Notifier;
 import org.eclipse.emf.ecore.EObject;
@@ -253,21 +254,32 @@
 		primFlushReflectedValues();
 		boolean isHeadless = UIContextDetermination.getCurrentContext() == UIContextDetermination.HEADLESS_CONTEXT;
 		if (getSourceProject() != null && getSourceType() != null && getSourceType().exists()) {
-			setModifiers();
-			setNaming();
-			try {
-				setSuper();
-			} catch (InheritanceCycleException e) {
-				JavaPlugin.getDefault().getLogger().log(e);
-			}
-			setImplements();
-			addMethods();
-			addFields();
-			reflectInnerClasses();
-			//addImports();
-			if (isHeadless) {
-				registerWithFactory();
-				return true;
+			ICompilationUnit cu = getSourceType().getCompilationUnit();
+			boolean isWC = cu != null ? cu.isWorkingCopy() : false;
+			IResource res = isWC ? getSourceType().getResource() : null;
+			// We are only interested in physical classes. If still just in working copy and not yet put out to
+			// disk, we don't should treat as not exist. Anything else is considered existing because we got past
+			// getSourceType.exists. This will return the truth for non-wc. But for wc types it will return true,
+			// even though not physically on disk (such as just creating it and hadn't saved it yet). So for wc types
+			// we need to test the actual resource.
+			// Test is OK if not wc, or if wc, then there is a res. and it is accessible.
+			if (!isWC || (res != null && res.isAccessible())) {
+				setModifiers();
+				setNaming();
+				try {
+					setSuper();
+				} catch (InheritanceCycleException e) {
+					JavaPlugin.getDefault().getLogger().log(e);
+				}
+				setImplements();
+				addMethods();
+				addFields();
+				reflectInnerClasses();
+				//addImports();
+				if (isHeadless) {
+					registerWithFactory();
+					return true;
+				}
 			}
 		}
 		if (isHeadless)
diff --git a/plugins/org.eclipse.jem.workbench/workbench/org/eclipse/jem/internal/adapters/jdom/JavaJDOMAdapterFactory.java b/plugins/org.eclipse.jem.workbench/workbench/org/eclipse/jem/internal/adapters/jdom/JavaJDOMAdapterFactory.java
index 628a388..da4f411 100644
--- a/plugins/org.eclipse.jem.workbench/workbench/org/eclipse/jem/internal/adapters/jdom/JavaJDOMAdapterFactory.java
+++ b/plugins/org.eclipse.jem.workbench/workbench/org/eclipse/jem/internal/adapters/jdom/JavaJDOMAdapterFactory.java
@@ -11,13 +11,15 @@
  *******************************************************************************/
 /*
  *  $RCSfile: JavaJDOMAdapterFactory.java,v $
- *  $Revision: 1.1 $  $Date: 2003/10/27 17:33:53 $ 
+ *  $Revision: 1.2 $  $Date: 2004/06/09 22:47:06 $ 
  */
 import java.util.*;
 
+import org.eclipse.emf.common.notify.*;
 import org.eclipse.emf.common.notify.Notification;
 import org.eclipse.emf.common.notify.Notifier;
 import org.eclipse.jdt.core.*;
+import org.eclipse.jem.internal.java.adapters.*;
 import org.eclipse.jem.internal.java.adapters.JavaReflectionAdapterFactory;
 import org.eclipse.jem.internal.java.adapters.ReflectionAdaptor;
 /**
@@ -144,6 +146,35 @@
 		return a.flushReflectedValuesIfNecessaryNoNotification(false);
 	return null;
 }
+
+public Notification flushReflectionPlusInnerNoNotification(String source) {
+	isBusyIteratingReflected = true;
+	Notification notification = null;
+	try {
+		String innerName = source + '$';
+		Iterator it = reflected.entrySet().iterator();
+		Map.Entry entry;
+		String key;
+		JavaReflectionAdaptor adaptor;
+		while (it.hasNext()) {
+			entry = (Map.Entry) it.next();
+			key = (String) entry.getKey();
+			if (key.equals(source) || key.startsWith(innerName)) {
+				adaptor = (JavaReflectionAdaptor) reflected.get(key);
+				if (adaptor != null) {
+					if (notification == null)
+						notification = adaptor.flushReflectedValuesIfNecessaryNoNotification(false);
+					else
+						((NotificationChain) notification).add(adaptor.flushReflectedValuesIfNecessaryNoNotification(false));
+				}
+			}
+		}
+	} finally {
+		finishedIteratingReflected();
+	}
+	return notification;
+
+}
 /**
  * Insert the method's description here.
  * Creation date: (11/2/2000 3:02:31 PM)
diff --git a/plugins/org.eclipse.jem.workbench/workbench/org/eclipse/jem/internal/adapters/jdom/JavaModelListener.java b/plugins/org.eclipse.jem.workbench/workbench/org/eclipse/jem/internal/adapters/jdom/JavaModelListener.java
index e9a9256..54e46a1 100644
--- a/plugins/org.eclipse.jem.workbench/workbench/org/eclipse/jem/internal/adapters/jdom/JavaModelListener.java
+++ b/plugins/org.eclipse.jem.workbench/workbench/org/eclipse/jem/internal/adapters/jdom/JavaModelListener.java
@@ -11,9 +11,16 @@
  *******************************************************************************/
 /*
  *  $RCSfile: JavaModelListener.java,v $
- *  $Revision: 1.2 $  $Date: 2004/01/13 16:17:42 $ 
+ *  $Revision: 1.3 $  $Date: 2004/06/09 22:47:06 $ 
  */
 
+import java.util.*;
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
 import org.eclipse.jdt.core.*;
 
 /**
@@ -21,14 +28,17 @@
  * Creation date: (10/31/2000 1:13:12 PM)
  * @author: Administrator
  */
-public class JavaModelListener implements IElementChangedListener {
+public abstract class JavaModelListener implements IElementChangedListener {
 	
 /**
  * JavaModelListener constructor comment.
  */
 public JavaModelListener() {
-	super();
-	JavaCore.addElementChangedListener(this, ElementChangedEvent.POST_CHANGE | ElementChangedEvent.POST_RECONCILE);
+	this(ElementChangedEvent.POST_CHANGE);
+}
+
+public JavaModelListener(int eventsToListen) {
+	JavaCore.addElementChangedListener(this, eventsToListen);
 }
 /**
  * One or more attributes of one or more elements maintained by
@@ -142,4 +152,115 @@
 protected void processJavaElementChanged(IType element, IJavaElementDelta delta) {
 	// override to implement specific behavior
 }
+private static final IPath CLASSPATH_PATH = new Path(".classpath");
+protected boolean isClassPathChange(IJavaElementDelta delta) {
+	int flags = delta.getFlags();
+	return (delta.getKind() == IJavaElementDelta.CHANGED && ((flags & IJavaElementDelta.F_ADDED_TO_CLASSPATH) != 0) || ((flags & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) != 0) || ((flags & IJavaElementDelta.F_REORDER) != 0));
+}
+
+/**
+ * Method isClasspathResourceChange.
+ * @param delta
+ * @return boolean
+ */
+protected boolean isClasspathResourceChange(IJavaElementDelta delta) {
+	IResourceDelta[] resources = delta.getResourceDeltas();
+	if (resources == null)
+		return false;
+	IPath path = null;
+	for (int i = 0; i < resources.length; i++) {
+		if (resources[i].getKind() == IResourceDelta.CHANGED) {
+			path = resources[i].getProjectRelativePath();
+			if (path.equals(CLASSPATH_PATH) || isAlsoClasspathChange(path))
+				return true;
+		}
+	}
+	return false;
+}
+
+/**
+ * Is this path also a classpath change type of resource. If so, return true.
+ * Subclasses may override. Default is false.
+ * @param path
+ * @return
+ * 
+ * @since 1.0.0
+ */
+protected boolean isAlsoClasspathChange(IPath path) {
+	return false;
+}
+
+/**
+ * This method will check to see if a <code>javaProject</code> is a project in the
+ * classpath of the adapterFactory java project.
+ */
+protected boolean isInClasspath(IJavaProject javaProject) {
+	IJavaProject adapterJavaProject = getJavaProject();
+	if (javaProject.equals(adapterJavaProject))
+		return true;
+	return isInClasspath(javaProject, adapterJavaProject, true, new HashSet());
+}
+
+/**
+ * Get the java project that we are interested in.
+ * @return
+ * 
+ * @since 1.0.0
+ */
+protected abstract IJavaProject getJavaProject();
+
+protected boolean isInClasspath(IJavaProject testProject, IJavaProject targetProject, boolean isFirstLevel, Set visited) {
+	if (visited.contains(targetProject))
+		return false;
+	visited.add(targetProject);
+	IClasspathEntry[] entries = null;
+	try {
+		entries = targetProject.getRawClasspath();
+	} catch (JavaModelException e) {
+		return false;
+	}
+	IClasspathEntry entry, resEntry;
+	IJavaProject proj = null;
+	List projects = null;
+	for (int i = 0; i < entries.length; i++) {
+		entry = entries[i];
+		if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
+			resEntry = JavaCore.getResolvedClasspathEntry(entry);
+			proj = getJavaProject(entry);
+			if (isFirstLevel || resEntry.isExported()) {
+				if (proj.equals(testProject))
+					return true;
+				else {
+					if (projects == null)
+						projects = new ArrayList();
+					projects.add(proj);
+				}
+			}
+		}
+	}
+	return isInClasspath(testProject, projects, false, visited);
+}
+
+protected boolean isInClasspath(IJavaProject testProject, List someJavaProjects, boolean isFirstLevel, Set visited) {
+	if (someJavaProjects == null)
+		return false;
+	int size = someJavaProjects.size();
+	IJavaProject javaProj = null;
+	for (int i = 0; i < size; i++) {
+		javaProj = (IJavaProject) someJavaProjects.get(i);
+		return isInClasspath(testProject, javaProj, isFirstLevel, visited);
+	}
+	return false;
+}
+
+protected IJavaProject getJavaProject(IClasspathEntry entry) {
+	IProject proj = getWorkspaceRoot().getProject(entry.getPath().segment(0));
+	if (proj != null)
+		return (IJavaProject) JavaCore.create(proj);
+	return null;
+}
+
+protected IWorkspaceRoot getWorkspaceRoot() {
+	return ResourcesPlugin.getWorkspace().getRoot();
+}
 }
diff --git a/plugins/org.eclipse.jem.workbench/workbench/org/eclipse/jem/internal/adapters/jdom/JavaReflectionSynchronizer.java b/plugins/org.eclipse.jem.workbench/workbench/org/eclipse/jem/internal/adapters/jdom/JavaReflectionSynchronizer.java
index 7eb682a..b91e1a8 100644
--- a/plugins/org.eclipse.jem.workbench/workbench/org/eclipse/jem/internal/adapters/jdom/JavaReflectionSynchronizer.java
+++ b/plugins/org.eclipse.jem.workbench/workbench/org/eclipse/jem/internal/adapters/jdom/JavaReflectionSynchronizer.java
@@ -11,15 +11,13 @@
  *******************************************************************************/
 /*
  *  $RCSfile: JavaReflectionSynchronizer.java,v $
- *  $Revision: 1.3 $  $Date: 2004/02/20 00:44:17 $ 
+ *  $Revision: 1.4 $  $Date: 2004/06/09 22:47:06 $ 
  */
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.logging.Level;
 
-import org.eclipse.core.resources.*;
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.Path;
 import org.eclipse.emf.common.notify.Notification;
 import org.eclipse.emf.common.notify.Notifier;
 import org.eclipse.jdt.core.*;
@@ -32,10 +30,11 @@
  */
 public class JavaReflectionSynchronizer extends JavaModelListener {
 	
-	private static final IPath CLASSPATH_PATH = new Path(".classpath"); //$NON-NLS-1$
 	protected JavaJDOMAdapterFactory fAdapterFactory;
+
 	protected boolean flushedAll = false;
 	protected List flushTypes = new ArrayList();
+	protected List flushTypePlusInner = new ArrayList();
 	protected List notifications = new ArrayList();
 	/**
 	 * JavaReflectionSynchronizer constructor comment.
@@ -44,69 +43,81 @@
 		super();
 		fAdapterFactory = synchronizee;
 	}
+	/* (non-Javadoc)
+	 * @see org.eclipse.jem.internal.adapters.jdom.JavaModelListener#getJavaProject()
+	 */
+	protected IJavaProject getJavaProject() {
+		return getAdapterFactory().getJavaProject();
+	}	
 	/**
 	 * Tell the reflection factory to flush the passed IType
 	 */
 	protected Notification doFlush(IType element) {
 		return getAdapterFactory().flushReflectionNoNotification(element.getFullyQualifiedName());
 	}
+	
+	/*
+	 * Flush the compilation unit and any inner classes since we don't if they may or may not of changed.
+	 */
+	protected Notification doFlush(ICompilationUnit element) {
+		return getAdapterFactory().flushReflectionPlusInnerNoNotification(getFullNameFromElement(element));
+	}
+	
 	protected void flush(IType element) {
 		if (!flushTypes.contains(element))
 			flushTypes.add(element);
 	}
+	/*
+	 * flush the compilation unit. Since we don't know if inner classes may also
+	 * of been affected, they to will be flushed.
+	 */
+	protected void flush(ICompilationUnit element) {
+		if (!flushTypePlusInner.contains(element))
+			flushTypePlusInner.add(element);		
+	}
 	protected void flushPackage(String packageName, boolean noFlushIfSourceFound) {
 		notifications.addAll(getAdapterFactory().flushPackageNoNotification(packageName, true));
 	}
 	protected JavaJDOMAdapterFactory getAdapterFactory() {
 		return fAdapterFactory;
 	}
-	private boolean isClassPathChange(IJavaElementDelta delta) {
-		int flags = delta.getFlags();
-		return (delta.getKind() == IJavaElementDelta.CHANGED && ((flags & IJavaElementDelta.F_ADDED_TO_CLASSPATH) != 0) || ((flags & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) != 0) || ((flags & IJavaElementDelta.F_REORDER) != 0));
-	}
 	/**
 	 * If the complation unit's content has changed, notify all adapters which point to it.
 	 * This change may not require a call to flush() if the structure of the entity has not changed.
 	 * Creation date: (8/17/2001 3:58:31 PM)
 	 * @param param org.eclipse.jdt.core.IJavaElementDelta
 	 */
-	public void processContentChanged(IJavaElementDelta delta) {
-		if (delta == null)
-			return;
-		// Any change will be notified, as changes to childrens may impact the text-location of this element.
-		IJavaElement element = delta.getElement();
-		if (element.getElementType() == IJavaElement.COMPILATION_UNIT)
-			if (((delta.getFlags()) & (IJavaElementDelta.F_CONTENT | IJavaElementDelta.F_MODIFIERS | IJavaElementDelta.F_CHILDREN | IJavaElementDelta.F_MOVED_TO | IJavaElementDelta.F_MOVED_FROM)) != 0) {
-				getAdapterFactory().notifyContentChanged((ICompilationUnit) element);
-			}
-	}
+// This doesn't really apply anymore. If the file has been physically changed, we cannot determine if it
+// just content like this. So we just ignore this for now.
+//	public void processContentChanged(IJavaElementDelta delta) {
+//		if (delta == null)
+//			return;
+//		// Any change will be notified, as changes to childrens may impact the text-location of this element.
+//		IJavaElement element = delta.getElement();
+//		if (element.getElementType() == IJavaElement.COMPILATION_UNIT)
+//			if (((delta.getFlags()) & (IJavaElementDelta.F_CONTENT | IJavaElementDelta.F_MODIFIERS | IJavaElementDelta.F_CHILDREN | IJavaElementDelta.F_MOVED_TO | IJavaElementDelta.F_MOVED_FROM)) != 0) {
+//				getAdapterFactory().notifyContentChanged((ICompilationUnit) element);
+//			}
+//	}
 	/**
 	 * Handle the change for a single element, children will be handled separately.
 	 *
 	 */
 	protected void processJavaElementChanged(ICompilationUnit element, IJavaElementDelta delta) {
-		if (!element.isWorkingCopy()) {
-			switch (delta.getKind()) {
-				case IJavaElementDelta.CHANGED : {						
-					if ((delta.getFlags() & IJavaElementDelta.F_PRIMARY_WORKING_COPY) != 0) {
-						try {
-							IType[] flushTypes = element.getAllTypes();
-							for (int i = 0; i < flushTypes.length; i++)
-								flush(flushTypes[i]);
-						} catch (JavaModelException e) {
-						}
-						
-					}
-					
-					break;
-				}
-				case IJavaElementDelta.ADDED :
-				case IJavaElementDelta.REMOVED : {
-					disAssociateSourcePlusInner(getFullNameFromElement(element));
-					return;
-				}
+		switch (delta.getKind()) {
+			case IJavaElementDelta.CHANGED : {
+				// A file save had occurred. It doesn't matter if currently working copy or not.
+				// It means something has changed to the file on disk, but don't know what.
+				if ((delta.getFlags() & IJavaElementDelta.F_PRIMARY_RESOURCE) != 0) {
+					flush(element);	// Flush everything, including inner classes.					
+				}						
+				break;
 			}
-			processChildren(element, delta);
+			case IJavaElementDelta.REMOVED : {
+				if (!element.isWorkingCopy())
+					disAssociateSourcePlusInner(getFullNameFromElement(element));				
+				break;
+			}
 		}
 	}
 	/**
@@ -147,25 +158,6 @@
 		}
 	}
 	/**
-	 * Method isClasspathResourceChange.
-	 * @param delta
-	 * @return boolean
-	 */
-	private boolean isClasspathResourceChange(IJavaElementDelta delta) {
-		IResourceDelta[] resources = delta.getResourceDeltas();
-		if (resources == null)
-			return false;
-		IPath path = null;
-		for (int i = 0; i < resources.length; i++) {
-			if (resources[i].getKind() == IResourceDelta.CHANGED) {
-				path = resources[i].getProjectRelativePath();
-				if (path.equals(CLASSPATH_PATH))
-					return true;
-			}
-		}
-		return false;
-	}
-	/**
 	 * Handle the change for a single element, children will be handled separately.
 	 *
 	 */
@@ -189,12 +181,12 @@
 			case IJavaElementDelta.ADDED : {
 				if (delta.getAffectedChildren().length == 0)
 					flushPackage(delta.getElement().getElementName(), true);
-					break;
+				break;
 			}
 			case IJavaElementDelta.REMOVED :{
 				if (delta.getAffectedChildren().length == 0)
 					getAdapterFactory().flushPackage(delta.getElement().getElementName(), false);
-					break;
+				break;
 			}
 			default :
 				super.processJavaElementChanged(element, delta);
@@ -221,6 +213,7 @@
 	 * that the type's name is package.filename (without the .java)
 	 * If we are wrong (if, then a rare case),  we will flush.
 	 * Next access will induce a reflection attempt.
+	 * @deprecated This doesn't look like it is ever called. It someone else calls it, please contact development to see if right method to be called.
 	 */
 	protected void processRemoveOrAdd(ICompilationUnit element) {
 		disAssociateSource(getFullNameFromElement(element));
@@ -249,72 +242,12 @@
 		JavaCore.removeElementChangedListener(this);
 	}
 	/**
-	 * This method will check to see if a <code>javaProject</code> is a project in the
-	 * classpath of the adapterFactory java project.
-	 */
-	protected boolean isInClasspath(IJavaProject javaProject) {
-		IJavaProject adapterJavaProject = getAdapterFactory().getJavaProject();
-		if (javaProject.equals(adapterJavaProject))
-			return true;
-		return isInClasspath(javaProject, adapterJavaProject, true, new HashSet());
-	}
-	protected boolean isInClasspath(IJavaProject testProject, IJavaProject targetProject, boolean isFirstLevel, Set visited) {
-		if (visited.contains(targetProject))
-			return false;
-		visited.add(targetProject);
-		IClasspathEntry[] entries = null;
-		try {
-			entries = targetProject.getRawClasspath();
-		} catch (JavaModelException e) {
-			return false;
-		}
-		IClasspathEntry entry, resEntry;
-		IJavaProject proj = null;
-		List projects = null;
-		for (int i = 0; i < entries.length; i++) {
-			entry = entries[i];
-			if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
-				resEntry = JavaCore.getResolvedClasspathEntry(entry);
-				proj = getJavaProject(entry);
-				if (isFirstLevel || resEntry.isExported()) {
-					if (proj.equals(testProject))
-						return true;
-					else {
-						if (projects == null)
-							projects = new ArrayList();
-						projects.add(proj);
-					}
-				}
-			}
-		}
-		return isInClasspath(testProject, projects, false, visited);
-	}
-	protected boolean isInClasspath(IJavaProject testProject, List someJavaProjects, boolean isFirstLevel, Set visited) {
-		if (someJavaProjects == null)
-			return false;
-		int size = someJavaProjects.size();
-		IJavaProject javaProj = null;
-		for (int i = 0; i < size; i++) {
-			javaProj = (IJavaProject) someJavaProjects.get(i);
-			return isInClasspath(testProject, javaProj, isFirstLevel, visited);
-		}
-		return false;
-	}
-	protected IJavaProject getJavaProject(IClasspathEntry entry) {
-		IProject proj = getWorkspaceRoot().getProject(entry.getPath().segment(0));
-		if (proj != null)
-			return (IJavaProject) JavaCore.create(proj);
-		return null;
-	}
-	protected IWorkspaceRoot getWorkspaceRoot() {
-		return ResourcesPlugin.getWorkspace().getRoot();
-	}
-	/**
 	 * @see org.eclipse.jem.internal.adapters.jdom.JavaModelListener#elementChanged(ElementChangedEvent)
 	 */
 	public void elementChanged(ElementChangedEvent event) {
 		try {
 			flushTypes.clear();
+			flushTypePlusInner.clear();
 			notifications.clear();
 			super.elementChanged(event);
 			flushTypes();
@@ -322,6 +255,7 @@
 		} finally {
 			flushedAll = false;
 			flushTypes.clear();
+			flushTypePlusInner.clear();
 			notifications.clear();
 		}
 	}
@@ -339,6 +273,16 @@
 					notifications.add(not);
 			}
 		}
+		if (!flushTypePlusInner.isEmpty()) {
+			ICompilationUnit unit = null;
+			Notification not;
+			for (int i = 0; i < flushTypePlusInner.size(); i++) {
+				unit = (ICompilationUnit) flushTypePlusInner.get(i);
+				not = doFlush(unit);
+				if (not != null)
+					notifications.add(not);
+			}
+		}		
 	}
 	/**
 	 * @param notifications
diff --git a/plugins/org.eclipse.jem/mofjava/org/eclipse/jem/java/impl/JavaClassImpl.java b/plugins/org.eclipse.jem/mofjava/org/eclipse/jem/java/impl/JavaClassImpl.java
index c2c7701..427d1de 100644
--- a/plugins/org.eclipse.jem/mofjava/org/eclipse/jem/java/impl/JavaClassImpl.java
+++ b/plugins/org.eclipse.jem/mofjava/org/eclipse/jem/java/impl/JavaClassImpl.java
@@ -11,7 +11,7 @@
  *******************************************************************************/
 /*
  *  $RCSfile: JavaClassImpl.java,v $
- *  $Revision: 1.4 $  $Date: 2004/05/05 21:03:07 $ 
+ *  $Revision: 1.5 $  $Date: 2004/06/09 22:46:53 $ 
  */
 
 import java.util.ArrayList;
@@ -446,7 +446,8 @@
 	/**
 	 * Return an IntrospectionAdaptor which can introspect our Java properties
 	 */
-	protected IIntrospectionAdapter getIntrospectionAdapter() {
+	protected synchronized IIntrospectionAdapter getIntrospectionAdapter() {
+		// Need to sync this because we are now in multi-thread env.
 		return (IIntrospectionAdapter) EcoreUtil.getRegisteredAdapter(this, IIntrospectionAdapter.ADAPTER_KEY);
 	}
 
@@ -702,7 +703,8 @@
 	/**
 	 * Return a ReadAdaptor which can reflect our Java properties
 	 */
-	protected ReadAdaptor getReadAdaptor() {
+	protected synchronized ReadAdaptor getReadAdaptor() {
+		// Need to sync because now in a multi-thread env.
 		return (ReadAdaptor) EcoreUtil.getRegisteredAdapter(this, ReadAdaptor.TYPE_KEY);
 	}