[65379] Deadlock with start remote vm between ui thread and build thread.
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 ba520eb..30befeb 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.17 $  $Date: 2004/06/02 19:42:39 $ 
+ *  $Revision: 1.18 $  $Date: 2004/06/04 15:29:34 $ 
  */
 
 import java.io.*;
@@ -355,22 +355,29 @@
 	/*
 	 * 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
-	 * done in UI thread.
+	 * done when build not in progress and serial access.
+	 * If waitForBuild is passed onto launching the registry. If we suspended the builds, then we must not
+	 * wait, or a deadlock will occur.
 	 */
-	void createRegistry(IProgressMonitor pm) {
-		synchronized (this) {
-			if (fRegistry != null)
-				return;	// It had already gotton created. Could of because UI and a thread were racing to do the creation, and one got there first.
+	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.
 		}
+
 		try {
 			ConfigurationContributor configurationContributor =  (ConfigurationContributor) getConfigurationContributor();
 			configurationContributor.setNature(this);
 			fRegistry = ProxyLaunchSupport.startImplementation(fProject, "Beaninfo", //$NON-NLS-1$
-				new IConfigurationContributor[] { configurationContributor}, pm);
+				new IConfigurationContributor[] { configurationContributor}, waitForBuild, new SubProgressMonitor(pm, 100));
 			fRegistry.addRegistryListener(registryListener);
 		} catch (CoreException e) {
 			BeaninfoPlugin.getPlugin().getLogger().log(e.getStatus());
-		}		
+		} finally {
+			pm.done();
+		}
 	}
 	
 	public synchronized boolean isRegistryCreated() {
@@ -426,7 +433,7 @@
 		} catch (CoreException e) {
 			BeaninfoPlugin.getPlugin().getLogger().log(e.getStatus());
 		} catch (Exception e) {
-			BeaninfoPlugin.getPlugin().getLogger().log(new Status(IStatus.WARNING, BeaninfoPlugin.PI_BEANINFO_PLUGINID, 0, "", e));
+			BeaninfoPlugin.getPlugin().getLogger().log(new Status(IStatus.WARNING, BeaninfoPlugin.PI_BEANINFO_PLUGINID, 0, "", e)); //$NON-NLS-1$
 		}
 		return bdoc;
 	}
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 a5509a7..196deee 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,17 +10,19 @@
  *******************************************************************************/
 /*
  *  $RCSfile: CreateRegistryJobHandler.java,v $
- *  $Revision: 1.3 $  $Date: 2004/06/02 19:42:39 $ 
+ *  $Revision: 1.4 $  $Date: 2004/06/04 15:29:34 $ 
  */
 package org.eclipse.jem.internal.beaninfo.adapters;
 
+import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.*;
+import org.eclipse.core.runtime.jobs.*;
  
 
 /**
  * This class is used by BeaninfoNature to handle the creation of the registry,
  * either as a job queued off to the UI thread, or directly in case either in
- * UI or UI not started.
+ * UI or UI not started. This class will be a singleton.
  * @since 1.0.0
  */
 class CreateRegistryJobHandler {
@@ -58,15 +60,10 @@
 	 * @since 1.0.0
 	 */
 	protected void processCreateRegistry(BeaninfoNature nature) {
-		// sync on nature because we aren't in the UI environment, so we can't sequentially do the create requests.
-		// We would get a race condition in non UI environment. In UI environment we can be sure that the
-		// create request will be processed sequentially (through the UI thread) and so not have a race. In that
-		// case we mustn't get the hold on nature.
-		synchronized (nature) {
-			doCreateRegistry(nature, new NullProgressMonitor());
-		}
+		doCreateRegistry(nature, new NullProgressMonitor());
 	}
 	
+	private int suspendedCount = 0;	// Number of nested suspends. Resume will occur only when it goes back to zero.
 	/*
 	 * Do the creation.
 	 * 
@@ -76,7 +73,49 @@
 	 * @since 1.0.0
 	 */
 	protected final void doCreateRegistry(BeaninfoNature nature, IProgressMonitor pm) {
-		nature.createRegistry(pm);
+		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
+				// is because we need the builds to be completed (so that we see the changed files), but we can't
+				// let it happen later. This is because there can be a deadlock between the build and this thread
+				// if we let the build (through some builder which is trying to do introspection) lock on this
+				// project after we've locked on this project. Therefor we need to complete the build, and then
+				// stop it from running again until we've completed on this project.
+				if (jobManager.find(ResourcesPlugin.FAMILY_AUTO_BUILD).length > 0 || jobManager.find(ResourcesPlugin.FAMILY_MANUAL_BUILD).length >0) {
+					try {						
+						jobManager.join(ResourcesPlugin.FAMILY_AUTO_BUILD, new SubProgressMonitor(pm, 100));
+						jobManager.join(ResourcesPlugin.FAMILY_MANUAL_BUILD, new SubProgressMonitor(pm, 100));
+					} catch (InterruptedException e) {
+						// Canceled, go on.
+					}
+				} else
+					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));
+				}
+			} else
+				pm.worked(300);
+			// Don't wait for the build to finish. Either we suspended the build, or we are in the build. In either case
+			// we can't wait for the build or we would deadlock.
+			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);
+					}
+				}
+			}
+			pm.done();
+		}
 	}
 
 }
diff --git a/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/UICreateRegistryJobHandler.java b/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/UICreateRegistryJobHandler.java
index ef99d63..4927c34 100644
--- a/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/UICreateRegistryJobHandler.java
+++ b/plugins/org.eclipse.jem.beaninfo/beaninfo/org/eclipse/jem/internal/beaninfo/adapters/UICreateRegistryJobHandler.java
@@ -10,15 +10,19 @@
  *******************************************************************************/
 /*
  *  $RCSfile: UICreateRegistryJobHandler.java,v $
- *  $Revision: 1.2 $  $Date: 2004/06/02 19:42:39 $ 
+ *  $Revision: 1.3 $  $Date: 2004/06/04 15:29:34 $ 
  */
 package org.eclipse.jem.internal.beaninfo.adapters;
 
-import org.eclipse.core.runtime.*;
-import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.core.runtime.jobs.Job;
+import java.lang.reflect.InvocationTargetException;
+import java.util.logging.Level;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.operation.IRunnableWithProgress;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.ui.PlatformUI;
+
+import org.eclipse.jem.internal.beaninfo.core.BeaninfoPlugin;
  
 
 /**
@@ -26,8 +30,8 @@
  * loaded except if ui plugin is available.
  * 
  * It will check to see if UI is running, and if it is not, then let super class handle.
- * If it is running, then if this is the UI thread, just do the creation, else if not
- * UI thread, create a job that will do a syncexec to the ui thread to do it.
+ * If it is running, then if this is the UI thread, use progress service, else if not then
+ * let super handle it normally.
  * 
  * @since 1.0.0
  */
@@ -40,30 +44,25 @@
 	 */
 	protected void processCreateRegistry(final BeaninfoNature nature) {
 		if (PlatformUI.isWorkbenchRunning()) {
-			final Display display = PlatformUI.getWorkbench().getDisplay();
-			if (display.getThread() == Thread.currentThread())
-				doCreateRegistry(nature, new NullProgressMonitor());	// We are in the UI thread, so just do it.
+			if (Display.getCurrent() == null)
+				super.processCreateRegistry(nature);	// We are not in the UI thread. Do normal.
 			else {
-				// We are not in the UI thread, so farm it off to a job to syncit.
-				// Use it as a job so that if it takes long enough, the progress view will be shown.
-				Job createJob = new Job(BeanInfoAdapterMessages.getString("UICreateRegistryJobHandler.StartBeaninfoRegistry")) { //$NON-NLS-1$
-					protected IStatus run(final IProgressMonitor monitor) {
-						display.syncExec(new Runnable() {
-							public void run() {
-								doCreateRegistry(nature, monitor);
-							}
-						});
-						return Status.OK_STATUS;
-					}
-				};
-				createJob.schedule();
-				while (true) {
-					try {
-						createJob.join();
-						break;
-					} catch (InterruptedException e) {
-					}
+				// We are in the UI, so use the progress service to farm off to another thread and keep the UI active, though disabled.
+				try {
+					PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() {
+
+						public void run(IProgressMonitor monitor) throws InterruptedException {
+							doCreateRegistry(nature, monitor);
+							if (monitor.isCanceled())
+								throw new InterruptedException();
+						}
+					});
+				} catch (InvocationTargetException e) {
+					BeaninfoPlugin.getPlugin().getLogger().log(e.getCause(), Level.WARNING);
+				} catch (InterruptedException e) {
+					// It was cancelled, so we just go on and launch.
 				}
+				
 			}
 		} else
 			super.processCreateRegistry(nature);	// Workbench not running, do default.
diff --git a/plugins/org.eclipse.jem.beaninfo/plugin.xml b/plugins/org.eclipse.jem.beaninfo/plugin.xml
index c122fc7..027d8b2 100644
--- a/plugins/org.eclipse.jem.beaninfo/plugin.xml
+++ b/plugins/org.eclipse.jem.beaninfo/plugin.xml
@@ -28,6 +28,7 @@
       <import plugin="org.eclipse.osgi"/>
       <import plugin="org.eclipse.ui" optional="true"/>
       <import plugin="org.eclipse.core.runtime"/>
+      <import plugin="org.eclipse.debug.core"/>
    </requires>
 
 
diff --git a/plugins/org.eclipse.jem.proxy/plugin.xml b/plugins/org.eclipse.jem.proxy/plugin.xml
index 2ab3d62..c5a95ec 100644
--- a/plugins/org.eclipse.jem.proxy/plugin.xml
+++ b/plugins/org.eclipse.jem.proxy/plugin.xml
@@ -37,10 +37,11 @@
       <import plugin="org.eclipse.core.resources"/>
       <import plugin="org.eclipse.jdt.launching"/>
       <import plugin="org.eclipse.jdt.core"/>
-      <import plugin="org.eclipse.debug.core" export="true"/>
+      <import plugin="org.eclipse.debug.core"/>
       <import plugin="com.ibm.wtp.common.util"/>
       <import plugin="org.eclipse.pde.core"/>
       <import plugin="org.eclipse.core.runtime"/>
+      <import plugin="org.eclipse.ui" optional="true"/>
    </requires>
 
 
diff --git a/plugins/org.eclipse.jem.proxy/proxy/org/eclipse/jem/internal/proxy/core/IUIRunner.java b/plugins/org.eclipse.jem.proxy/proxy/org/eclipse/jem/internal/proxy/core/IUIRunner.java
new file mode 100644
index 0000000..351a9c7
--- /dev/null
+++ b/plugins/org.eclipse.jem.proxy/proxy/org/eclipse/jem/internal/proxy/core/IUIRunner.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+/*
+ *  $RCSfile: IUIRunner.java,v $
+ *  $Revision: 1.1 $  $Date: 2004/06/04 15:29:38 $ 
+ */
+package org.eclipse.jem.internal.proxy.core;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+ 
+
+/**
+ * Interface that doesn't require UI. The implementation will. This will
+ * only be used if within UI environment.
+ * 
+ * <package-protected> because should only be used within here.
+ * 
+ * @since 1.0.0
+ */
+interface IUIRunner {
+	/**
+	 * Handle the build. If not in UI thread, just call back to ProxyLaunchSupport
+	 * to handle the build. If on UI thread, then use the IProgressService to do it.
+	 * This will keep the UI from "locking", though it will be disabled it won't deadlock.
+	 * 
+	 * @param pm
+	 * 
+	 * @since 1.0.0
+	 */
+	public void handleBuild(IProgressMonitor pm) throws CoreException;
+}
diff --git a/plugins/org.eclipse.jem.proxy/proxy/org/eclipse/jem/internal/proxy/core/ProxyLaunchSupport.java b/plugins/org.eclipse.jem.proxy/proxy/org/eclipse/jem/internal/proxy/core/ProxyLaunchSupport.java
index 43b3a07..ee5450b 100644
--- a/plugins/org.eclipse.jem.proxy/proxy/org/eclipse/jem/internal/proxy/core/ProxyLaunchSupport.java
+++ b/plugins/org.eclipse.jem.proxy/proxy/org/eclipse/jem/internal/proxy/core/ProxyLaunchSupport.java
@@ -10,15 +10,17 @@
  *******************************************************************************/
 /*
  *  $RCSfile: ProxyLaunchSupport.java,v $
- *  $Revision: 1.9 $  $Date: 2004/06/02 19:58:49 $ 
+ *  $Revision: 1.10 $  $Date: 2004/06/04 15:29:38 $ 
  */
 package org.eclipse.jem.internal.proxy.core;
 
 import java.text.MessageFormat;
 import java.util.*;
+import java.util.logging.Level;
 
 import org.eclipse.core.resources.*;
 import org.eclipse.core.runtime.*;
+import org.eclipse.core.runtime.jobs.IJobManager;
 import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.debug.core.*;
 import org.eclipse.jdt.core.*;
@@ -197,23 +199,52 @@
 	
 	/**
 	 * Start an implementation using the default config for the given project.
+	 * <p> 
+	 * This will wait for build. If you
+	 * know the build has been suspended by your thread, then you must use the other method that takes a waitForThread
+	 * boolean, and you must pass in false. Otherwise it will deadlock.
 	 * 
 	 * @param project The project. It must be a java project, and it cannot be <code>null</code>.
-	 * @param vmTitle
+	 * @param vmTitle title for VM. It may be <code>null</code>.
 	 * @param aContribs The contributions array. It may be <code>null</code>.
 	 * @param pm
 	 * @return The created registry.
 	 * @throws CoreException
 	 * 
+	 * @see ProxyLaunchSupport#startImplementation(IProject, String, IConfigurationContributor[], boolean, IProgressMonitor)
+	 * @since 1.0.0
+	 */
+	public static ProxyFactoryRegistry startImplementation(
+			IProject project,
+			String vmTitle,
+			IConfigurationContributor[] aContribs,
+			IProgressMonitor pm)
+				throws CoreException {
+		return startImplementation(project, vmTitle, aContribs, true, pm);
+	}
+	
+	/**
+	 * Start an implementation using the default config for the given project.
+	 * <p> 
+	 * If you know the build has been suspended by your thread, then you must use call this with false for waitForThread. Otherwise it will deadlock.
+	 * 
+	 * @param project The project. It must be a java project, and it cannot be <code>null</code>.
+	 * @param vmTitle title for VM. It may be <code>null</code>.
+	 * @param aContribs The contributions array. It may be <code>null</code>.
+	 * @param waitForBuild wait for the build. If caller knows that the build has been suspended by this thread, then it must call this with false. Otherwise a deadlock will occur.
+	 * @param pm
+	 * @return The created registry.
+	 * @throws CoreException
+	 * 
 	 * @since 1.0.0
 	 */
 	public static ProxyFactoryRegistry startImplementation(
 			IProject project,
 			String vmTitle,
 			IConfigurationContributor[] aContribs,
+			boolean waitForBuild, 
 			IProgressMonitor pm)
 				throws CoreException {
-		
 		// First find the appropriate launch configuration to use for this project.
 		// The process is:
 		//	1) See if the project's persistent property has a setting for "proxyLaunchConfiguration", if it does,
@@ -257,18 +288,24 @@
 			config = configwc;
 		}
 		
-		return startImplementation(config, vmTitle, aContribs, pm);
+		return startImplementation(config, vmTitle, aContribs, waitForBuild, pm);
 	}
 	
 	/**
 	 * Launch a registry using the given configuration.
+	 * <p> 
+	 * This will wait for build. If you
+	 * know the build has been suspended by your thread, then you must use the other method that takes a waitForThread
+	 * boolean, and you must pass in false. Otherwise it will deadlock.
+	 *
 	 * @param config 
-	 * @param vmTitle
+	 * @param vmTitle title for VM. It may be <code>null</code>.
 	 * @param aContribs The contributions array. It may be <code>null</code>.
 	 * @param pm
 	 * @return The registry from this configuration.
 	 * @throws CoreException
 	 * 
+	 * @see ProxyLaunchSupport#startImplementation(ILaunchConfiguration, String, IConfigurationContributor[], boolean, IProgressMonitor)
 	 * @since 1.0.0
 	 */
 	public static ProxyFactoryRegistry startImplementation(
@@ -277,18 +314,47 @@
 			IConfigurationContributor[] aContribs,
 			IProgressMonitor pm)
 			throws CoreException {
-		
+		return startImplementation(config, vmTitle, aContribs, true, pm);
+	}
+
+	/**
+	 * Launch a registry using the given configuration.
+	 * <p> 
+	 * If you know the build has been suspended by your thread, then you must use you must pass in false for waitForThread. Otherwise it will deadlock.
+	 *
+	 * @param config
+	 * @param vmTitle title for VM. It may be <code>null</code>.
+	 * @param aContribs The contributions array. It may be <code>null</code>.
+	 * @param waitForBuild wait for the build. If caller knows that the build has been suspended by this thread, then it must call this with false. Otherwise a deadlock will occur.
+	 * @param pm
+	 * @return The registry from this configuration.
+	 * @throws CoreException
+	 * 
+	 * @since 1.0.0
+	 */
+	public static ProxyFactoryRegistry startImplementation(
+				ILaunchConfiguration config,
+				String vmTitle,
+				IConfigurationContributor[] aContribs,
+				boolean waitForBuild,
+				IProgressMonitor pm)
+				throws CoreException {
+
 		if (pm == null)
 			pm = new NullProgressMonitor();
 		
 		final ILaunchConfigurationWorkingCopy configwc = config.getWorkingCopy();
 		
-		// See if build needed or waiting or inprogress, if so, wait for it to complete. We've
-		// decided
-		// too difficult to determine if build would affect us or not, so just wait.
 		pm.beginTask("", 400);
-		pm.subTask(ProxyMessages.getString("ProxyLaunch")); //$NON-NLS-1$
-		handleBuild(new SubProgressMonitor(pm, 100));
+		pm.subTask(ProxyMessages.getString("ProxyLaunch"));	//$NON-NLS-1$
+		if (waitForBuild) {
+			// See if build needed or waiting or inprogress, if so, wait for it to complete. We've
+			// decided too difficult to determine if build would affect us or not, so just wait.		
+			if (UI_RUNNER != null)
+				UI_RUNNER.handleBuild(new SubProgressMonitor(pm, 100));
+			else
+				runBuild(new SubProgressMonitor(pm, 100));
+		}
 				
 		if (aContribs != null) {
 			IConfigurationContributor[] newContribs = new IConfigurationContributor[aContribs.length+1];
@@ -439,20 +505,35 @@
 		return launchInfo.resultRegistry;
 	}
 	
-	private static void handleBuild(IProgressMonitor pm) throws CoreException {
+	/*
+	 * Run the build. If the original launch was in the UI thread, this will
+	 * be called under control of an IProgressService so that it is in a separate
+	 * thread and the UI will remain responsive (in that either a busy cursor comes
+	 * up or eventually a progress dialog).
+	 * <package-protected> so that only the UI handler will access it.
+	 */
+	static void runBuild(IProgressMonitor pm) throws CoreException {
 		boolean autobuilding = ResourcesPlugin.getWorkspace().isAutoBuilding();
 		if (!autobuilding) {
 			// We are not autobuilding. So kick off a build right here and
-			// wait for it.
+			// wait for it. (If we already within a build on this thread, then this
+			// will return immediately without building. We will take that risk. If
+			// some other thread is building, we will wait for it finish before we
+			// can get it and do our build.
 			ResourcesPlugin.getWorkspace().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, pm);			
 		} else {
-			Job[] build = Platform.getJobManager().find(ResourcesPlugin.FAMILY_AUTO_BUILD);
-			pm.beginTask("", 100);
-			if (build.length == 1) {
-				if (build[0].getState() == Job.RUNNING || build[0].getState() == Job.WAITING || build[0].getState() == Job.SLEEPING) {
+			pm.beginTask("", 200); //$NON-NLS-1$
+			IJobManager jobManager = Platform.getJobManager();
+			Job currentJob = jobManager.currentJob();
+			if (currentJob == null || (!currentJob.belongsTo(ResourcesPlugin.FAMILY_AUTO_BUILD) && !currentJob.belongsTo(ResourcesPlugin.FAMILY_MANUAL_BUILD))) { 
+				if (jobManager.find(ResourcesPlugin.FAMILY_AUTO_BUILD).length > 0 || jobManager.find(ResourcesPlugin.FAMILY_MANUAL_BUILD).length >0) {
+					// We are not within a build job. If we were, then we don't do the build. We will take
+					// that risk. The problem is that if within the build, we can't wait for it to finish because
+					// we would stop the thread and so the build would not complete.
 					pm.subTask(ProxyMessages.getString("ProxyWaitForBuild")); //$NON-NLS-1$
 					try {						
-						build[0].join();						
+						jobManager.join(ResourcesPlugin.FAMILY_AUTO_BUILD, new SubProgressMonitor(pm, 100));
+						jobManager.join(ResourcesPlugin.FAMILY_MANUAL_BUILD, new SubProgressMonitor(pm, 100));
 					} catch (InterruptedException e) {
 						throw new CoreException(
 								new Status(IStatus.ERROR, ProxyPlugin.getPlugin().getBundle().getSymbolicName(), IStatus.ERROR, "", e)); //$NON-NLS-1$
@@ -470,6 +551,7 @@
 	 * public but only so that launch delegate can get to it.
 	 */
 	public static String ATTR_PRIVATE;
+	private static IUIRunner UI_RUNNER = null;
 	static {
 		ATTR_PRIVATE = null;
 		try {
@@ -479,6 +561,16 @@
 				Class debugUIConstants = debuguiBundle.loadClass("org.eclipse.debug.ui.IDebugUIConstants"); //$NON-NLS-1$
 				ATTR_PRIVATE = (String) debugUIConstants.getField("ATTR_PRIVATE").get(null); //$NON-NLS-1$
 			}
+			
+			Bundle uiBundle = Platform.getBundle("org.eclipse.ui");	//$NON-NLS-1$
+			if (uiBundle != null) {
+				try {
+					// We have a UI bundle, so we can load our UIRunner class and it will load fine.
+					UI_RUNNER = (IUIRunner) Class.forName("org.eclipse.jem.internal.proxy.core.UIRunner").newInstance(); //$NON-NLS-1$
+				} catch (InstantiationException e1) {
+					ProxyPlugin.getPlugin().getLogger().log(e1, Level.WARNING);
+				}
+			}
 		} catch (SecurityException e) {
 		} catch (ClassNotFoundException e) {
 		} catch (NoSuchFieldException e) {
diff --git a/plugins/org.eclipse.jem.proxy/proxy/org/eclipse/jem/internal/proxy/core/UIRunner.java b/plugins/org.eclipse.jem.proxy/proxy/org/eclipse/jem/internal/proxy/core/UIRunner.java
new file mode 100644
index 0000000..ebccc77
--- /dev/null
+++ b/plugins/org.eclipse.jem.proxy/proxy/org/eclipse/jem/internal/proxy/core/UIRunner.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+/*
+ *  $RCSfile: UIRunner.java,v $
+ *  $Revision: 1.1 $  $Date: 2004/06/04 15:29:37 $ 
+ */
+package org.eclipse.jem.internal.proxy.core;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.logging.Level;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.PlatformUI;
+ 
+
+/**
+ * The actual implementation of IUIRunner to run the build under
+ * IProgressService control if in the UI thread.
+ * 
+ * <package-protected> because should only be used within here.
+ * 
+ * @since 1.0.0
+ */
+class UIRunner implements IUIRunner, IRunnableWithProgress {
+	/* (non-Javadoc)
+	 * @see org.eclipse.jem.internal.proxy.core.IUIRunner#handleBuild(org.eclipse.core.runtime.IProgressMonitor)
+	 */
+	public void handleBuild(IProgressMonitor pm) throws CoreException {
+		if (!PlatformUI.isWorkbenchRunning() || Display.getCurrent() == null) {
+			ProxyLaunchSupport.runBuild(pm);
+		} else {
+			pm.beginTask("", 100); //$NON-NLS-1$
+			try {
+				PlatformUI.getWorkbench().getProgressService().busyCursorWhile(this);
+			} catch (InvocationTargetException e) {
+				if (e.getCause() instanceof CoreException)
+					throw (CoreException) e.getCause();
+				ProxyPlugin.getPlugin().getLogger().log(e.getCause(), Level.WARNING);
+			} catch (InterruptedException e) {
+				// It was cancelled, so we just go on and launch.
+			}
+			pm.done();
+		}
+	}
+	/* (non-Javadoc)
+	 * @see org.eclipse.jface.operation.IRunnableWithProgress#run(org.eclipse.core.runtime.IProgressMonitor)
+	 */
+	public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+		try {
+			ProxyLaunchSupport.runBuild(monitor);
+		} catch (CoreException e) {
+			throw new InvocationTargetException(e);
+		}
+		if (monitor.isCanceled()) {
+			throw new InterruptedException();
+		}
+	}
+}